(ns emptyhead.thought.define
  "Utilities for defining new thoughts."
  (:require [emptyhead.thought.crud :as thought]
            [emptyhead.thought.eval :as eval]
            [emptyhead.idea.crud :as idea]
            [emptyhead.util.magic :as magic]
            [emptyhead.idea.memtag :as memtag]
            [emptyhead.idea.protocol :as prtc]))

(defn register-implementation!
  [operator impl]
  (let [impl-prop (magic/thought-impl-prop operator)]
    (idea/have-idea! :prefix (str "impl_thought#" (magic/symbolize-ns operator))
                     :properties [impl-prop]
                     :shadowing [impl-prop]
                     :data {:implementation impl})))

(defn register-constructor!
  [operator & {:keys [constr-fn defaults]
               :or {constr-fn (fn [thought parent] {})
                    defaults {}}}]
  (let [constr-op (conj operator :construct)]
    (register-implementation!
     constr-op
     (fn [thought & [parent]]
       (let [thought (prtc/value thought)
             parent (prtc/value parent)]
         [parent
          (memtag/uid-of
           (thought/register-thought!
            operator
            (merge defaults
                   (thought/make-thought operator)
                   {:data (thought/data thought)}
                    (constr-fn thought parent)
                   )))])))))

(defn define!
  [operator impl & {:keys [constr-fn defaults]
                    :as constr-args}]
  (register-implementation! operator impl)
  (register-constructor! operator constr-args) )
