 
 ;; TODO: generalize goal condition, etc.
 
+(deftype PartialResult [result-pairs max-reward])
+
 (defn incremental-dijkstra 
   "Expand queue items until (1) goal, or (2) (queue-cutoff queue min-reward). 
    Safe against recursive calls in expand-fn, which takes a node and min-reward and
-   returns [[old-node new-reward] & [new-node reward]*]"
+   returns a PartialResult of nodes."
   [queue min-reward expand-fn goal-fn]
   (loop []
     (or (let [cutoff (queue-best-reward queue)] 
-          (when (not (viable? cutoff min-reward)) cutoff)) 
+          (when (not (viable? cutoff min-reward)) (PartialResult nil cutoff))) 
         (let [[best best-reward] (pop-queue queue)]
-          (or (when-let [g (goal-fn best)] [g best-reward])
+          (or (when-let [g (goal-fn best)] (PartialResult [[g best-reward]] (queue-best-reward queue)))
               (let [next-min-reward (max min-reward (queue-best-reward queue))]
                 (queues/pq-replace! queue best (make-queue-priority best-reward))
-                (let [[[_ new-reward] & new-items] (expand-fn best next-min-reward)]
-                  (assert (identical? _ best))
-                  (queues/pq-replace! queue best (make-queue-priority new-reward))
-                  (doseq [[ni nr] new-items] 
+                (let [{:keys [result-pairs max-reward]} (expand-fn best next-min-reward)]
+                  (queues/pq-replace! queue best (make-queue-priority max-reward))
+                  (doseq [[ni nr] result-pairs] 
                     (queues/pq-add! queue ni (make-queue-priority nr)))
                   (recur))))))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Outcome maps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+
+(defn make-descendents [state action prim-constructor ref-constructor]
+  (if (env/primitive? action)
+      (when-let [[ss sr] (and (env/applicable? action state) (env/successor action state))]
+        [(prim-constructor ss sr)])
+    (map ref-constructor (hierarchy/immediate-refinements action state))))
 
 (defn generalize-outcome-pair [[outcome-state reward] gen-state reward-to-gen-state]
   [(vary-meta (env/apply-effects gen-state (env/extract-effects outcome-state)) assoc 

  (expand-node        [min-reward] (throw (UnsupportedOperationException.))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Recursive Node ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(declare make-sp-recursive-node)

(deftype SPRecursiveNode [name subproblem remaining-actions] :as this
  Object
  (equals [y] (= name (:name y)))
  (hashCode [] (hash name))
  SearchNode
  (extract-goal-state []  nil)
  (expand-node        [min-reward]
    (let [result (next-solution-or-cutoff (force subproblem) min-reward)]
      (if (number? result) 
          [[this result]]
        [[this (nth result 1)]
         (make-sp-recursive-node result remaining-actions)]))))

(defn make-initial-sp-nodes [state action]
  (if (env/primitive? action)
    (when-let [[ss sr] (and (env/applicable? action state) (env/successor action state))]
      [[(GoalNode ss) sr]])
    (for [ref (hierarchy/immediate-refinements action state)]
      (make-sp-recursive-node [state 0] ref))))

(defn make-sp-recursive-node [[state reward] remaining-actions]
  [(if-let [[f & r] (seq remaining-actions)]
     (let [context          (env/precondition-context f state)
           state-in-context (env/extract-context state context)
           sub-name         [state-in-context (env/action-name f)]
           sup-name         [state-in-context (map env/action-name remaining-actions)]]
       (SPRecursiveNode sup-name
         (delay 
          (make-search-in-context 
           (get-cached-search sub-name 
             (make-incremental-dijkstra-search
              (make-initial-sp-nodes (env/get-logger state context) f)))
           state reward))
         r))
     (GoalNode state))
   reward])


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Drivers  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn sahucs-simple [henv]
  (binding [*problem-cache* (HashMap.)]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defprotocol IncrementalSearch 
  (next-partial-solution [sp min-reward]
     "Output is PartialResult, where results are states."))

(declare extract-goal-state expand-node)

