From 77933f39499bd74c7013913e2414ad90b812c9a5 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 22 Jun 2016 19:59:52 +0300
Subject: [PATCH] Move kdtree, lru and heap into uxbox.util submodule.

---
 .../heap.js => src/uxbox/util/heap_impl.js    | 12 +--
 src/uxbox/util/kdtree.cljs                    | 30 +++++++
 .../core.js => src/uxbox/util/kdtree_impl.js  | 89 ++++++++++---------
 vendor/lru.js => src/uxbox/util/lru_impl.js   | 11 +--
 src/uxbox/view.cljs                           |  1 +
 src/uxbox/worker/align.cljs                   |  9 +-
 6 files changed, 94 insertions(+), 58 deletions(-)
 rename vendor/kdtree/heap.js => src/uxbox/util/heap_impl.js (91%)
 create mode 100644 src/uxbox/util/kdtree.cljs
 rename vendor/kdtree/core.js => src/uxbox/util/kdtree_impl.js (86%)
 rename vendor/lru.js => src/uxbox/util/lru_impl.js (91%)

diff --git a/vendor/kdtree/heap.js b/src/uxbox/util/heap_impl.js
similarity index 91%
rename from vendor/kdtree/heap.js
rename to src/uxbox/util/heap_impl.js
index 60d2fc987..3956202f6 100644
--- a/vendor/kdtree/heap.js
+++ b/src/uxbox/util/heap_impl.js
@@ -8,13 +8,15 @@
  * @license MIT License <https://opensource.org/licenses/MIT>
  */
 
-goog.provide("kdtree.heap");
-goog.provide("kdtree.heap.MinHeap");
+"use strict";
+
+goog.provide("uxbox.util.heap_impl");
+goog.provide("uxbox.util.heap_impl.MinHeap");
 
 goog.scope(function() {
-  "use strict";
+  const self = uxbox.util.heap_impl;
 
-  const compare = (x,y) => x-y;
+  const compare = (x, y) => x - y;
 
   class MinHeap {
     constructor(cmp) {
@@ -108,5 +110,5 @@ goog.scope(function() {
     }
   }
 
-  kdtree.heap.MinHeap = MinHeap;
+  self.MinHeap = MinHeap;
 });
diff --git a/src/uxbox/util/kdtree.cljs b/src/uxbox/util/kdtree.cljs
new file mode 100644
index 000000000..e03e2360a
--- /dev/null
+++ b/src/uxbox/util/kdtree.cljs
@@ -0,0 +1,30 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
+
+(ns uxbox.util.kdtree
+  "A cljs layer on top of js impl of kdtree located in `kdtree_impl.js`."
+  (:require [uxbox.util.kdtree-impl :as impl]))
+
+(defn create
+  "Create an empty or initialized kd-tree instance."
+  ([] (impl/create))
+  ([points] (impl/create (clj->js points))))
+
+(defn setup!
+  "Generate new kd-tree instance with provided generation parameter
+  or just return a prevuously created from internal LRU cache."
+  [t w h ws hs]
+  (impl/setup t w h ws hs))
+
+(defn nearest
+  "Search nearest points to the provided point
+  and return the `n` maximum results."
+  ([t p]
+   (nearest t p 10))
+  ([t p n]
+   {:pre [(vector? p)]}
+   (let [p (into-array p)]
+     (map clj->js (impl/nearest t p n)))))
diff --git a/vendor/kdtree/core.js b/src/uxbox/util/kdtree_impl.js
similarity index 86%
rename from vendor/kdtree/core.js
rename to src/uxbox/util/kdtree_impl.js
index 92c2e0724..dcc20f198 100644
--- a/vendor/kdtree/core.js
+++ b/src/uxbox/util/kdtree_impl.js
@@ -13,12 +13,16 @@
 
 "use strict";
 
-goog.provide("kdtree.core");
-goog.require("kdtree.heap");
-goog.require("lru");
+goog.provide("uxbox.util.kdtree_impl");
+goog.require("uxbox.util.heap_impl");
+goog.require("uxbox.util.lru_impl");
 goog.require("goog.asserts");
 
 goog.scope(function() {
+  const self = uxbox.util.kdtree_impl;
+
+  const heap = uxbox.util.heap_impl;
+  const lru = uxbox.util.lru_impl;
   const assert = goog.asserts.assert;
 
   // Hardcoded dimensions value;
@@ -76,7 +80,7 @@ goog.scope(function() {
   function searchNearest(root, point, maxNodes) {
     const search = (best, node) => {
       if (best === null) {
-        best = new kdtree.heap.MinHeap((x, y) => x[1] - y[1]);
+        best = new heap.MinHeap((x, y) => x[1] - y[1]);
       }
 
       let distance = precision(calculateDistance(point, node.obj));
@@ -147,38 +151,7 @@ goog.scope(function() {
   // --- Public Api
   const cache = new lru.create();
 
-  function create(points) {
-    const tree = new KDTree();
-    if (goog.isArray(points)) {
-      return initialize(tree, points);
-    } else {
-      return tree;
-    }
-  };
-
   function generate(width, height, widthStep, heightStep) {
-    const key = `${width}.${height}.${widthStep}.${heightStep}`;
-
-    let tree = lru.get(cache, key);
-    if (tree instanceof KDTree) {
-      return tree;
-    } else {
-      tree = new KDTree();
-      setup(tree, width, height, widthStep, heightStep);
-      lru.set(cache, key, tree);
-      return tree;
-    }
-  }
-
-  function initialize(tree, points) {
-    assert(goog.isArray(points));
-    assert(tree instanceof KDTree);
-
-    tree.root = buildTree(null, points, 0);
-    return tree;
-  }
-
-  function setup(tree, width, height, widthStep, heightStep) {
     const totalSize = Math.floor((width/widthStep) * (height/heightStep));
     const points = new Array(totalSize);
     let pos = 0;
@@ -189,7 +162,21 @@ goog.scope(function() {
       }
     }
 
-    initialize(tree, points);
+    return points;
+  }
+
+  function setup(tree, width, height, widthStep, heightStep) {
+    const key = `${width}.${height}.${widthStep}.${heightStep}`;
+    const root = lru.get(cache, key);
+
+    if (root instanceof Node) {
+      tree.root = root;
+    } else {
+      const points = generate(width, height, widthStep, heightStep);
+      tree.root = buildTree(null, points, 0);
+      lru.set(cache, key, tree.root);
+    }
+
     return tree;
   }
 
@@ -198,6 +185,23 @@ goog.scope(function() {
     return tree.root !== null;
   }
 
+  function initialize(tree, points) {
+    assert(goog.isArray(points));
+    assert(tree instanceof KDTree);
+
+    tree.root = buildTree(null, points, 0);
+    return tree;
+  }
+
+  function create(points) {
+    const tree = new KDTree();
+    if (goog.isArray(points)) {
+      return initialize(tree, points);
+    } else {
+      return tree;
+    }
+  };
+
   function clear(tree) {
     assert(tree instanceof KDTree);
     tree.root = null;
@@ -212,11 +216,10 @@ goog.scope(function() {
   }
 
   // Factory functions
-  kdtree.core.create = create;
-  kdtree.core.generate = generate;
-  kdtree.core.initialize = initialize;
-  kdtree.core.setup = setup;
-  kdtree.core.isInitialized = isInitialized;
-  kdtree.core.clear = clear;
-  kdtree.core.nearest = nearest;
+  self.create = create;
+  self.initialize = initialize;
+  self.setup = setup;
+  self.isInitialized = isInitialized;
+  self.clear = clear;
+  self.nearest = nearest;
 });
diff --git a/vendor/lru.js b/src/uxbox/util/lru_impl.js
similarity index 91%
rename from vendor/lru.js
rename to src/uxbox/util/lru_impl.js
index 16c7a6d4a..d3b0ed25e 100644
--- a/vendor/lru.js
+++ b/src/uxbox/util/lru_impl.js
@@ -10,10 +10,11 @@
 
 "use strict";
 
-goog.provide("lru");
+goog.provide("uxbox.util.lru_impl");
 goog.require("goog.asserts");
 
 goog.scope(function() {
+  const self = uxbox.util.lru_impl;
   const assert = goog.asserts.assert;
 
   class Node {
@@ -118,8 +119,8 @@ goog.scope(function() {
     return new Cache(limit);
   }
 
-  lru.create = create;
-  lru.get = (c, key) => c.getItem(key);
-  lru.set = (c, key, val) => c.setItem(key, val);
-  lru.remove = (c, key) => c.removeItem(key);
+  self.create = create;
+  self.get = (c, key) => c.getItem(key);
+  self.set = (c, key, val) => c.setItem(key, val);
+  self.remove = (c, key) => c.removeItem(key);
 });
diff --git a/src/uxbox/view.cljs b/src/uxbox/view.cljs
index 4315201ef..44d98060c 100644
--- a/src/uxbox/view.cljs
+++ b/src/uxbox/view.cljs
@@ -6,6 +6,7 @@
 
 (ns uxbox.view
   (:require [uxbox.view.state :as st]
+            [uxbox.common.constants]
             #_[uxbox.view.locales :as lc]
             [uxbox.view.ui :as ui]))
 
diff --git a/src/uxbox/worker/align.cljs b/src/uxbox/worker/align.cljs
index 9dad2f704..3c221f88a 100644
--- a/src/uxbox/worker/align.cljs
+++ b/src/uxbox/worker/align.cljs
@@ -7,7 +7,7 @@
 (ns uxbox.worker.align
   "Workspace aligment indexes worker."
   (:require [beicon.core :as rx]
-            [kdtree.core :as kd]
+            [uxbox.util.kdtree :as kd]
             [uxbox.worker.impl :as impl]
             [uxbox.common.geom.point :as gpt]))
 
@@ -16,14 +16,13 @@
 (defmethod impl/handler :grid/init
   [{:keys [sender width height x-axis y-axis] :as opts}]
   (time
-   (let [value (kd/generate width height (or x-axis 10) (or y-axis 10))]
-     (set! tree value)))
+   (kd/setup! tree width height (or x-axis 10) (or y-axis 10)))
   (impl/reply! sender nil))
 
 (defmethod impl/handler :grid/align
   [{:keys [sender point] :as message}]
-  (let [point #js [(:x point) (:y point)]
-        results (js->clj (kd/nearest tree point 1))
+  (let [point [(:x point) (:y point)]
+        results (kd/nearest tree point 1)
         [[x y] d] (first results)
         result (gpt/point x y)]
     (impl/reply! sender {:point (gpt/point x y)})))