 
 ; Only changes from sahucs.clj are in expand-sa-node.
 
+(def *infinite-depth* 1000000000000)
+
 (declare get-sa-node)
-(defn get-sanode-entry [cache state reward-to-state actions]
+(defn get-sanode-entry [cache state reward-to-state actions min-cycle-depth]
   (make-sanode-entry state 
    (when (seq actions) (get-sa-node cache state (first actions)))
-   reward-to-state actions))
+   reward-to-state actions min-cycle-depth))
 
 (defn get-sa-node [#^HashMap cache s a]
   "Create a new sa-node, or returned the cached copy if it exists."

        (SANode context a 
          (atom (if ss {(extract-effect ss context [a]) r} {})) 
          (make-queue (for [ref (when-not prim? (hierarchy/immediate-refinements a s))]
                        [(get-sanode-entry cache s 0.0 ref) 0.0])))))))


;; May return states better than next-best, but these will be held at the parent.
(defn expand-sa-node [node #^HashMap cache next-best state reward-to-state last-cutoff
                      #^IdentityHashMap stack-node-depths depth]
  (assert (not (.containsKey stack-node-depths node)))
  (.put stack-node-depths node depth)
  (loop [new-results (if (= last-cutoff (cutoff node)) {}
                         (util/filter-map #(<= (val %) last-cutoff)  @(:result-map-atom node)))
         min-cycle-depth 10000000000000
         bad-kids nil ; list of entries involved in cycles that need to be fixed before exit
         bad-results {}] 
     (if (< (cutoff node) next-best)
         (let [cut (cutoff node)] ; Cutoff before fixing cycling children.
           (.remove stack-node-depths node)
           (doseq [entry bad-kids] 
             (queues/g-pq-replace! (:queue node) entry 
               (- 0 (:reward-to-state entry) (if-let [n  (:sanode entry)] (cutoff n) 0))))
           (PartialResult (stitch-effect-map new-results state reward-to-state) cut min-cycle-depth
                          (stitch-effect-map bad-results state reward-to-state)))   
       (let [[entry neg-reward] (queues/g-pq-remove-min-with-cost! (:queue node))
             b-s (:state entry), b-rts (:reward-to-state entry), 
             b-ra (:remaining-actions entry), b-sa (:sanode entry),
             rec-next-best (- (max next-best (cutoff node)) b-rts)]
           (if (empty? b-ra)
               (let [eff (extract-effect b-s (:context node) (:opt (meta b-s)))]
                 (if bad-kids
                     (recur new-results min-cycle-depth (cons entry bad-kids)
                            (assoc-safe bad-results >= eff b-rts))
                   (do (swap! (:result-map-atom node) assoc-safe >= eff b-rts)
                       (recur (assoc-safe new-results >= eff b-rts) min-cycle-depth bad-kids bad-results))))
             (let [rec  (if-let [stack-depth (.get stack-node-depths b-sa)]
                            (PartialResult {} (- neg-reward) stack-depth {})
                          (expand-sa-node b-sa cache rec-next-best b-s b-rts (- 0 neg-reward b-rts)
                                          stack-node-depths (inc depth)))
                   inside-cycle? (< (:min-cycle-depth rec) depth)]
               (doseq [[ss sr] (:result-map rec)]
                 (queues/g-pq-add! (:queue node) (get-sanode-entry cache ss sr (next b-ra)) (- sr)))
               (when (or inside-cycle? (> (:cutoff rec) Double/NEGATIVE_INFINITY)) 
                 (queues/g-pq-replace! (:queue node) entry (- 0 b-rts (:cutoff rec))))
               (if inside-cycle?
                   (recur new-results (min min-cycle-depth (:min-cycle-depth rec)) (cons entry bad-kids) bad-results)
                 (recur new-results min-cycle-depth bad-kids bad-results))))))))

;; ALMOST: except suboptimal states may get cached at higher levels too.
;; Such bad states cannot be cached.  
;;  (DUH)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    Top-level    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (util/map-map1 
   (fn [[effects local-reward]]
     [(vary-meta (env/apply-effects state effects) assoc 
                 :opt (concat (:opt (meta state)) (:opt (meta effects)))
                 :cycle-depth (:cycle-depth (meta effects)))
      (+ reward-to-state local-reward)]) 
   effect-map))


(defn cutoff [queue]
  (- (nth (queues/g-pq-peek-min queue) 1)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Data Structures ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
