(ns uxbox.ui.workspace.shortcuts
  (:require-macros [uxbox.util.syntax :refer [define-once]])
  (:require [goog.events :as events]
            [beicon.core :as rx]
            [uxbox.rstore :as rs]
            [uxbox.data.workspace :as dw])
  (:import goog.events.EventType
           goog.events.KeyCodes
           goog.ui.KeyboardShortcutHandler
           goog.ui.KeyboardShortcutHandler))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Keyboard Shortcuts Handlers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defonce ^:const +shortcuts+
  {:ctrl+g #(rs/emit! (dw/toggle-flag :grid))
   :ctrl+shift+f #(rs/emit! (dw/toggle-flag :drawtools))
   :ctrl+shift+i #(rs/emit! (dw/toggle-flag :icons))
   :ctrl+shift+l #(rs/emit! (dw/toggle-flag :layers))
   :ctrl+r #(rs/emit! (dw/toggle-flag :ruler))
   :esc #(rs/emit! (dw/deselect-all))
   :backspace #(rs/emit! (dw/delete-selected))
   :delete #(rs/emit! (dw/delete-selected))
   :up #(rs/emit! (dw/move-selected :up))
   :down #(rs/emit! (dw/move-selected :down))
   :right #(rs/emit! (dw/move-selected :right))
   :left #(rs/emit! (dw/move-selected :left))})

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Keyboard Shortcuts Watcher
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defonce ^:const ^:private +bus+
  (rx/bus))

(defonce ^:const +stream+
  (rx/to-observable +bus+))

(defn- init-handler
  []
  (let [handler (KeyboardShortcutHandler. js/document)]
    ;; Register shortcuts.
    (doseq [item (keys +shortcuts+)]
      (let [identifier (name item)]
        (.registerShortcut handler identifier identifier)))

    ;; Initialize shortcut listener.
    (let [event KeyboardShortcutHandler.EventType.SHORTCUT_TRIGGERED
          callback #(rx/push! +bus+ (keyword (.-identifier %)))
          key (events/listen handler event callback)]
      (fn []
        (events/unlistenByKey key)
        (.clearKeyListener handler)))))

(define-once :subscriptions
  (rx/on-value +stream+ #(println "[debug]: shortcut:" %))
  (rx/on-value +stream+ (fn [event]
                          (when-let [handler (get +shortcuts+ event)]
                            (handler)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Keyboard Shortcuts Mixin
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn -will-mount
  [own]
  (let [sub (init-handler)]
    (assoc own ::subscription sub)))

(defn -will-unmount
  [own]
  (let [sub (::subscription own)]
    (sub)
    (dissoc own ::subscription)))

(defn -transfer-state
  [old-own own]
  (assoc own ::subscription (::subscription old-own)))

(def mixin
  {:will-mount -will-mount
   :will-unmount -will-unmount
   :transfer-state -transfer-state})
