 (defprotocol SDH-HLA
   (active-var-set  [a])
   (leaf-var-set    [a])
-  (greedy?         [a s v av])    ; Has a descendent that can be done greedily.
-  (do-refinement   [a s v av lv]) ;returns [action-seq new-hla]. av is active-var set, lv is leaf-var set
+  (needs-expand?   [a])
+  (expand          [a lv])           ; returns [[action-seq new-hla]]
+  (greedy-select?  [a s v av])    ; Has a descendent that can be done greedily.
+  (select-leaf     [a s v av]) ; returns new-hlas. av is active-var set, lv is leaf-var set
   ) 
 
 

;; TODO: fire more than one greedy action at once ...
; ;TODO: how do we keep track of preconditions moved up front ?

; Am I greedy, or do I have a 
(declare make-action-hla)

(deftype SDH-Action-HLA [hierarchy name action precond-var-set precond-hlas] :as this
  SDH-HLA
    (active-var-set []  (apply clojure.set/union (map active-var-set precond-hlas)))
    (leaf-var-set   []  (apply clojure.set/union (map leaf-var-set precond-hlas)))
    (greedy?        [s v av] 
      (or (every? #(and (satisfied? % s) (or (active? %) (not (av (:var %))))) precond-hlas)
          (some #(greedy? % s v av) (util/make-safe (seq (filter #(contains? (leaf-var-set %) v) precond-hlas))))
          ))
    (do-refinement  [s v av lv]
      (if (every? #(and (satisfied? % s) (or (active? %) (not (av (:var %))))) precond-hlas) 
          (do (println "GREED2") [[[action] nil]])
        (let [possible-vals  (filter #(contains? (leaf-var-set %) v) precond-hlas)
              [deep shallow] (util/separate active? possible-vals)
              val-options    (or (and (:greedy-optimization? hierarchy) 
                                      (when-first [x (filter #(greedy? % s v av) deep)] [x])) 
                                 (seq deep) 
                                 (seq shallow))]
;          (println "refining at " v "with options" val-options)
            (assert (seq val-options))
            (assert (<= (count shallow) 1))
        
            (for [precond-hla val-options
                  [prefix remaining] (do-refinement precond-hla s v av lv)]
              [prefix 
               (let [new-precond-hlas
                      (for [hla precond-hlas]
                        (if (identical? hla precond-hla) remaining hla))]
                 (SDH-Action-HLA. hierarchy
                   [:!A* (env/action-name action) (map env/action-name new-precond-hlas)]
                   action precond-var-set new-precond-hlas))]))))
  env/Action
    (action-name     [] name)
    (primitive?      [] false)


(deftype SDH-Active-Precond-HLA  [hierarchy name first-action leaf-precond active-var-set leaf-var-set] :as this
  SDH-HLA
    (active-var-set  []  active-var-set)
    (leaf-var-set    []  leaf-var-set)
    (needs-expand?   []  (needs-expand? first-action))
    (expand          [lv] 
      (for [[prefix new-fa] (expand first-action lv)]
        [prefix (if new-fa (make-active-precond-hla hierarchy new-fa leaf-precond) leaf-precond)]))
    (greedy-select?  [s v av] (greedy-select? first-action s v av))
    (select-leaf      [s v av] 
      (for [new-fa (select-leaf first-action s v av)] 
        (make-active-precond-hla hierarchy new-fa leaf-precond)))
  SDH-Precond-HLA  
    (active?     []  true)
    (satisfied?  [s] false)    
  env/Action
    (action-name [] name)
    (primitive?  [] false)
 ; env/ContextualAction 
 ;   (precondition-context [s] (env/precondition-context leaf-precond s))   
    )

(defn- make-active-precond-hla [hierarchy first-action leaf-precond]
  (SDH-Active-Precond-HLA hierarchy 
    [:!P+ (env/action-name first-action) (env/action-name leaf-precond)]
    first-action leaf-precond
    (clojure.set/union (active-var-set first-action) (active-var-set leaf-precond))
    (leaf-var-set first-action)))



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Leaf Precond HLAs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(declare advance-active-leaf-precond-hla)

(deftype SDH-Active-Leaf-Precond-HLA  [name inactive-leaf cur-val] :as this
  SDH-HLA
    (active-var-set  []  (leaf-var-set inactive-leaf))
    (leaf-var-set    []  (active-var-set inactive-leaf))
    (needs-expand?   []  (not (satisfied? this)))
    (expand          [lv] 
      (let [{:keys [hierarchy var dst-val]} inactive-leaf]               
       (cond (empty? (clojure.set/intersection lv ((:interfering-set hierarchy) var)))
               [[[inactive-leaf] (advance-active-leaf-precond-hla this dst-val)]]
             (= cur-val dst-val)
               [[[]     this]]
             :else  
               (for [[nv as] (get dtg cur-val), 
                     :let [np (advance-active-leaf-precond-hla this nv)]
                     action as
                     :let [ahla (make-action-hla hierarchy action)]]
                 (if (env/primitive? ahla)
                     [[ahla] np]
                   [[] (make-active-precond-hla hierarchy ahla np)])))))
    (greedy-select?  [s v av] false)
    (select-leaf     [s v av] (throw (UnsupportedOperationException.)))
  SDH-Precond-HLA 
    (active?     []  true)
    (satisfied?  [s] (= cur-val (:dst-val inactive-leaf)))    
  env/Action
    (action-name [] name)
    (primitive?  [] false))

(defn- advance-active-leaf-precond-hla [prev new-val]
  (SDH-Active-Leaf-Precond-HLA (:name prev) (:inactive-leaf prev) new-val))

(defn- make-active-leaf-precond-hla [inactive-leaf cur-val]
  (SDH-Active-Leaf-Precond-HLA (assoc (:name inactive-leaf) 0 :!P*) inactive-leaf cur-val))


(deftype SDH-Inactive-Leaf-Precond-HLA  [hierarchy name var dst-val dtg precond-var-set] :as this
  SDH-HLA
    (active-var-set  []  #{})
    (leaf-var-set    []  #{var})
    (needs-expand?   []  false)
    (expand          [lv] (throw (UnsupportedOperationException.)))
    (greedy-select?  [s v av] false)
    (select-leaf     [s v av] (assert (= v var)) [(make-active-leaf-precond-hla this (env/get-var s v))])
  SDH-Precond-HLA 
    (active?     []  false)
    (satisfied?  [s] (= (env/get-var s var) dst-val))    
