 (ns aurora.language
   (:require [aurora.btree :as btree])
-  (:require-macros [aurora.macros :refer [apush aclear set!!]]))
+  (:require-macros [aurora.macros :refer [apush aclear amake set!!]]))
 
 ;; KNOWLEDGE
 

            (swap! rule->flow assoc agg-rule-id (AggregateFlow. index group-len limit-ix ascending? agg-ixes agg-funs sinks))
            (swap! kind->name->rules update-in ["know" (str "delta-" agg-index-id)] conj agg-rule-id)))))

    ;; rewrite (foo x y) (bar y z) to (delta-foo x y) (bar y z) + (foo x y) (delta-bar y z) + (delta-foo x y) (delta-bar y z)
    (doseq [[rule-id clauses] @rule-id->clauses]

      ;; remove current rule
      (swap! rule-id->clauses dissoc rule-id)

      ;; add derivative rules
      (let [db-clauses (for [[_ clause-type clause-id name] clauses
                             :when (and (= clause-type "when")
                                        (not (#{"=constant" "=variable" "=function" "filter" "interval"} name)))]
                         [rule-id clause-type clause-id name])
            other-clauses (for [[_ clause-type clause-id name] clauses
                                :when (or (not= clause-type "when")
                                          (#{"=constant" "=variable" "=function" "filter" "interval"} name))]
                            [rule-id clause-type clause-id name])
            num-db-clauses (count db-clauses)
            num-derivatives (js/Math.pow 2 num-db-clauses)]
        (dotimes [derivative num-derivatives]
          (when (> derivative 0) ;; skip the case where no deltas are present
            (let [derivative-rule-id (str rule-id "-deriv-" derivative)]
              (swap! rule-id->clauses assoc derivative-rule-id #{})
              (doseq [[clause [_ clause-type clause-id name]] (map vector (range) db-clauses)]
                ;; TODO do we need to keep the clause-ids unique?
                (swap! rule-id->clauses update-in [derivative-rule-id] conj
                       (if (= 1 (mod (bit-shift-right derivative clause) 2))
                         [derivative-rule-id clause-type clause-id (str "delta-" name)]
                         [derivative-rule-id clause-type clause-id name])))
              (doseq [[_ clause-type clause-id name] other-clauses]
                (swap! rule-id->clauses update-in [derivative-rule-id] conj
                       (if (= clause-type "know")
                         [derivative-rule-id clause-type clause-id (str "delta-" name)]
                         [derivative-rule-id clause-type clause-id name]))))))))

    (doseq [[rule-id clauses] @rule-id->clauses]
      (let [var->when-count (atom {})]


           (dotimes [j (alength dirtied-rules)]
             (aset rule->dirty? (aget dirtied-rules j) true))))))

(deftype SolverFlow [solvers sinks]
  Object
  (run [this kn rule->dirty? kind->name->rules]
       (let [facts&vals #js []]
         (dotimes [i (alength solvers)]
           (let [solver (aget solvers i)]
             (.reset solver)
             (js/Array.prototype.push.apply facts&vals (.elems solver))))
         (dotimes [i (alength sinks)]
           (.run (aget sinks i) kn rule->dirty? kind->name->rules facts&vals)))))

