       (get-in [sas/goal-var-name sas/goal-false-val sas/goal-true-val])
       util/safe-singleton))
 
-(defn target-var [v] [:target v])
-(defn possible-parent-var [p c]  [:parent? p c])
-(defn possible-actions-var [v]  [:actions v])
+(defn target-var [v] [:target v]) ; a value for v, :wait if no target.
+(defn possible-children-var [v]  [:children v]) ; a set of child vars
+(defn possible-actions-var [v]  [:actions v]) ; a set of actions, :wait if no target.
 
 (defn expand-initial-state 
   "Expand the initial state with lots more stuff.  Each var can be free, OR
    have a child (in which case it must eventually be used to fire an active action on
    that var), AND in such a case, it can also have an active action to help achieve that val.
    (which changes only that var)."
-  [init child-var-map]
-  (let [vars (state/list-vars init)]
-    (state/set-vars init
+  [init child-var-map goal-action]
+  (let [vars (keys child-var-map)]
+    (into {}
       (concat 
-       (for [var vars] [(target-var v) nil])
-       (for [[p cs] child-var-map, c cs] [(possible-parent-var p c) true])
-       [[(target-var sas/goal-var-name) sas/goal-true-val]]))))
-
-
-
-
-(defn action-effect-var [a] (util/safe-singleton (keys (:precond-map a))))
-
-
-
-
-
-(defn make-add-action-action [{:keys [name precond-map effect-map reward] :as factored-primitive}]
-  (util/sref-set! *add-count* (inc (util/sref-get *add-count*)))
-  (let [[evar eval] (util/safe-singleton (seq effect-map))]
-    (env-util/make-factored-primitive
-     [::AddAction name]
-     {(action-var evar) nil, evar (precond-map evar)}
-     {(action-var evar) factored-primitive}
-     reward)))
-
-(defn make-set-parent-var-action [p-var c-var]
-  (env-util/make-factored-primitive 
-   [::SetParent p-var c-var] 
-   {(free-var p-var) true} 
-   {(free-var p-var) false (parent-var p-var c-var) true} 
+       (for [v vars] [v (state/get-var init v)])
+       (for [v vars] [(target-var v) :wait])
+       (for [v vars] [(possible-children-var v) (child-var-map v)])
+       (for [v vars] [(possible-actions-var v) :wait])
+       [[(target-var sas/goal-var-name) sas/goal-true-val]]
+       [[(possible-actions-var sas/goal-var-name) #{goal-action}]]))))
+
+(defn action-effect-var [a] (util/safe-singleton (keys (:effect-map a))))
+
+
+
+
+(defn make-assign-actions-action [v actions]
+  (assert (set? actions))
+  (env-util/make-factored-primitive
+   [::AssignActions v actions]
+   {}
+   {(possible-actions-var v) actions}
    0))
 
-
-(defn make-fire-action
-  "Simple version of greedy-fire, used for exhaustive action list. (No add-parent)."
-  [{:keys [name precond-map effect-map reward] :as factored-primitive}]
-  (let [effect-var (key (util/safe-singleton (seq effect-map)))
-        precond-vars (keys (dissoc precond-map effect-var))]
-    (env-util/make-factored-primitive
-     [::Fire name]
-     (into precond-map 
-           (concat [[(action-var effect-var) factored-primitive]]
-                   (for [v precond-vars] [(parent-var v effect-var) true])
-                   (for [v precond-vars] [(action-var v) :frozen])))
-     (into effect-map 
-           (concat [[(action-var effect-var) nil]]
-                   (for [v precond-vars] [(free-var v)              true])
-                   (for [v precond-vars] [(parent-var v effect-var) false])
-                   (for [v precond-vars] [(action-var v) nil])))
-     0)))
-
-
-;; TODO: should fail if I own parent, it has right value, but an action. (right now, we assert)...
-;; Try to make an action that greedily fires the action scheduled on effect-var,
-;; effectively representing a composition of set-parent and fire-action actions.
-;; Note that this avoids some (unnecessary) branching on children of parent vars.
-;; Assumes this will always be called on a "source", and asserts correspondingly.
-(defn make-greedy-fire-action [s effect-var]
-  (let [{:keys [name precond-map effect-map reward] :as factored-primitive}
-        (->> effect-var action-var (state/get-var s))
-        precond-vars (keys (dissoc precond-map effect-var))
-        [free-pv unfree-pv] (util/separate #(state/get-var s (free-var %)) precond-vars)]
-    (assert (every? #(contains? #{nil :frozen} (state/get-var s (action-var %))) precond-vars))
-#_    (util/assert-is (every? #(contains? #{nil :frozen} (state/get-var s (action-var %))) precond-vars)
-                    "%s" [name precond-map effect-map s])    
-    (env-util/make-factored-primitive
-     [::Fire name]
-     (into precond-map 
-           (concat [[(action-var effect-var) factored-primitive]]
-                   (for [v free-pv]   [(free-var v)              true])
-                   (for [v unfree-pv] [(parent-var v effect-var) true])
-                   (for [v precond-vars] [(action-var v) (state/get-var s (action-var v))])))           
-     (into effect-map 
-           (concat [[(action-var effect-var) nil]]
-                   (for [v unfree-pv] [(free-var v)              true])
-                   (for [v unfree-pv] [(parent-var v effect-var) false])
-                   (for [v precond-vars] [(action-var v) nil])))
-     0)))
-
-
-
-(defn make-greedy-fire-action [s firing-seq]
-  (doseq [[a1 a2] (partition 2 1 firing-seq)]
-    (let [v1 (action-effect-var a1)]
-      (assert (= (state/get-var s v1) (state/get-var s (target-var v1)) ((:precond-map a2) v1)))))
-  (assert (env/state-matches-map? s (apply util/merge-agree (map :precond-map firing-seq))))  
-  (env-util/make-factored-primitive
-   (vec (cons ::Fire (map :name firing-seq)))
-   (apply util/merge-agree (map :precond-map firing-seq))
-   (into precond-map 
-         (concat [[(action-var effect-var) factored-primitive]]
-                 (for [v free-pv]   [(free-var v)              true])
-                 (for [v unfree-pv] [(parent-var v effect-var) true])
-                 (for [v precond-vars] [(action-var v) (state/get-var s (action-var v))])))           
-   (into effect-map 
-         (concat [[(action-var effect-var) nil]]
-                 (for [v unfree-pv] [(free-var v)              true])
-                 (for [v unfree-pv] [(parent-var v effect-var) false])
-                 (for [v precond-vars] [(action-var v) nil])))
-   0)
-
-  
-  (let [{:keys [name precond-map effect-map reward] :as factored-primitive}
-        (->> effect-var action-var (state/get-var s))
-        precond-vars (keys (dissoc precond-map effect-var))
-        [free-pv unfree-pv] (util/separate #(state/get-var s (free-var %)) precond-vars)]
-    (assert (every? #(contains? #{nil :frozen} (state/get-var s (action-var %))) precond-vars))
-#_    (util/assert-is (every? #(contains? #{nil :frozen} (state/get-var s (action-var %))) precond-vars)
-                    "%s" [name precond-map effect-map s])    
-))
-
-
-(defn make-fire-action-type [s edge-rule effect-var]
-  (doto (case edge-rule
-          :naive (make-fire-action (->> effect-var action-var (state/get-var s)))
-          :greedy (make-greedy-fire-action s effect-var)
-          (:sloppy :extra-sloppy) (make-sloppy-fire-action s effect-var))
-     #_ (-> (env/applicable? s) assert)))
+(defn make-assign-children-action [p children]
+  (assert (set? children))
+  (env-util/make-factored-primitive
+   [::AssignChildren p children]
+   {}
+   {(possible-children-var p) children}
+   0))
+
+(defn make-commitment-action [p c cur-val dst-val wanting-actions possible-actions-fn]
+  (assert (not (= cur-val dst-val)))
+  (assert (set? wanting-actions))
+  (env-util/make-factored-primitive
+   [::Commit p c dst-val wanting-actions]
+   {}
+   {(possible-children-var p) #{c}
+    (possible-actions-var c) wanting-actions
+    (target-var p) dst-val
+    (possible-actions-var p) (possible-actions-fn p cur-val dst-val)}
+   0))
+
+(defn make-greedy-fire-action [s a effect-var cvm possible-actions-fn]
+  (doseq [[pvar pval] (dissoc (:precond-map a) effect-var)]
+    (assert (= (state/get-var s pvar) pval))
+    (assert (= (state/get-var s (possible-actions-var pvar)) :wait)))  
+  (env-util/make-factored-primitive
+   [::Fire a]
+   {}
+   (into (:effect-map a)
+         (cons
+          [(possible-actions-var effect-var)
+           (let [cur-val (get (:effect-map a) effect-var)
+                 dst-val (state/get-var s (target-var effect-var))]
+             (assert (not (= dst-val :wait)))
+             (if (= cur-val dst-val) :wait (possible-actions-fn effect-var cur-val dst-val)))]           
+          (apply concat
+                 (for [[pvar pval] (dissoc (:precond-map a) effect-var)]
+                   [[(possible-children-var pvar) (cvm pvar)]
+                    [(possible-actions-var pvar) :wait]
+                    [(target-var pvar) :wait]]))))
+   (:reward a)))
+
+
+
 
 
 

          :when (and (= s cur-val) (not (contains? (backward-sets t) s)))]
      t)))


(defn allowed-action? [s a effect-var]
  (assert (= effect-var (util/safe-singleton (keys (:effect-map a)))))
  (every?
   (fn [v]
     (when (state/get-var s (possible-parent-var v effect-var))
       (assert (not (state/get-var s (target-var v))))
       true))   
   (keys (:precond-map a))))

(defn greedy-action? [s a] (state/state-matches-map? s (:precond-map a)))


;; if a var is actually assigned and has a target and its value is right, ...
(defn fire-sequences [s v])





(defn bottom-up-actions [s v cvm dtgs acyclic-succ-fn]
  (let [cur-val (state/get-var s v)
        dst-val (state/get-var s (target-var v))
        [greedy-actions ungreedy-actions] (->> (acyclic-succ-fn v cur-val dst-val)
                                               (map (dtgs v cur-val))
                                               (apply concat)
                                               (filter #(allowed-action? s % v) )
                                               (util/separate greedy-action?))]
    (assert dst-val)
    (assert (not (= cur-val dst-val)))
    (concat
     (intentional-actions s ungreedy-actions)
     (for [a greedy-actions, fs (fire-sequences s a)]
       (make-greedy-fire-action s fs)))))





;; TODO: generalize to modes other than greedy.
(defn var-ordering-edges
  "Construct a graph on the state variables, where an edge from s --> t means
   'something must happen at s for the action at t to go away', more or less.

   Specifically, we have the following kinds of edges:
    (1)                  If (= (action-var v) :frozen), child(v)!=nil, child(v) -->  v
    (2)(a) naive:        If (action-var c) has precondition on p, (not owned or not frozen) and not reserved elsewhere, p --> c
    (2)(b) greedy etc.:  If (action-var c) has precondition on p, value mismatch and not reserved elsewhere, p --> c
    (3)(a) naive+greedy: If (action-var c) has precondition on p, reserved by o!=c, o --> c
    (3)(b) sloppy:       If (action-var c) has precondition on p, value mismatch or action on p and reserved by o!=c, o --> c
    (3)(c) extra-sloppy: If (action-var c) has precondition on p, value mismatch and reserved by o!=c, o --> c"   
  [s child-map rule]
  (apply concat
         (for [v (keys child-map)]
           (let [a (state/get-var s (action-var v))]
             (cond
               (nil? a)      nil
               (= :frozen a) (when-let [c (current-child s child-map v)] [[c v]])
               :else         (remove nil?
                               (for [[p pval] (-> a (util/safe-get :precond-map) (dissoc v))]
                                (let [right-val? (= (state/get-var s p) pval)
                                      p-child    (current-child s child-map p)
                                      unavail?   (not (or (= p-child nil) (= p-child v)))]
                                  (case rule
                                    :naive  (cond unavail?         [p-child v]
                                                  (or (not (= p-child v)) (not (= (state/get-var s (action-var p)) :frozen))) [p v])
                                    :greedy (cond unavail?         [p-child v]
                                                  (not right-val?)
                                                  #_(when-not (some #(let [c (current-child s child-map %)]
                                                                     (not (or (= p-child nil) (= p-child v))))
                                                                  (keys (dissoc (:precond-map a) v)))
                                                    [p v])  ;; TODO: put back?

                                                    [p v])
                                    :sloppy (cond (and unavail? (or (not right-val?) (when-let [a (state/get-var s (action-var p))] (not (= a :frozen)))))         [p-child v]
                                                  (and (not unavail?) (not right-val?)) [p v])
                                    :extra-sloppy
                                            (cond (and unavail? (not right-val?)) [p-child v]
                                                  (and (not unavail?) (not right-val?)) [p v]))))))))))




(defn source-vars
  "Take the graph from var-ordering-edges, and return the sources in the same component
   as the goal variable, which are ripe for action.  Returns nil if there are any cycles
   in the graph, since this indicates a deadlock (at least some actions cannot fire)."
  [s child-map check-deadlock? check-components? edge-rule]
;  (println (var-ordering-edges s child-map rule))
  (let [edges (doall (var-ordering-edges s child-map edge-rule))]
    (when (or (not check-deadlock?) (graphs/dag? edges)) 
      (let [sources (clojure.set/difference (set (cons sas/goal-var-name (map first edges))) (set (map second edges)))
            goal-component-sources
            (if check-components?
              (clojure.set/intersection
               sources
               (graphs/ancestor-set (cons [sas/goal-var-name sas/goal-var-name] edges) [sas/goal-var-name]))
              sources)]
        (when-not (= (count sources) (count goal-component-sources)) (println "Warning: multiple components..."))
        (when check-deadlock? (assert (seq goal-component-sources)))
        goal-component-sources))))

(defn source-var-type [s child-map v]
  (let [a (state/get-var s (action-var v))]
    (cond (= a :frozen)  :top-down-activate
          a              :fire

          ;; no action
          (not (state/get-var s (free-var v))) :bottom-up-action 
          (some (fn [c] (when-let [ca (state/get-var s (action-var c))]
                          (contains? (:precond-map ca) v)))
                (child-map v))
                         :bottom-up-activate
          :els           :top-down-action)))

;; TODO: dynamic bottom-up pruning.
 ; i.e., exists precondition of some current action, NOT currently achieved,
 ; that has every child of a parent-link in its ancestor-set. 
; Or, more simply, variables should "die off".  
;; TODO: generalize.  This is just special case for most logistics.
(defn uses-dead-vars? [s ancestor-map child-map extra-edges]
;  false #_
  (let [gpm      (:precond-map (state/get-var s (action-var sas/goal-var-name)))
        live-set (apply clojure.set/union #{sas/goal-var-name}
                        (for [pv (remove #{sas/goal-var-name} (keys gpm))
                              :when (not (= (state/get-var s pv) (gpm pv)))]
                          (ancestor-map pv)))]
    (not-every? live-set
                (concat (map second extra-edges)
                        (for [p (keys child-map)
                              :let [a (state/get-var s (action-var p))]
                              :when (and a (not (= a :frozen)))]
                          p)
                        (for [[p cs] child-map, c cs
                              :when (state/get-var s (parent-var p c))]
                          c)))))


(defn activation-actions  "Return a list of all activation actions for var v"
  [child-map v]
  (for [c (child-map v)]
    (make-set-parent-var-action v c)))

(defn add-actions [s v dtgs]
  (cons (make-freeze-var-action v)
        (for [as (vals (get-in dtgs [v (state/get-var s v)])), a as]
          (make-add-action-action a))))

(defn add-directed-actions [s v dtgs cvm acyclic-succ-fn]
  (let [c-val (state/get-var s v)
        dtg   (get-in dtgs [v c-val])
        child (current-child s cvm v)
        d-val (-> (state/get-var s (action-var child)) :precond-map (get v))]
    ;;    (when greedy? #_ (util/assert-is (not (= c-val d-val)) "%s" (def *s* s)))
    (if d-val 
      (if (= c-val d-val)
        [(make-freeze-var-action v)]
        (for [n-val (acyclic-succ-fn v c-val d-val), a (dtg n-val)]
          (make-add-action-action a)))
      ;; This should only arise in cyclic domains -- TODO: remove?
      (add-actions s v dtgs))))

;   (or (deadlocked? s child-map [[v c]]))




;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Actions fn, actual env ;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defrecord ASPlanEnv [base-sas-env init actions actions-fn g-map 
                    ; Following stuff is used by hierarchy.
                      causal-graph dtgs ancestor-var-map child-var-map topological-sort-indices acyclic-succ-fn]
  env/Env 
    (initial-state [e] init)
    (actions-fn    [e] actions-fn)

  env/FactoredEnv
    (goal-map      [e] g-map))


(defn make-asplan-env
  "Make an actino-set planning environment.  Switches are:
    check-deadlock?: check for cycles in precedence graph above and beyond lack of sources
