 (def friction-value 0.80)
 (def min-velocity 0.05)
 
-(sm/defn should-update-velocity? :- s/Bool
+; TODO namespace keywords
+
+(defn should-update-velocity?
   "Entities' velocity should be updated if they're intending to move somewhere
   or if they're currently moving and affected by friction."
-  [entity :- Entity]
-  (or (get-in entity [:motion :direction])
+  [entity]
+  (or (get-in entity [:component/motion :motion/direction])
       (and
-        (get-in entity [:motion :affected-by-friction])
+        (get-in entity [:component/motion :motion/affected-by-friction])
         (or
-          (not= (get-in entity [:motion :velocity :x]) 0)
-          (not= (get-in entity [:motion :velocity :y]) 0)))))
+          (not= (get-in entity [:component/motion :motion/velocity :geometry/x]) 0)
+          (not= (get-in entity [:component/motion :motion/velocity :geometry/y]) 0)))))
 
-(sm/defn get-acceleration :- s/Num
-  [entity :- Entity]
-  (if (get-in entity [:motion :direction])
-    (get-in entity [:motion :max-acceleration])
+(s/fdef should-update-velocity?
+  :args (s/cat :entity :entity/entity)
+  :ret boolean?)
+
+(defn get-acceleration
+  [entity]
+  (if (get-in entity [:component/motion :motion/direction])
+    (get-in entity [:component/motion :motion/max-acceleration])
     0))
 
-(sm/defn -update-axis-velocity :- Entity
-  [entity :- Entity
-   axis :- Axis
-   trig-fn :- (s/enum Math/cos Math/sin)]
-  (let [axis-velocity (get-in entity [:motion :velocity axis])
+(s/fdef get-acceleration
+  :args (s/cat :entity :entity/entity)
+  :ret number?)
+
+(defn -update-axis-velocity
+  [entity axis trig-fn]
+  (let [axis-velocity (get-in entity [:component/motion :motion/velocity axis])
         new-velocity (+ axis-velocity
                         (* (get-acceleration entity)
-                           (trig-fn (get-in entity [:motion :direction]))))]
+                           (trig-fn (get-in entity [:component/motion :motion/direction]))))]
     (if (> (Math/abs new-velocity) min-velocity)
-      (assoc-in entity [:motion :velocity axis] new-velocity)
-      (assoc-in entity [:motion :velocity axis] 0))))
+      (assoc-in entity [:component/motion :motion/velocity axis] new-velocity)
+      (assoc-in entity [:component/motion :motion/velocity axis] 0))))
 
-(sm/defn cap-velocity :- Entity
-  [entity :- Entity]
-  (let [velocity (get-in entity [:motion :velocity])
-        x-velocity (velocity :x)
-        y-velocity (velocity :y)
-        max-speed (get-in entity [:motion :max-speed])
+(s/fdef -update-axis-velocity
+  :args (s/cat :entity (s/and :entity/entity
+                              #(contains? (% :entity) :component/motion))
+               :axis #{:geometry/x :geometry/y}
+               :trig-fn #{Math/cos Math/sin})
+  :ret :entity/entity)
+
+(defn cap-velocity
+  [entity]
+  (let [velocity (get-in entity [:component/motion :motion/velocity])
+        x-velocity (velocity :geometry/x)
+        y-velocity (velocity :geometry/y)
+        max-speed (get-in entity [:component/motion :max-speed])
         amplitude (Math/sqrt (+ (* x-velocity x-velocity)
                                 (* y-velocity y-velocity)))
         multiplier (if (> amplitude max-speed)
                      (/ max-speed amplitude)
                      1)]
     (assoc-in entity
-              [:motion :velocity]
+              [:component/motion :motion/velocity]
               {:x (* x-velocity multiplier)
                :y (* y-velocity multiplier)})))
 
-(sm/defn update-velocity :- Entity
-  [entity :- Entity]
+(s/fdef cap-velocity
+  :args (s/and (s/cat :entity :entity/entity)
+               #(contains? (% :entity) :component/motion))
+  :ret :entity/entity)
+
+(defn update-velocity
+  [entity]
   (if (should-update-velocity? entity)
     (-> entity
-        (-update-axis-velocity :x Math/cos)
-        (-update-axis-velocity :y Math/sin)
+        (-update-axis-velocity :geometry/x Math/cos)
+        (-update-axis-velocity :geometry/y Math/sin)
         cap-velocity)
     entity))
 
-(sm/defn apply-friction :- Entity
-  [entity :- Entity]
-  (if (get-in entity [:motion :affected-by-friction])
+(s/fdef update-velocity
+  :args (s/cat :entity :entity/entity)
+  :ret :entity/entity)
+
+(defn apply-friction
+  [entity]
+  (if (get-in entity [:component/motion :motion/affected-by-friction])
     (reduce
       (fn [entity axis]
-        (update-in entity [:motion :velocity axis] #(* % friction-value)))
+        (update-in entity [:component/motion :motion/velocity axis] #(* % friction-value)))
       entity
-      [:x :y])
+      [:geometry/x :geometry/y])
     entity))
 
-(sm/defn update-position :- Entity
-  [entity :- Entity]
-  (let [velocity (-> entity :motion :velocity)
-        center (-> entity :shape :center)]
+(s/fdef apply-friction
+  :args (s/and (s/cat :entity :entity/entity)
+               #(contains? (% :entity) :component/motion))
+  :ret :entity/entity)
+
+(defn update-position
+  [entity]
+  (let [velocity (-> entity :component/motion :motion/velocity)
+        center (-> entity :component/shape :shape/center)]
     (assoc-in entity
-              [:shape :center]
-              {:x (+ (velocity :x) (center :x))
-               :y (+ (velocity :y) (center :y))})))
+              [:component/shape :shape/center]
+              {:geometry/x (+ (velocity :x) (center :x))
+               :geometry/y (+ (velocity :y) (center :y))})))
 
-(sm/defn relevant-to-movement-system? :- s/Bool
-  [entity :- Entity]
+(s/fdef update-position
+  :args (s/and (s/cat :entity :entity/entity)
+               #(contains? (% :entity) :component/motion)
+               #(contains? (% :entity) :component/shape))
+  :ret :entity/entity)
+
+(defn relevant-to-movement-system?
+  [entity]
   (or
-    (get-in entity [:motion :direction])
-    (not= (get-in entity [:motion :velocity :x] 0) 0)
-    (not= (get-in entity [:motion :velocity :y] 0) 0)))
+    (get-in entity [:component/motion :motion/direction])
+    (not= (get-in entity [:component/motion :motion/velocity :geometry/x] 0) 0)
+    (not= (get-in entity [:component/motion :motion/velocity :geometry/y] 0) 0)))
+
+(s/fdef relevant-to-movement-system?
+  :args (s/cat :entity :entity/entity)
+  :ret boolean?)
 
 ;; System definition
 
-(sm/def move-system :- System
+(def move-system
   {:tick-fn (fn move-system-tick [entities]
               (doseq [entity (filter relevant-to-movement-system? entities)]
                 (let [moved-entity (-> entity


                  (when (not= moved-entity entity)
                    (attempt-to-move! entity
                                      (-> moved-entity :shape :center)
                                      (-> moved-entity :motion :velocity)
                                      entities)))))})

(ns voke.system.movement
  (:require [cljs.spec :as s]
            [voke.events :refer [publish-event]]
            [voke.system.collision.system :refer [attempt-to-move!]]))

; A dumb-as-rocks velocity/acceleration system.
; Based on http://www.randygaul.net/2012/02/22/basic-2d-vector-physics-acceleration-orientation-and-friction/ .
