(ns uxbox.ui.shapes.text
  (:require [sablono.core :refer-macros [html]]
            [cuerdas.core :as str]
            [rum.core :as rum]
            [lentes.core :as l]
            [goog.events :as events]
            [uxbox.rstore :as rs]
            [uxbox.state :as st]
            [uxbox.shapes :as ush]
            [uxbox.data.workspace :as dw]
            [uxbox.ui.core :as uuc]
            [uxbox.ui.mixins :as mx]
            [uxbox.ui.keyboard :as kbd]
            [uxbox.ui.shapes.core :as uusc]
            [uxbox.ui.shapes.icon :as uusi]
            [uxbox.util.dom :as dom])
  (:import goog.events.EventType))

(defn on-mouse-down
  [event own {:keys [id group] :as shape} selected]
  (let [selected? (contains? selected id)
        local (:rum/local own)]
    (when-not (:blocked shape)
      (cond
        (:edition @local)
        nil

        (and group (:locked (ush/resolve-parent shape)))
        nil

        (and (not selected?) (empty? selected))
        (do
          (dom/stop-propagation event)
          (uuc/acquire-action! :shape/movement)
          (rs/emit! (dw/select-shape id)))

        (and (not selected?) (not (empty? selected)))
        (do
          (dom/stop-propagation event)
          (if (kbd/shift? event)
            (rs/emit! (dw/select-shape id))
            (rs/emit! (dw/deselect-all)
                      (dw/select-shape id))))

        :else
        (do
          (dom/stop-propagation event)
          (uuc/acquire-action! :shape/movement))))))

(defn on-mouse-up
  [event {:keys [id group] :as shape}]
  (cond
    (and group (:locked (ush/resolve-parent shape)))
    nil

    :else
    (do
      (dom/stop-propagation event)
      (uuc/release-action! :draw/selrect)
      (uuc/release-action! :shape/movement))))

(defn- text-component-did-mount
  [own]
  (letfn [(on-double-click [ev]
            (let [container (mx/get-ref-dom own "container")
                  local (:rum/local own)]
              (swap! local assoc :edition true)
              (uuc/acquire-action! ::edition)
              (set! (.-contentEditable container) true)
              (.setAttribute container "contenteditable" "true")
              (.focus container)))
          (on-blur [ev]
            (let [container (mx/get-ref-dom own "container")
                  local (:rum/local own)]
              (uuc/release-action! ::edition)
              (swap! local assoc :edition false)
              (set! (.-contentEditable container) false)
              (.removeAttribute container "contenteditable")))]

    (let [dom (mx/get-ref-dom own "main")
          dom2 (mx/get-ref-dom own "container")
          key1 (events/listen dom EventType.DBLCLICK on-double-click)
          key2 (events/listen dom2 EventType.BLUR on-blur)]
      (assoc own ::key1 key1))))

(defn- text-component-will-unmount
  [own]
  (let [key1 (::key1 own)
        key2 (::key2 own)]
    (events/unlistenByKey key1)
    (events/unlistenByKey key2)
    (dissoc own ::key1 ::key2)))

(defn- text-component-transfer-state
  [old-own own]
  (let [data (select-keys old-own [::key1 ::key2])]
    (merge own data)))

(defn- text-component-render
  [own shape]
  (let [{:keys [id x1 y1 content group]} shape
        selected (rum/react uusc/selected-shapes-l)
        selected? (and (contains? selected id) (= (count selected) 1))
        on-mouse-down #(on-mouse-down % own shape selected)
        on-mouse-up #(on-mouse-up % shape)
        local (:rum/local own)]
    (html
     [:g.shape {:class (when selected? "selected")
                ;; :on-double-click #(on-double-click own %)
                :ref "main"
                :on-mouse-down on-mouse-down
                :on-mouse-up on-mouse-up}
      (uusc/render-shape (assoc shape :editing? (:edition @local false)) nil)
      (when (and selected? (not (:edition @local false)))
        (uusi/handlers shape))])))

(def ^:const text-component
  (mx/component
   {:render text-component-render
    :name "text-componet"
    :did-mount text-component-did-mount
    :will-unmount text-component-will-unmount
    :transfer-state text-component-transfer-state
    :mixins [mx/static rum/reactive (mx/local)]}))

(defmethod uusc/render-component :builtin/text
  [own shape]
  (text-component shape))

(def ^:const +select-rect-attrs+
  {:stroke-dasharray "5,5"
   :style {:stroke "#333" :fill "transparent"
           :stroke-opacity "0.4"}})

(defmethod uusc/render-shape :builtin/text
  [{:keys [id x1 y1 x2 y2 content drawing? editing?] :as shape}]
  (let [key (str id)
        rfm (ush/transformation shape)
        size (ush/size shape)
        props {:x x1 :y y1
               :transform (str rfm)}
        attrs (merge props size)]
    (html
     [:g
      (if (or drawing? editing?)
        [:g
         [:rect (merge attrs +select-rect-attrs+)]])
      [:foreignObject attrs
       [:p {:ref "container"} content]]])))

