 (def no-children :terminal)
 
 (defprotocol Subproblem
+  (input-set       [s])
+  (output-set      [s])
   (current-summary [s])
   (child-keys      [s] "seq or no-children")
   (get-child       [s child-key])
   (refine-input    [s refined-input-set]))
 
-(def input-set :input-set)
-(def output-set :output-set)
-(defn get-child-map [s] (into {} (for [k (child-keys s)] [k (get-child s k)])))
-
+;;(def input-set :input-set)
+;;(def output-set :output-set)
+;;(defn get-child-map [s] (into {} (for [k (child-keys s)] [k (get-child s k)])))
+
+
+
+
+
+;; TODO: getting child from super ...
+(declare make-generic-subproblem)
+
+(defrecord GenericSubproblem [; ??? summarizer
+                              kernel in-set out-set child-key-seq
+                              ^HashMap child-cache ^HashMap refinement-cache]
+  (input-set       [s] in-set)
+  (output-set      [s] out-set)
+  (current-summary [s] ...???)
+  (child-keys      [s] child-key-seq)
+  (get-child       [s child-key]
+    (util/cache-with child-cache child-key (compute-child-kernel kernel in-set child-key)))
+  (refine-input    [s refined-input-set]
+    (if (= in-set refined-input-set)
+      s
+      (util/cache-with refinement-cache refined-input-set
+                       (make-generic-subproblem kernel refined-input-set)))))
+
+(defn make-generic-subproblem [kernel input-set]
+  (GenericSubproblem.
+   kernel
+   input-set
+   (compute-output-set kernel input-set)
+   (compute-child-keys kernel input-set)
+   (HashMap.) (HashMap.)))
+
+
+
+
+(declare make-generic-wrapping-subproblem)
+
+(defrecord GenericWrappingSubproblem [super-sp root-sp key-trail ; summarizer???
+                                      kernel in-set out-set child-key-seq
+                                      ^HashMap child-cache ^HashMap refinement-cache]
+  Subproblem
+  (input-set       [s] in-set)
+  (output-set      [s] out-set)
+  (current-summary [s] ...???)
+  (child-keys      [s] child-key-seq)
+  (get-child       [s] ???)
+  (refine-input    [s refined-input-set]
+    (if (= in-set refined-input-set)
+      s
+      (util/cache-with refinement-cache refined-input-set
+                       ???))))
+
+(defn make-generic-subproblem [name super-sp root-sp key-trail summary???
+                               in-set .....])
+
+
+(defn make-refinement-kernel [actions]
+  (let [[f & r] (util/make-safe actions)
+        left-k (make-action-kernel f)]
+    (if (empty? r)
+      left-k
+      (make-seq-kernel left-k (make-refinement-kernel r)))))
 
 ;; TODO: simple generic SimpleSubproblem record ? 
 
 ;; TODO: stop early on empty sets or bad rewards, etc.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Planning Subproblems ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Planning Kernels ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (declare make-primitive-subproblem)



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; Subproblem Protocols ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;Clear how costs must go
;;How should sets go -- eager or lazy ? ? ???
;;Can forget about sets -- switch to breakout children instead.

;; Things:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Primitive ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn make-primitive-kernel [action]
  (reify SubproblemKernel
         (compute-output-set-and-reward   [sk input-set]
            (angelic/optimistic-set-and-reward action input-set))
         (compute-child-keys   [sk input-set]
            no-children)
         (compute-child-kernel [sk input-set child-key]
            (throw (UnsupportedOperationException.)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HLA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn simple-immediate-refinements-set [a input-set]
  (for [[constraint ref] (angelic/immediate-refinements-set a input-set)]
    (cons
     (env-util/make-factored-primitive [:noop] constraint {} 0)     
     ref)))

(defn make-refinement-kernel [actions]
  (let [[f & r] (util/make-safe actions)
        left-k (make-action-kernel f)]
    (if (empty? r)
      left-k
      (make-seq-kernel left-k (make-refinement-kernel r)))))

;; TODO: handle proper key matching ? 
(defn make-hla-kernel [action]
  (reify SubproblemKernel
         (compute-output-set-and-reward   [sk input-set]
            (angelic/optimistic-set-and-reward action input-set))
         (compute-child-keys   [sk input-set]
            (simple-immediate-refinements-set action input-set))
         (compute-child-kernel [sk input-set child-key]
            (make-refinement-kernel child-key))))

(defn make-action-kernel [action]
  ((if (env/primitive? action) make-primitive-kernel make-hla-kernel) action))


(comment 
  (defn make-hla-subproblem [super-hs input-set action]
    (let [[opt-set rew] (angelic/optimistic-set-and-reward action input-set)]
      (HlaSubproblem.
       super-hs input-set action opt-set ??????summarizer
       (cond (not (angelic/can-refine-from-set? action input-set))
             no-children
             (and super-hs (not (blocked??? super-hs)))
             ???                        ;reuse
             :else
             (into {}
                   (for [ref (simple-immediate-refinements-set action input-set)]
                     [(map env/action-name ref)
                      (delay (make-refinement-subproblem this??? input-set ref))
                      (ActionInstance. ai nil prev-aio full-ref (atom nil))])))
       (HashMap.)))))



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Sequence ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn make-seq-kernel [left-k right-k]
  (reify SubproblemKernel
         (compute-output-set-and-reward   [sk input-set]
            (angelic/optimistic-set-and-reward action input-set))
         (compute-child-keys   [sk input-set]
            (simple-immediate-refinements-set action input-set))
         (compute-child-kernel [sk input-set child-key]
            (make-refinement-kernel child-key))))


(comment

 ;; For now, pick the right first if possible -- fix later.
 ;; TODO: unfactor ?
 ;; TODO: how do we wrap partial SPs? 
 (defrecord SeqSubproblem [super-sp root-hs key-seq
                           input-set left-sp right-sp output-constraint
                           child-map]
   Subproblem
   (current-summary [s] ...?)
   (child-keys      [s] (keys child-map))
   (get-child       [s child-key] (force (util/safe-get child-map child-key)))
   (refine-input    [s refined-input-set]
                    (if (= refined-input-set input-set)
                      s
                      (util/cache-with refinement-map refined-input-set
                                       (make-hla-subproblem s refined-input-set action)))))


 (defn make-seq-subproblem [super-sp root-hs key-seq]))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Wrapped Seq ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
