    function."
   [init fn-coll]
   ((apply comp fn-coll) init))
+
+(println "test iter-fns" (iter-fns {} [#(assoc % :yo :dawg)]))
+
+(defn game-loop
+  [scenes scene-id state frame-count]
+  (if (< frame-count 10)
+    (recur scenes scene-id
+           (iter-fns state (scene-id scenes))
+           (inc frame-count))
+    state))
+
+(println "test game-loop" (game-loop {:yo [#(assoc % :yo :dawg)]} :yo {} 0))
 
 (defn deep-merge
   "Recursively merges maps. If vals are not maps, the last value wins.

    (apply merge-with deep-merge vals)
    (last vals)))

(defn mk-component
  [component-id fields & [init-state]]
  (let [default-state (reduce into {} (for [f fields] {f nil}))
        init-state (or init-state default-state)]
    {component-id {:fields fields
                   :init-state init-state}}))

(defn add-component
  "Adds a component for the given entity-id and component"
  [state component]
  (assoc-in state [:components :_meta] component))

(defn mk-entity
  "Returns a hashmap representing the entities identity, components and systems.
   Validates 

   Example:
   (mk-entity :player {:moveable {:move f}})"
  [uuid components systems]
  ;; TODO validate that each component has all required component fns
  ;; implemented. Can we do this at compile time?

  [entity components systems])

(defn add-entity
  "Adds an entity to the game state hashmap or overwrites it if it
   already exists.

   Example:
   (let [[e c s] (mk-entity :p1 [] []
     (add-entity game-state e c s)"
  [state entity components systems]
  (deep-merge state {:entities entity
                     :components components
                     :systems systems}))

(defn add-system
  "Adds or overwrites a system for the given entity-id and component"
  [state entity-id component system f]
  (assoc-in state [:systems entity-id component system] f))

(defn remove-entity
  "Remove an entity and all of it's constituant components and systems"
  [])

(defn implements-component? [entity component]
  (boolean (some #{component} (:components entity))))

(defn filter-by-component
  "Takes a vector of id, hashmap pairs where the hashmap has a key
   for :components that the entitity implements.

   Returns a vector of ids that implement component."
  [entities component]
  (map first
       (filter #(implements-component? (second %) component) entities)))

(defn get-system-fns
  "Returns a vector of functions for the component."
  [systems ids component]
  (map #(get-in systems [% component]) ids))

;; This only operates on entities, can a system work on something
;; other than entities? What about game meta data?
(defn exec-system
  "Execute the component by calling each component function in order."
  [state component fn-keys]
  (let [;; Get all entities that implement this component
        ids (filter-by-component (seq (:entities state)) component)
        ;; Get the system for the matching component
        component-fns (get-system-fns (:systems state) ids component)
        ;; Make a sequence of all the functions to call in order as
        ;; specified by fn-keys
        fns (reduce into [] (for [k fn-keys] (map k component-fns)))] 
    (iter-fns state fns)))

(defn mk-system-spec
  "Convenience wrapper so you don't have to specify vectors of vectors.

   Example:
   (mk-system-spec [:my-sys [:f1 :f2]]
                   [:my-other-sys [:f3 :f4]])"
  [& specs] specs)


;; Gameloop:   recursive function that calls all systems in a scene
;;
;; Scenes:     collection of system functions called by the game loop
;;
;; Systems:    functions that operate on components and return
;;             updated game state.
;;
;; Entities:   unique IDs that have a list of components to
;;             participate in
;;
;; Components: hold state and lists of functions relating to a certain aspect.
;;
;; State:      stores state for components, entities, and systems
;;
;; Using one state hashmap should be performant enough even though it
;; creates a new copy on every change to state in the game loop due to
;; structural sharing

(def SCENES {})
(def STATE {})

(defn add-scene
  "Add or update existing scene in the scenes hashmap"
  [scenes-hm uid fns]
  (assoc scenes-hm uid fns))

(println "test add-scene" (add-scene SCENES :yo [identity]))

(defn iter-fns
  "Pass an initial value through a collection of functions with the 
