             [uxbox.util.rlocks :as rlocks]
             [uxbox.util.uuid :as uuid]
             [uxbox.util.workers :as uw]))
-
-(s/def ::x1 number?)
-(s/def ::y1 number?)
-(s/def ::x2 number?)
-(s/def ::y2 number?)
-(s/def ::type keyword?)
-
-(s/def ::rect-shape (s/keys :req-un [::x1 ::y1 ::x2 ::y2 ::type]))
-
-;; --- Shapes CRUD
-
-(deftype AddShape [data]
-  udp/IPageUpdate
-  ptk/UpdateEvent
-  (update [_ state]
-    (let [shape (geom/setup-proportions data)
-          page (l/focus ul/selected-page state)]
-      (impl/assoc-shape-to-page state shape page))))
-
-(defn add-shape
-  [data]
-  (AddShape. data))
-
-(defn delete-shape
-  "Remove the shape using its id."
-  [id]
-  (reify
-    udp/IPageUpdate
-    ptk/UpdateEvent
-    (update [_ state]
-      (let [shape (get-in state [:shapes id])]
-        (impl/dissoc-shape state shape)))))
-
-(defn update-shape
-  "Just updates in place the shape."
-  [{:keys [id] :as shape}]
-  (reify
-    udp/IPageUpdate
-    ptk/UpdateEvent
-    (update [_ state]
-      (update-in state [:shapes id] merge shape))))
-
-;; --- Shape Transformations
-
-(declare align-point)
-
-(def ^:private canvas-coords
-  (gpt/point c/canvas-start-x
-             c/canvas-start-y))
-
-(declare apply-temporal-displacement)
-
-(defn initial-align-shape
-  [id]
-  (reify
-    ptk/WatchEvent
-    (watch [_ state s]
-      (let [{:keys [x1 y1] :as shape} (->> (get-in state [:shapes id])
-                                           (geom/shape->rect-shape state))
-            point1 (gpt/point x1 y1)
-            point2 (gpt/add point1 canvas-coords)]
-        (->> (align-point point2)
-             (rx/map #(gpt/subtract % canvas-coords))
-             (rx/map (fn [{:keys [x y] :as pt}]
-                       (apply-temporal-displacement id (gpt/subtract pt point1)))))))))
-
-(defn update-rotation
-  [sid rotation]
-  {:pre [(number? rotation)
-         (>= rotation 0)
-         (>= 360 rotation)]}
-  (reify
-    udp/IPageUpdate
-    ptk/UpdateEvent
-    (update [_ state]
-      (update-in state [:shapes sid]
-                 geom/rotate rotation))))
-
-(defn update-size
-  "A helper event just for update the position
-  of the shape using the width and height attrs
-  instread final point of coordinates."
-  [sid opts]
-  {:pre [(uuid? sid)]}
-  (reify
-    udp/IPageUpdate
-    ptk/UpdateEvent
-    (update [_ state]
-      (update-in state [:shapes sid] geom/resize-dim opts))))
-
-;; --- Apply Temporal Displacement
-
-(deftype ApplyTemporalDisplacement [id delta]
-  udp/IPageUpdate
-  ptk/UpdateEvent
-  (update [_ state]
-    (let [shape (get-in state [:shapes id])
-          displ (:tmp-displacement shape (gpt/point 0 0))
-          delta (gpt/add displ delta)]
-      (assoc-in state [:shapes id :tmp-displacement] delta))))
-
-(defn apply-temporal-displacement
-  [id pt]
-  {:pre [(uuid? id) (gpt/point? pt)]}
-  (ApplyTemporalDisplacement. id pt))
-
-;; --- Apply Displacement
-
-;; TODO: move to shapes-impl ns.
-
-(deftype ApplyDisplacement [id]
-  udp/IPageUpdate
-  ptk/UpdateEvent
-  (update [_ state]
-    (let [{:keys [tmp-displacement type] :as shape} (get-in state [:shapes id])
-          xfmt  (gmt/translate-matrix tmp-displacement)]
-
-      (if (= type :group)
-        (letfn [(update-item [state id]
-                  (let [{:keys [type items] :as shape} (get-in state [:shapes id])]
-                    (if (= type :group)
-                      (reduce update-item state items)
-                      (update-in state [:shapes id]
-                                 (fn [shape]
-                                   (as-> (dissoc shape :tmp-displacement) $
-                                     (geom/transform state $ xfmt)))))))]
-          (-> (reduce update-item state (:items shape))
-              (update-in [:shapes id] dissoc :tmp-displacement)))
-
-        (update-in state [:shapes id] (fn [shape]
-                                        (as-> (dissoc shape :tmp-displacement) $
-                                          (geom/transform state $ xfmt))))))))
-
-(defn apply-displacement
-  [id]
-  {:pre [(uuid? id)]}
-  (ApplyDisplacement. id))
-
-;; --- Apply Temporal Resize Matrix
-
-(deftype ApplyTemporalResizeMatrix [id mx]
-  udp/IPageUpdate
-  ptk/UpdateEvent
-  (update [_ state]
-    (assoc-in state [:shapes id :tmp-resize-xform] mx)))
-
-(defn apply-temporal-resize-matrix
-  "Attach temporal resize matrix transformation to the shape."
-  [id mx]
-  (ApplyTemporalResizeMatrix. id mx))
-
-;; --- Apply Resize Matrix
-
-(declare apply-resize-matrix)
-
-(deftype ApplyResizeMatrix [id]
-  udp/IPageUpdate
-  ptk/UpdateEvent
-  (update [_ state]
-    (let [{:keys [type tmp-resize-xform]
-           :or {tmp-resize-xform (gmt/matrix)}
-           :as shape} (get-in state [:shapes id])]
-      (if (= type :group)
-        (letfn [(update-item [state id]
-                  (let [{:keys [type items] :as shape} (get-in state [:shapes id])]
-                    (if (= type :group)
-                      (reduce update-item state items)
-                      (update-in state [:shapes id]
-                                 (fn [shape]
-                                   (as-> (dissoc shape :tmp-resize-xform) $
-                                     (geom/transform state $ tmp-resize-xform)))))))]
-          (-> (reduce update-item state (:items shape))
-              (update-in [:shapes id] dissoc :tmp-resize-xform)))
-        (update-in state [:shapes id] (fn [shape]
-                                        (as-> (dissoc shape :tmp-resize-xform) $
-                                          (geom/transform state $ tmp-resize-xform))))))))
-
-(defn apply-resize-matrix
-  "Apply definitivelly the resize matrix transformation to the shape."
-  [id]
-  {:pre [(uuid? id)]}
-  (ApplyResizeMatrix. id))
-
-(defn update-position
-  "Update the start position coordenate of the shape."
-  [sid {:keys [x y] :as opts}]
-  (reify
-    ptk/UpdateEvent
-    (update [_ state]
-      (update-in state [:shapes sid] geom/absolute-move opts))))
-
-(defn update-text
-  [sid {:keys [content]}]
-  {:pre [(string? content)]}
-  (reify
-    udp/IPageUpdate
-    ptk/UpdateEvent
-    (update [_ state]
-      (assoc-in state [:shapes sid :content] content))))
-
-;; --- Update Shape Attrs
-
-(declare UpdateAttrs)
-
-(deftype UpdateAttrs [id attrs]
-  ptk/WatchEvent
-  (watch [_ state stream]
-    (println "update-attrs" id attrs)
-    (let [{:keys [type] :as shape} (get-in state [:shapes id])]
-      (if (= type :group)
-        (rx/from-coll (map #(UpdateAttrs. % attrs) (:items shape)))
-        (rx/of #(update-in % [:shapes id] merge attrs))))))
 
 (s/def ::fill-color us/color?)
 (s/def ::fill-opacity number?)

                   ::blocked
                   ::locked]))

(defn update-attrs
  [id attrs]
  {:pre [(uuid? id) (us/valid? ::shape-attrs attrs)]}
  (let [atts (us/extract attrs ::shape-attrs)]
    (UpdateAttrs. id attrs)))

;; --- Shape Proportions

(defn select-shapes-by-selrect
  "Select shapes that matches the select rect."
  [selrect]
  {:pre [(us/valid? ::rect-like-shape selrect)]}
  (SelectShapesBySelrect. selrect))

;; --- Update Interaction
