                              (:results @state)))})
 
 (deftemplate page "index.html" []
-  {[:.search-field] (kioo/listen :on-key-down
-                      (fn [_]
-                        (let [input (.-value (dom/getElement "search-field"))]
-                          (if (blank? input)
-                            (init-state)
-                            (put! query-chan input)))))
+  {[:.results] (kioo/content (result-cards))})
 
-   [:.test-button] (kioo/listen :on-click
-                     (fn [_]
-                       (.log js/console (clj->js (:results @state)))))
+; Pipelines
 
-   [:.test-state-push] (kioo/listen :on-click
-                         (fn [_]
-                           (put! second-chan
-                             [{
-                               :category-drugs "-generation antihistamines: Brompheniramine, Carbinoxamine, Chlorpheniramine, Clemastine, Cyproheptadine, Dexbrompheniramine, Dexchlorpheniramine, Dimenhydrinate, Diphenhydramine (oral), Doxylamine, Hydroxyzine, Meclizine, Promethazine, Triprolidine",
-                               :organ-system "Anticholinergics",
-                               :rationale "Highly anticholinergic; clearance reduced with advanced age, and tolerance develops when used as hypnotic; risk of confusion, dry mouth, constipation, and other anticholinergic effects or toxicity. Use of diphenhydramine in situations such as acute treatment of severe allergic reaction may be appropriate",
-                               :recommendation "Avoid",
-                               :quality-of-evidence "Moderate",
-                               :strength-of-recommendation "Strong",
-                               :evidence "2015 Criteria: Duran 2013, Fox 2014, Kalisch Ellet 2014. From previous criteria: Agostini 2001, Boustani 2007, Guaiana 2010, Han 2001, Rudolph 2008"
-                              },
-                              {
-                               :category-drugs "Antiparkinsonian agents: Benztropine (oral), Trihexyphenidyl",
-                               :organ-system "Anticholinergics",
-                               :rationale "Not recommended for prevention of extrapyramidal symptoms with antipsychotics; more effective agents available for treatment of Parkinson disease.",
-                               :recommendation "Avoid",
-                               :quality-of-evidence "Moderate",
-                               :strength-of-recommendation "Strong",
-                               :evidence "Rudolph 2008"
-                              }])))
+; Query pipeline
+(defn throttle [in ms-delay]
+  (let [out (chan)]
+    (go (while true
+      ; Take from the input channel and pass through.
+      (>! out (<! in))
 
-   [:.results] (kioo/content (result-cards))})
+      ; Park while trying to take from an unused channel. This channel receives
+      ; no input, and will park until timed out, delaying the above take from
+      ; the input channel as the user types.
+      (<! (timeout ms-delay))))
+    out))
+
+(defn get-results [in]
+  (let [out (chan)]
+    (go (while true
+      (let [[url search-text] (<! in)
+            response (<! (http/get url {:query-params {"q" search-text}}))]
+        (>! out (vector search-text response)))))
+    out))
+
+(defn extract-hits [in]
+  (let [out (chan)]
+    (go (while true
+      (let [[search-text mid-results] (<! in)
+            output (get-in mid-results [:body :hits :hits])]
+        (>! out (vector search-text output)))))
+    out))
+
+(defn flatten-structure [in]
+  (let [out (chan)]
+    (go (while true
+      (let [[search-text mid-results] (<! in)
+            output (vec (map #(:_source %) mid-results))]
+        (>! out (vector search-text output)))))
+    out))
+
+(defn update-query-results [in]
+  (go (while true
+    (let [[search-text query-results] (<! in)]
+      (update-cache search-text query-results)
+      (update-results query-results)))))
+
+; Query process pipeline entry point
+; Sliding buffer is used to complete throttling
+(def query-chan (chan (sliding-buffer 1)))
+(def throttled-query-chan (throttle query-chan 3000))
+(def get-results-out (get-results throttled-query-chan))
+(def extract-hits-out (extract-hits get-results-out))
+(def flatten-structure-out (flatten-structure extract-hits-out))
+(update-query-results flatten-structure-out)
+
+; Cache pipeline
+(defn update-cache-results [in]
+  (go (while true
+    (let [query-result (<! in)]
+      (update-results (get (:cache @state) query-result))))))
+
+(def cache-chan (chan))
+(update-cache-results cache-chan)
+
+; Creates and returns a channel to listen to events specified by type parameter
+(defn listen [el type]
+  (let [out (chan)]
+    (events/listen el type #(put! out %))
+    out))
+
+(defn search-field []
+  (dom/getElementByClass "search-field"))
+
+(defn listen-search-input []
+  (let [input (listen (search-field) "keyup")]
+    (go (while true
+      (<! input)
+
+      (let [cache (:cache @state)
+            query-text (.-value (search-field))]
+        (if (blank? query-text)
+          (update-results (:all-results @state))
+          (if (contains? cache query-text)
+            (put! cache-chan query-text)
+            (put! query-chan (vector query-url query-text)))))))))
 
 (defn init []
-  (init-state)
-  (reagent/render-component [page] (.-body js/document)))
+  (load-all-results all-results-url)
+  (reagent/render-component [page] (.-body js/document))
+  (listen-search-input))

   :quality-of-evidence "Quality Of Evidence"
   :strength-of-recommendation "Strength of Recommendation"
   :evidence "Evidence"})

; (defsnippet result-data "templates/results.html" [:.list-row] [[k v]]
;   {[:.list-row] (kioo/content [:li (k labels)]
;                               [:li v])})
;
; (defsnippet result-card "templates/results.html" [:.card] [results]
;   {[:.list-column] (kioo/content [:li
;                                    [:ul {:class "list-row"}
;                                      (map result-data results)]])})
;
; (deftemplate result-cards "templates/results.html" []
;   {[:.cards] (kioo/content (map result-card
;                              (:results @state)))})

(defsnippet result-data "templates/results.html" [:.row] [[k v]]
  {[:.row] (kioo/content [:li (k labels)] [:li v])})

(ns app.app
  (:require [goog.events :as events]
            [goog.dom :as dom]
            [clojure.string :as string :refer [blank?]]
            [cljs.core.async :refer [<! >! put! close! chan
                                     timeout sliding-buffer]]
