 ; (defrecord Jedi [id name homeworld apprentice master])
 
 (def jedi-url "http://localhost:3000/dark-jedis/")
+(def planets-url "ws://localhost:4000")
 
-(defonce app-state (reagent/atom {:planet {:id nil :name "unknown"}
-                                  :jedis []
-                                  :first-jedi-id 3616}))
+(defonce initial-state {:planet {:id nil :name "unknown"}
+                        :jedis []
+                        :first-jedi-id 3616
+                        :db-initialized? true})
 
 (defn pad
   "Pads the collection coll to the given length n with val"
   [n val coll]
   (take n (concat coll (repeat val))))
-
-; Open a new websocket connection only if there's no planet in state.
-; Without this we'd create a new websocket connection on each figwheel reload.
-(when-not (get-in @app-state [:planet :id])
-  (go
-    (let [{:keys [ws-channel error]} (<! (ws-ch "ws://localhost:4000" {:format :json}))]
-      (if-not error
-        (loop []
-          ; If the websocket server gets closed, the ws-channel gets closed too and the response will be nil.
-          (let [response (<! ws-channel)
-                error (:error response)
-                planet (keywordize-keys (:message response))]
-            (if planet
-              (do
-                (swap! app-state assoc :planet planet)
-                (recur))
-              (if error
-                (println (str "Error while receiving message: " error))
-                (println "Websocket connection closed unexpectedly")))))
-        (println (str "Error while connecting: " error))))))
 
 (defn get-jedi
   "Fetches info about Jedi. Returns a channel with:

    [chord.client :refer [ws-ch]]
    [cljs.core.async :refer [<!]]
    [cljs-http.client :as http]
    [re-frame.core :as re-frame :refer [subscribe register-sub]])
  (:require-macros
    [cljs.core.async.macros :refer [go]]
    [reagent.ratom :refer [reaction]]))

  (reaction (:planet @db)))

(register-sub :current-planet current-planet)

;;; handlers

(defn change-current-planet [db, [_ planet]]
  (assoc db :planet planet))

(register-handler :change-current-planet
                  change-current-planet)

(defn monitor-planets [db _]
  (do
    ; Open a new websocket connection only if there's no planet in state.
    ; Without this we'd create a new websocket connection on each figwheel reload.
    (when-not (get-in db [:planet :id])
      (go
        (let [{:keys [ws-channel error]} (<! (ws-ch planets-url {:format :json}))]
          (if-not error
            (loop []
              ; If the websocket server gets closed, the ws-channel gets closed too and the response will be nil.
              (let [response (<! ws-channel)
                    error (:error response)
                    planet (keywordize-keys (:message response))]
                (if planet
                  (do
                    (dispatch [:change-current-planet planet])
                    (recur))
                  (if error
                    (println (str "Error while receiving message: " error))
                    (println "Websocket connection closed unexpectedly")))))
            (println (str "Error while connecting: " error))))))
    db))

(register-handler :monitor-planets
                  monitor-planets)

(defn save-jedi
  [db [_ jedi]]
  (assoc db :jedis (conj (:jedis db) jedi)))

(register-handler :save-jedi
                  save-jedi)

(defn populate-jedis [db _]
  (do
    (when-not (seq (:jedis db))
      ; Weird, when using go-loop, I'm getting exactly the same error as presented here:
      ; https://theholyjava.wordpress.com/2014/05/12/core-async-cant-recur-here-in-clojurescript-but-ok-in-clojure/
      (go
        (loop [jedi-id (:first-jedi-id db)]
          (when-let [jedi (<! (get-jedi jedi-id))]
            (dispatch [:save-jedi jedi])
            (recur (get-in jedi [:apprentice :id]))))))
    db))

(register-handler :populate-jedis
                  populate-jedis)

;;; initial dispatches

(dispatch [:initialize-db])
(dispatch [:monitor-planets])
(dispatch [:populate-jedis])

;;; components

