(ns buddho.core.dhamma.occur
  "Implementation of dhamma occurence mechanism."
  (:require [buddho.core.state :as s :refer [value]]
            [buddho.core.dhamma.aspects :refer [pop-asp-stage]]
            [buddho.core.dhamma.data :refer [make-dhamma]]))

(defmulti impl!
  "Execute `dhamma`'s action in the context of `_parent`.
  Returns (potentially modified) `_parent`.
  Exists only as a component of [[occur!]]; implement but do not call this!"
  (fn [dhamma & [_parent]] (:name (value dhamma))))

;; XXX should this be an error?
(defmethod impl! :default [_dhamma & [parent]]
  (println "default occur")
  parent)

(def root-dhamma (make-dhamma :root))

(defn occur!
  "Execute `dhamma` in the context of `parent`, applying aspects to `dhamma` according to its :asp-props.
  Returns (potentially modified) `parent`."
  [dhamma & [parent]]
  (loop [dh (value dhamma)
         parent (or parent root-dhamma)]
    (let [cur (first (:asp-props dh))
          [aspects dh] (pop-asp-stage dh)
          ;; Execute aspects, potentially modifying dh
          dh (reduce #(occur! %2 %1) dh aspects)
          ;; If it's time for `dhamma`'s implementation to run, do so,
          ;; potentially modifying `parent`.
          parent (if (= cur [:dhamma (:name dh)])
                   (impl! dh parent)
                   parent)]

      ;; Recur if there's remaining aspects, otherwise return `parent`.
      (if (not-empty (:asp-props dh))
        (recur dh parent)
        parent))))
