             [cljs.reader :as reader]
             [clojure.string :as string]
             [dato.lib.core :as dato]
+            [dato.datascript-utils :as dsu]
             [dato.debug.components.keyboard-listener :as keyboard]
+            [goog.dom.classes :as gclass]
             [om-bootstrap.panel :as bs-p]
             [om-bootstrap.grid :as g]
             [om.core :as om :include-macros true]

          (when (om/get-state owner [:open?])
            (bs-p/panel
             {:header (dom/div "["
                               (dom/button {:on-click #(om/set-state! owner [:tool] :timeline)} "Timeline")
                               "] | ["
                               (dom/button {:on-click #(om/set-state! owner [:tool] :states)} "States")
                               "] | ["
                               (dom/button {:on-click #(om/set-state! owner [:tool] :query)} "Expression Watch")
                               "] - Dato Debugger " (dom/small "(" log-count " states)"))}
             (case (om/get-state owner [:tool])
               :states   (dom/div
                          (dom/h3 "Click a slot to restore a state")
                          (dom/ul
                           (for [slot-idx (range 0 10)]
                             (let [local-storage-name (str "dato_save_state_" slot-idx)
                                   existing-db        (js/localStorage.getItem local-storage-name)]
                               (dom/li {:style    {:cursor "pointer"}
                                        :on-click #(restore-save-state! owner slot-idx)} (if existing-db
                                                                                           (dom/strong "Slot " slot-idx)
                                                                                           "No state saved"))))))
               :query    (dom/div
                          (g/grid
                           {}
                           (g/row
                            {}
                            (g/col
                             {:xs 0 :sm 2 :md 2 :lg 2}
                             (g/row
                              {}
                              (g/col
                               {:xs 12 :sm 12 :md 12 :lg 12}
                               (dom/input {:placeholder "Search Expressions"})))
                             (g/row
                              {}
                              (g/col
                               {:xs 12 :sm 12 :md 12 :lg 12}
                               (dom/ul
                                (for [[idx query] (map-indexed vector (om/get-state owner [:query]))
                                      :let [current-query? (= (:title query) (om/get-state owner [:current-query]))
                                            title (str idx ". " (:title query))]]
                                  (dom/li {:style    {:cursor "pointer"}
                                           :on-click #(om/set-state! owner [:current-query] idx)}
                                          (if current-query?
                                            (dom/strong title)
                                            title)))))))
                            (g/col {:xs 3 :sm 3 :md 3 :lg 3}
                                   (let [current-query (om/get-state owner [:query (om/get-state owner [:current-query])])]
                                     (dom/div
                                      (when (false? (:valid? current-query))
                                        (dom/pre "Invalid code"))
                                      (dom/input {:placeholder "Query title"
                                                  :value "Current Session"})
                                      (dom/textarea {:placeholder "Expression (cljs code)"
                                                     :value       (:str current-query)
                                                     :on-change   (fn [event]
                                                                    (let [str-value (.. event -target -value)
                                                                          valid? (try (compile-expr str-value identity)
                                                                                      true
                                                                                      (catch js/Error e
                                                                                        false))]
                                                                      (om/update-state! owner [:queries (om/get-state owner [:current-query])] (fn [s]
                                                                                                                                                 (merge s
                                                                                                                                                        {:str    str-value
                                                                                                                                                         :valid? valid?})))))
                                                     :style       {:width  "100%"
                                                                   :height "100%"}}))))
                            (g/col {:xs 12 :sm 7 :md 7 :lg 7}
                                   (when-let [current-query (om/get-state owner [:query (om/get-state owner [:current-query])])]
                                     (dom/pre
                                      (binding [*print-length* 10]
                                        (let [query-results ((:fn current-query) db)]
                                          (with-out-str (pp/pprint query-results))))))))))
               :editor   (dom/div
                          "Code editor"
                          (dom/link {:rel      "stylesheet"
                                     :property "stylesheet"
                                     :href     "/css/vendor/codemirror/codemirror.css"})
                          (dom/div {:className "editor"}))
               :timeline (dom/div
                          (dom/h3 (pr-str (get-in log [selected-state-idx :tx/intent])))
                          (dom/div
                           (dom/input {:type      "range"
                                       :min       0
                                       :max       (max 0 (dec (count (:log data))))
                                       :value     (om/get-state owner [:states :selected])
                                       :on-change #(let [idx (reader/read-string (.. % -target -value))]
                                                     (om/set-state! owner [:states :selected] idx)
                                                     (set-app-state! idx))})
                           (dom/button {:on-click #(play-all-states!)
                                        :disabled (not (pos? log-count))} "> Play All")
                           (dom/div {:style {:float "right"
                                             :width "50%"}}
                                    (dom/pre (pr-str (get-in selected-state [:tx :tx-data]))))
                           (dom/ul
                            {:className "event-history"}
                            (let [int (->> (:log data)
                                           (map-indexed vector)
                                           (reduce (fn [run [idx next]]
                                                     (let [cnt        (count run)
                                                           last-event (:tx/intent (nth run (dec cnt)))
                                                           selected?  (= idx selected-state-idx)]
                                                       (if (= last-event (:tx/intent next))
                                                         (-> run
                                                             (update-in [(dec cnt) :count] inc)
                                                             (update-in [(dec cnt) :selected?] #(or selected? %)))
                                                         (conj run (-> next
                                                                       (assoc :count 1)
                                                                       (assoc :selected? selected?)))))) [{}]))]
                              (for [tx int]
                                (dom/li (if (:selected? tx)
                                          (dom/strong (pr-str (:tx/intent tx)))
                                          (pr-str (:tx/intent tx)))
                                        (when (pos? (dec (:count tx))) (str " x " (:count tx))))))))))))))))))

    om/IWillMount
    (will-mount [_]
      (om/set-state! owner [:current-save-slot] 0)
      (om/set-state! owner [:tool] :components)
      (om/set-state! owner [:current-query] "default")
      (om/set-state! owner [:open?] true)
      (om/set-state! owner [:query] (or (:expressions opts) [])))
    om/IDidUpdate
    (did-update [_ _ prev]
      (let [node                (om/get-node owner)
            editor-node         (.querySelector node ".editor")
            switched-to-editor? (and (not= :debugger (:tool prev))
                                     (= :debugger (om/get-state owner [:tool])))]
        (when (and switched-to-editor? editor-node)
