(ns uxbox.ui.workspace.canvas
  (:require [sablono.core :as html :refer-macros [html]]
            [rum.core :as rum]
            [beicon.core :as rx]
            [uxbox.router :as r]
            [uxbox.rstore :as rs]
            [uxbox.state :as s]
            [uxbox.shapes :as shapes]
            [uxbox.library.icons :as _icons]
            [uxbox.data.projects :as dp]
            [uxbox.data.workspace :as dw]
            [uxbox.ui.mixins :as mx]
            [uxbox.ui.dom :as dom]
            [uxbox.ui.util :as util]
            [uxbox.ui.workspace.base :as wb]
            [uxbox.ui.workspace.grid :refer (grid)]
            [uxbox.ui.workspace.toolboxes :as toolboxes]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Background
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn background-render
  []
  (html
   [:rect
    {:x 0 :y 0 :width "100%" :height "100%" :fill "white"}]))

(def background
  (util/component
   {:render background-render
    :name "background"
    :mixins [mx/static]}))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shape
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def ^:private
  selection-circle-style
  {:fillOpacity "0.5"
   :strokeWidth "1px"
   :vectorEffect "non-scaling-stroke"
   :cursor "move"})

(def ^:private
  default-selection-props
  {:r 4 :style selection-circle-style
   :fill "lavender"
   :stroke "gray"})

(defn- shape-render
  [own {:keys [id x y width height] :as shape}]
  (let [local (:rum/local own)
        selected (rum/react wb/selected-state)]
    (html
     [:g {
          :on-mouse-down
          (fn [event]
            (dom/stop-propagation event)
            (swap! local assoc :init-coords [x y])
            (reset! wb/shapes-dragging? true))

          :on-click
          (fn [event]
            (when (= (:init-coords @local) [x y])
              (if (.-ctrlKey event)
                (rs/emit! (dw/select-shape id))
                (rs/emit! (dw/deselect-all)
                          (dw/select-shape id)))))

          :on-mouse-up
          (fn [event]
            (dom/stop-propagation event)
            (reset! wb/shapes-dragging? false))
          }
      (shapes/render shape)
      (if (contains? selected id)
        [:g {:class "controls"}
         [:rect {:x x :y y :width width :height height
                 :style {:stroke "black" :fill "transparent"
                         :stroke-opacity "0.5"}}]
         [:circle (merge default-selection-props
                         {:cx x :cy y})]
         [:circle (merge default-selection-props
                         {:cx (+ x width) :cy y})]
         [:circle (merge default-selection-props
                         {:cx x :cy (+ y height)})]
         [:circle (merge default-selection-props
                         {:cx (+ x width) :cy (+ y height)})]])])))


;; (defn- shape-render
;;   [own shape]
;;   (let [local (:rum/local own)
;;         x 30
;;         y 30
;;         width 100
;;         height 100]
;;     (html
;;      [:g
;;       (shapes/render shape {:x x :y y :width width :height height})
;;       [:g {:class "controls"}
;;        [:rect {:x x :y y :width width :height height
;;                :style {:stroke "black" :fill "transparent"
;;                        :stroke-opacity "0.5"}}]
;;        [:circle (merge default-selection-props
;;                        {:cx x :cy y})]
;;        [:circle (merge default-selection-props
;;                        {:cx (+ x width) :cy y})]
;;        [:circle (merge default-selection-props
;;                        {:cx x :cy (+ y height)})]
;;        [:circle (merge default-selection-props
;;                        {:cx (+ x width) :cy (+ y height)})]]])))

(def shape
  (util/component
   {:render shape-render
    :name "shape"
    :mixins [mx/static rum/reactive (mx/local {})]}))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Canvas
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn canvas-render
  []
  (let [page (rum/react wb/page-state)
        shapes (rum/react wb/shapes-state)
        page-width (:width page)
        page-height (:height page)]
    (letfn [(on-mouse-down [event]
              (dom/stop-propagation event)
              (rs/emit! (dw/deselect-all)))
            (on-mouse-up [event]
              (dom/stop-propagation event)
              (reset! wb/shapes-dragging? false))]
      (html
       [:svg.page-canvas {:x wb/document-start-x
                          :y wb/document-start-y
                          :ref "canvas"
                          :width page-width
                          :height page-height
                          :on-mouse-down on-mouse-down
                          :on-mouse-up on-mouse-up}
        (background)
        (grid 1)
        [:svg.page-layout {}
         (for [item shapes]
           (rum/with-key (shape item) (str (:id item))))]]))))

(def canvas
  (util/component
   {:render canvas-render
    :name "canvas"
    :mixins [rum/reactive wb/mouse-mixin]}))