 (ns overtone.device.midi.nanoKONTROL2
   (:use [overtone.midi]
-        [overtone.libs.event :only [event]]))
-
-(defrecord NanoKontrol2 [name in out interfaces state])
-
-(def event-handle "/overtone/midi/nanokontrol2")
+        [overtone.libs.event :only [event on-event on-latest-event]]
+        [overtone.core :only [control-bus bus-set!]]))
+
+(defrecord NanoKontrol2 [name out interfaces state busses])
+
+(def event-handle [:midi-device "KORG INC." "SLIDER/KNOB" "nanoKONTROL2 SLIDER/KNOB" :control-change])
+
+(defn- merge-control-defaults
+  "Returns config map where control info maps are merged
+  with :control-defaults map."
+  [config]
+  (assoc config
+    :interfaces
+    (into {}
+          (map (fn [[i-name i-info]]
+                 [i-name (assoc (dissoc i-info :control-defaults)
+                           :controls (into {}
+                                           (map (fn [[c-name c-info]]
+                                                  [c-name (merge (:control-defaults i-info)
+                                                                 c-info)])
+                                                (:controls i-info))))])
+               (:interfaces config)))))
+
+(def default-event-type
+  {:button :on-event
+   :slider :on-latest-event
+   :pot    :on-latest-event})
 
 (def config
-  {:name "nanoKONTROL2"
-   :interfaces {:input-controls {:name "Input Controls"
-                                 :type :midi-in
-                                 :midi-handle "nanoKONTROL2"
-                                 :control-defaults {:chan 0 :cmd 176 :type :button}
-                                 :controls {:track-left {:note 58}
-                                            :track-right {:note 59}
-                                            :cycle {:note 46}
-                                            :marker-set {:note 60}
-                                            :marker-left {:note 61}
-                                            :marker-right {:note 62}
-                                            :rewind {:note 43}
-                                            :fast-forward {:note 44}
-                                            :stop {:note 42}
-                                            :play {:note 41}
-                                            :record {:note 45}
-                                            :s0 {:note 32}
-                                            :m0 {:note 48}
-                                            :r0 {:note 64}
-                                            :slider0 {:note 0 :type :slider}
-                                            :pot0 {:note 16 :type :pot}
-
-                                            :s1 {:note 33}
-                                            :m1 {:note 49}
-                                            :r1 {:note 65}
-                                            :slider1 {:note 1 :type :slider}
-                                            :pot1 {:note 17 :type :pot}
-
-                                            :s2 {:note 34}
-                                            :m2 {:note 50}
-                                            :r2 {:note 66}
-                                            :slider2 {:note 2 :type :slider}
-                                            :pot2 {:note 18 :type :pot}
-
-                                            :s3 {:note 35}
-                                            :m3 {:note 51}
-                                            :r3 {:note 67}
-                                            :slider3 {:note 3 :type :slider}
-                                            :pot3 {:note 19 :type :pot}
-
-                                            :s4 {:note 36}
-                                            :m4 {:note 52}
-                                            :r4 {:note 68}
-                                            :slider4 {:note 4 :type :slider}
-                                            :pot4 {:note 20 :type :pot}
-
-                                            :s5 {:note 37}
-                                            :m5 {:note 53}
-                                            :r5 {:note 69}
-                                            :slider5 {:note 5 :type :slider}
-                                            :pot5 {:note 21 :type :pot}
-
-                                            :s6 {:note 38}
-                                            :m6 {:note 54}
-                                            :r6 {:note 70}
-                                            :slider6 {:note 6 :type :slider}
-                                            :pot6 {:note 22 :type :pot}
-
-                                            :s7 {:note 39}
-                                            :m7 {:note 55}
-                                            :r7 {:note 71}
-                                            :slider7 {:note 7 :type :slider}
-                                            :pot7 {:note 23 :type :pot}}}
-                :leds {:name "LEDs"
-                       :type :midi-out
-                       :midi-handle "nanoKONTROL2"
-                       :control-defaults {:type :led}
-                       :controls {:cycle {:note 46}
-                                  :rewind {:note 43}
-                                  :fast-forward {:note 44}
-                                  :stop {:note 42}
-                                  :play {:note 41}
-                                  :record {:note 45}
-                                  :s0 {:note 32}
-                                  :m0 {:note 48}
-                                  :r0 {:note 64}
-                                  :s1 {:note 33}
-                                  :m1 {:note 49}
-                                  :r1 {:note 65}
-                                  :s2 {:note 34}
-                                  :m2 {:note 50}
-                                  :r2 {:note 66}
-                                  :s3 {:note 35}
-                                  :m3 {:note 51}
-                                  :r3 {:note 67}
-                                  :s4 {:note 36}
-                                  :m4 {:note 52}
-                                  :r4 {:note 68}
-                                  :s5 {:note 37}
-                                  :m5 {:note 53}
-                                  :r5 {:note 69}
-                                  :s6 {:note 38}
-                                  :m6 {:note 54}
-                                  :r6 {:note 70}
-                                  :s7 {:note 39}
-                                  :m7 {:note 55}
-                                  :r7 {:note 71}}}}})
-
+  (merge-control-defaults
+   {:name "nanoKONTROL2"
+    :interfaces {:input-controls {:name "Input Controls"
+                                  :type :midi-in
+                                  :midi-handle "nanoKONTROL2"
+                                  :control-defaults {:chan 0 :cmd 176 :type :button}
+                                  :controls {:track-left {:note 58}
+                                             :track-right {:note 59}
+                                             :cycle {:note 46}
+                                             :marker-set {:note 60}
+                                             :marker-left {:note 61}
+                                             :marker-right {:note 62}
+                                             :rewind {:note 43}
+                                             :fast-forward {:note 44}
+                                             :stop {:note 42}
+                                             :play {:note 41}
+                                             :record {:note 45}
+                                             :s0 {:note 32}
+                                             :m0 {:note 48}
+                                             :r0 {:note 64}
+                                             :slider0 {:note 0 :type :slider}
+                                             :pot0 {:note 16 :type :pot}
+
+                                             :s1 {:note 33}
+                                             :m1 {:note 49}
+                                             :r1 {:note 65}
+                                             :slider1 {:note 1 :type :slider}
+                                             :pot1 {:note 17 :type :pot}
+
+                                             :s2 {:note 34}
+                                             :m2 {:note 50}
+                                             :r2 {:note 66}
+                                             :slider2 {:note 2 :type :slider}
+                                             :pot2 {:note 18 :type :pot}
+
+                                             :s3 {:note 35}
+                                             :m3 {:note 51}
+                                             :r3 {:note 67}
+                                             :slider3 {:note 3 :type :slider}
+                                             :pot3 {:note 19 :type :pot}
+
+                                             :s4 {:note 36}
+                                             :m4 {:note 52}
+                                             :r4 {:note 68}
+                                             :slider4 {:note 4 :type :slider}
+                                             :pot4 {:note 20 :type :pot}
+
+                                             :s5 {:note 37}
+                                             :m5 {:note 53}
+                                             :r5 {:note 69}
+                                             :slider5 {:note 5 :type :slider}
+                                             :pot5 {:note 21 :type :pot}
+
+                                             :s6 {:note 38}
+                                             :m6 {:note 54}
+                                             :r6 {:note 70}
+                                             :slider6 {:note 6 :type :slider}
+                                             :pot6 {:note 22 :type :pot}
+
+                                             :s7 {:note 39}
+                                             :m7 {:note 55}
+                                             :r7 {:note 71}
+                                             :slider7 {:note 7 :type :slider}
+                                             :pot7 {:note 23 :type :pot}}}
+                 :leds {:name "LEDs"
+                        :type :midi-out
+                        :midi-handle "nanoKONTROL2"
+                        :control-defaults {:type :led}
+                        :controls {:cycle {:note 46}
+                                   :rewind {:note 43}
+                                   :fast-forward {:note 44}
+                                   :stop {:note 42}
+                                   :play {:note 41}
+                                   :record {:note 45}
+                                   :s0 {:note 32}
+                                   :m0 {:note 48}
+                                   :r0 {:note 64}
+                                   :s1 {:note 33}
+                                   :m1 {:note 49}
+                                   :r1 {:note 65}
+                                   :s2 {:note 34}
+                                   :m2 {:note 50}
+                                   :r2 {:note 66}
+                                   :s3 {:note 35}
+                                   :m3 {:note 51}
+                                   :r3 {:note 67}
+                                   :s4 {:note 36}
+                                   :m4 {:note 52}
+                                   :r4 {:note 68}
+                                   :s5 {:note 37}
+                                   :m5 {:note 53}
+                                   :r5 {:note 69}
+                                   :s6 {:note 38}
+                                   :m6 {:note 54}
+                                   :r6 {:note 70}
+                                   :s7 {:note 39}
+                                   :m7 {:note 55}
+                                   :r7 {:note 71}}}}}))
 
 (defn- byte-seq-to-array
   "Turn a seq of bytes into a native byte-array."

         (smr-col-off out id)
         (Thread/sleep (nth intro-times id))))))

(defn- merge-control-defaults
  "Returns config map where control info maps are merged
  with :control-defaults map."
  [config]
  (assoc config
    :interfaces
    (into {}
          (map (fn [[i-name i-info]]
                 [i-name (assoc (dissoc i-info :control-defaults)
                           :controls (into {}
                                           (map (fn [[c-name c-info]]
                                                  [c-name (merge (:control-defaults i-info)
                                                                 c-info)])
                                                (:controls i-info))))])
               (:interfaces config)))))

(defn note-controls-map
  [config]
  (let [controls (-> config :interfaces :input-controls :controls)]
    (into {}
          (map (fn [[k v]] [(:note v) k])
               controls))))

(defn mk-midi-in-handler
  [config state event-name]
  (let [ncm (note-controls-map config)]
    (fn [msg ts]
      (let [note   (:note msg)
            vel    (:vel msg)
            at-key (get ncm note)
            atm    (get state at-key)]
        (reset! atm vel)
        (event event-name :msg msg :ts ts :val vel :id at-key)))))

(defn connect
  "Connect to a connected nanoKONTROL2 midi device. By default, it

              (-> config :interfaces :leds :midi-handle)))
  ([midi-in-str midi-out-str] (connect true midi-in-str midi-out-str))
  ([force-external-led-mode? midi-in-str midi-out-str]
     (let [out        (midi-out midi-out-str)
           interfaces (-> config :interfaces)
           state      (into {}
                            (map (fn [[k v]] [k (atom nil)])
                                 (-> config :interfaces :input-controls :controls)))
           busses     (into {}
                            (map (fn [[k v]] [k (control-bus)])
                                 (-> config :interfaces :input-controls :controls)))]
       (when force-external-led-mode?
         (set-external-led-mode! out))

       (doseq [[k v] (-> config :interfaces :input-controls :controls)]
         (let [type      (:type v)
               note      (:note v)
               handle    (concat event-handle [note])
               update-fn (fn [{:keys [data2-f]}]
                           (println "updating bus: " (busses k) data2-f)
                           (bus-set! (busses k) data2-f)

                           (reset! (state k) data2-f))]
           (cond
            (= :on-event (default-event-type type))
            (on-event handle update-fn (str "update-state-for" handle))

            (= :on-latest-event (default-event-type type))
            (on-latest-event handle update-fn (str "update-state-for" handle)))))

       (intromation out)
       (NanoKontrol2. (:name config) out interfaces state busses))))
