 (defprotocol Evaluable
   (evaluate!      [s]))
 
-(defn can-evaluate? [s]
+(defn can-evaluate? [s] 
   (instance? angelic.search.implicit.fah_astar_eval2.Evaluable s))
 
 ;; Stub implements node, watched, possibly Evaluable, cached, Summarizable
-;;  -- Has at most a single output.
-;; Reward does not include output -- so stub + output reward gives consistent picture.
-;; Watchers of stub must include it as OR- in their summaries.
-;; Stubs cannot be subsumption children.
-;; TODO: codify these constraints somehow. 
-
+;;  -- Has at most a single output, not included in local reward -- goes dead 
 (defprotocol Stub
   (stub-name   [s])
   (input-set   [s]))
 
-(traits/deftrait simple-stub [name inp] [] [] Stub (input-set [s] inp) (stub-name [s] name))
+(defn get-stub-output [s] (util/safe-singleton (get-outputs s)))
+
+(traits/deftrait simple-stub [name inp] [] [simple-cached-node simple-watched]
+  Stub (input-set [s] inp) (stub-name [s] name))
 
 (defmethod print-method angelic.search.implicit.fah_astar_eval2.Stub [s o]
   (print-method (format "#<ST$%8h %s>" (System/identityHashCode s) (stub-name s)) o))
+
 
 (defprotocol Subproblem
   (stub              [s])
   (output-set        [s])
   (tree-summarizer   [s] "Summarizer that includes children.")
-  (terminal?         [s] "Subproblem will not return further outputs.")
+  (terminal?         [s] "Subproblem will not return any outputs.")
   (refine-input      [s refined-input-set] "Return a child stub."))
 
 (defn subproblem-name [s] (stub-name (stub s)))


(declare make-state-abstracted-subproblem)
(defn make-state-abstracted-stub [inner-stub in-set]
 ; (println "MSAS" inner-stub in-set)
  (let [ret (traits/reify-traits
             [simple-cached-node simple-watched or-summarizable
              (simple-stub [:SA (stub-name inner-stub) in-set] in-set)])]
    (connect-and-watch! ret inner-stub #(set-stub-output! ret (make-state-abstracted-subproblem ret %)))
    ret))

;; Note: subsumed subproblems can have different irrelevant vars
(defn make-state-abstracted-subproblem [stb inner-sp]
;  (println "MSASP" inner-sp )
  (let [ts  (tree-summarizer inner-sp)
        in  (input-set stb)
        out (state/transfer-effects in (output-set inner-sp))
        ret (traits/reify-traits [simple-cached-node simple-watched or-summarizable]
             Subproblem             (stub            [s] stb)
                                    (output-set      [s] out)
                                    (tree-summarizer [s] ts)
                                    (terminal?       [s] (terminal? inner-sp))
                                    (refine-input    [s ni] (if (=-state-sets ni in) stb (refine-input inner-sp ni))))]
    (connect-and-watch! ret inner-sp
      (fn [o] (connect-and-watch! ret (make-state-abstracted-stub (stub o) in) #(add-sp-child! ret %))))
    
    ret))



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  Subproblem Impl  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn set-stub-output! [stub sp]
  (assert (empty? (get-outputs stub)))
  (summaries/summary-changed-local! stub)
  (add-output! stub sp))

(defn add-sp-child! [sp child-sp]
  (assert (not (terminal? sp)))
  (summaries/summary-changed-local! sp)
  (add-output! sp child-sp))


(traits/deftrait simple-subproblem
  [stb out-set ts term? ri-fn] []
  [simple-cached-node simple-watched]
  Subproblem (stub            [s] stb)
             (output-set      [s] out-set)
             (tree-summarizer [s] ts)
             (terminal?       [s] term?)
             (refine-input    [s ni] (ri-fn s ni)))


(defn make-simple-subproblem [stub subsuming-sp out-set terminal? summary-fn ri-fn init-bound]
  (let [ts  (make-tree-summarizer init-bound)
        ret (traits/reify-traits [(simple-subproblem stub out-set ts terminal? ;; Note ni may have different context.
                                                     (fn [s ni] (if (= ni (input-set stub)) stub (ri-fn s ni))))]
              summaries/Summarizable (summarize       [s] (summary-fn s (top-down-bound ts))))]
    (init-tree-summarizer! ts ret subsuming-sp)
    ret))

;; TODO: collect children too ?

(declare make-output-collecting-subproblem)
(defn make-output-collecting-stub [inner-stub]
  (assert (not (= (first (stub-name inner-stub)) :OS)))
  (assert (not (= (first (stub-name inner-stub)) :SA)))  
  (let [in-set (input-set inner-stub)
        ret (traits/reify-traits [or-summarizable (simple-stub [:OS (stub-name inner-stub) in-set] in-set)])]
    (connect-and-watch! ret inner-stub #(set-stub-output! ret (make-output-collecting-subproblem ret %)))
    ret))

