<commit_before>(ns keechma.controller-manager
  (:require [cljs.core.async :refer [<! >! chan close! put! alts! timeout]]
            [keechma.util :refer [dissoc-in]]
            [keechma.controller :as controller :refer [SerializedController]])
  (:require-macros [cljs.core.async.macros :as m :refer [go go-loop]]))

(defn ^:private send-command-to [reporter controller command-name args] 
  (reporter :controller :in (:name controller) command-name args :info)
  (put! (:in-chan controller) [command-name args])
  controller)

(defn ^:private route-command-to-controller [reporter controllers command-name command-args]
  (let [[controller-name command-name] command-name
        controller (get controllers controller-name)]
    (if controller
      (send-command-to reporter controller command-name command-args)
      (throw (ex-info "Trying to send command to a controller that is not running" {:controller controller-name :command command-name :args command-args})))))

(defn route-change-execution-plan [route-params running-controllers controllers]
  (let [plan {:stop          {}
              :start         {}
              :wake          {}
              :route-changed []}
        running-controller-keys-set (set (keys running-controllers))]
    (reduce (fn [acc [topic controller]]
              (let [{:keys [stop start wake route-changed]} acc
                    new-params (controller/params controller route-params)
                    running-controller (get running-controllers topic)
                    prev-params (:params running-controller)]
                (cond
                  (= SerializedController (type running-controller)) (assoc acc :wake (assoc wake topic new-params))
                  (and (nil? prev-params) (nil? new-params))     acc
                  (and (nil? prev-params) (boolean new-params)) (assoc acc :start (assoc start topic new-params))
                  (and (boolean prev-params) (nil? new-params)) (assoc acc :stop (assoc stop topic new-params))
                  (not= new-params prev-params)                 (assoc acc :stop (assoc stop topic new-params) :start (assoc start topic new-params))
                  (= new-params prev-params)    (assoc acc :route-changed (conj route-changed topic))
                  :else acc))) plan controllers)))

(defn apply-stop-controllers [app-db reporter stop]
  (let [running-controllers (get-in app-db [:internal :running-controllers])]
    (loop [stop stop
           app-db app-db]
      (if-let [s (first stop)]
        (let [[topic params] s
              controller (get running-controllers topic)
              new-app-db (-> (controller/stop controller (:params controller) app-db)
                             (dissoc-in [:internal :running-controllers topic]))]
          (reporter :app :out :controller [topic :stop] nil :info)
          (close! (:in-chan controller))
          (recur (rest stop) new-app-db))
        app-db))))

(defn apply-start-or-wake-controllers [action app-db reporter controllers commands-chan get-running start-or-wake]
  (loop [start-or-wake start-or-wake
         app-db app-db]
      (if-let [s (first start-or-wake)]
        (let [[topic params] s
              controller (assoc (get controllers topic)
                                :in-chan (chan)
                                :out-chan commands-chan
                                :params params
                                :route-params (:route app-db)
                                :name topic
                                :reporter reporter
                                :running (partial get-running topic))
              new-app-db (-> (action controller params app-db)
                             (assoc-in [:internal :running-controllers topic] controller))]
          (reporter :app :out :controller [topic :start-or-wake] params :info)
          (recur (rest start-or-wake) new-app-db))
        app-db)))

(def apply-start-controllers (partial apply-start-or-wake-controllers controller/start))
(def apply-wake-controllers (partial apply-start-or-wake-controllers controller/wake))

(defn call-handler-on-started-controllers [app-db-atom reporter start]
  (doseq [[topic _] start]
    (let [controller (get-in @app-db-atom [:internal :running-controllers topic])]
      (reporter :app :out :controller [topic :handler] nil :info)
      (controller/handler controller app-db-atom (:in-chan controller) (:out-chan controller)))))

(defn send-route-changed-to-surviving-controllers [app-db-atom reporter route-changed route-params]
  (doseq [topic route-changed]
    (let [controller (get-in @app-db-atom [:internal :running-controllers topic])]
      (send-command-to reporter controller :route-changed route-params))))

(defn apply-route-change [reporter route-params app-db-atom commands-chan controllers]
  (let [app-db @app-db-atom
        execution-plan (route-change-execution-plan route-params (get-in app-db [:internal :running-controllers]) controllers)
        {:keys [stop start wake route-changed]} execution-plan
        get-running (fn [topic] (get-in @app-db-atom [:internal :running-controllers topic]))]
    (reset! app-db-atom
            (-> (assoc app-db :route route-params)
                (apply-stop-controllers reporter stop)
                (apply-start-controllers reporter controllers commands-chan get-running start)
                (apply-wake-controllers reporter controllers commands-chan get-running wake)))
    (call-handler-on-started-controllers app-db-atom reporter (concat start wake))
    (send-route-changed-to-surviving-controllers app-db-atom reporter route-changed route-params)))

(defn call-ssr-handler-on-started-controllers [app-db-atom reporter start ssr-handler-done-cb]
  (let [wait-chan (chan)
        wait-count (loop [wait-count 0
                          start start]
                     (if-let [s (first start)]<commit_msg>Report some more events from app state<commit_after>(ns keechma.controller-manager
  (:require [cljs.core.async :refer [<! >! chan close! put! alts! timeout]]
            [keechma.util :refer [dissoc-in]]
            [keechma.controller :as controller :refer [SerializedController]])
  (:require-macros [cljs.core.async.macros :as m :refer [go go-loop]]))

(defn ^:private send-command-to [reporter controller command-name args] 
  (reporter :controller :in (:name controller) command-name args :info)
  (put! (:in-chan controller) [command-name args])
  controller)

(defn ^:private route-command-to-controller [reporter controllers command-name command-args]
  (let [[controller-name command-name] command-name
        controller (get controllers controller-name)]
    (if controller
      (send-command-to reporter controller command-name command-args)
      (throw (ex-info "Trying to send command to a controller that is not running" {:controller controller-name :command command-name :args command-args})))))

(defn report-running-controllers [app-db-atom]
  (let [running-controllers (get-in @app-db-atom [:internal :running-controllers])]
    (reduce (fn [acc [k v]] (assoc acc k (:params v))) {} running-controllers)))

(defn route-change-execution-plan [route-params running-controllers controllers]
  (let [plan {:stop          {}
              :start         {}
              :wake          {}
              :route-changed []}
        running-controller-keys-set (set (keys running-controllers))]
    (reduce (fn [acc [topic controller]]
              (let [{:keys [stop start wake route-changed]} acc
                    new-params (controller/params controller route-params)
                    running-controller (get running-controllers topic)
                    prev-params (:params running-controller)]
                (cond
                  (= SerializedController (type running-controller)) (assoc acc :wake (assoc wake topic new-params))
                  (and (nil? prev-params) (nil? new-params))     acc
                  (and (nil? prev-params) (boolean new-params)) (assoc acc :start (assoc start topic new-params))
                  (and (boolean prev-params) (nil? new-params)) (assoc acc :stop (assoc stop topic new-params))
                  (not= new-params prev-params)                 (assoc acc :stop (assoc stop topic new-params) :start (assoc start topic new-params))
                  (= new-params prev-params)    (assoc acc :route-changed (conj route-changed topic))
                  :else acc))) plan controllers)))

(defn apply-stop-controllers [app-db reporter stop]
  (let [running-controllers (get-in app-db [:internal :running-controllers])]
    (loop [stop stop
           app-db app-db]
      (if-let [s (first stop)]
        (let [[topic params] s
              controller (get running-controllers topic)
              new-app-db (-> (controller/stop controller (:params controller) app-db)
                             (dissoc-in [:internal :running-controllers topic]))]
          (reporter :app :out :controller [topic :stop] nil :info)
          (close! (:in-chan controller))
          (recur (rest stop) new-app-db))
        app-db))))

(defn apply-start-or-wake-controllers
  [action reporter-action app-db reporter controllers commands-chan get-running start-or-wake]
  (loop [start-or-wake start-or-wake
         app-db app-db]
      (if-let [s (first start-or-wake)]
        (let [[topic params] s
              controller (assoc (get controllers topic)
                                :in-chan (chan)
                                :out-chan commands-chan
                                :params params
                                :route-params (:route app-db)
                                :name topic
                                :reporter reporter
                                :running (partial get-running topic))
              new-app-db (-> (action controller params app-db)
                             (assoc-in [:internal :running-controllers topic] controller))]
          (reporter :app :out :controller [topic reporter-action] params :info)
          (recur (rest start-or-wake) new-app-db))
        app-db)))

(def apply-start-controllers (partial apply-start-or-wake-controllers controller/start :start))
(def apply-wake-controllers (partial apply-start-or-wake-controllers controller/wake :wake))

(defn call-handler-on-started-controllers [app-db-atom reporter start]
  (doseq [[topic _] start]
    (let [controller (get-in @app-db-atom [:internal :running-controllers topic])]
      (reporter :app :out :controller [topic :handler] nil :info)
      (controller/handler controller app-db-atom (:in-chan controller) (:out-chan controller)))))

(defn send-route-changed-to-surviving-controllers [app-db-atom reporter route-changed route-params]
  (doseq [topic route-changed]
    (let [controller (get-in @app-db-atom [:internal :running-controllers topic])]
      (send-command-to reporter controller :route-changed route-params))))

(defn apply-route-change [reporter route-params app-db-atom commands-chan controllers]
  (reporter :router :out nil :route-changed route-params :info)
  (let [app-db @app-db-atom
        execution-plan (route-change-execution-plan route-params (get-in app-db [:internal :running-controllers]) controllers)
        {:keys [stop start wake route-changed]} execution-plan
        get-running (fn [topic] (get-in @app-db-atom [:internal :running-controllers topic]))]
    (reset! app-db-atom
            (-> (assoc app-db :route route-params)
                (apply-stop-controllers reporter stop)
                (apply-start-controllers reporter controllers commands-chan get-running start)
                (apply-wake-controllers reporter controllers commands-chan get-running wake)))
    (call-handler-on-started-controllers app-db-atom reporter (concat start wake))
    (send-route-changed-to-surviving-controllers app-db-atom reporter route-changed route-params))
  (reporter :app :in nil :running-controllers (report-running-controllers app-db-atom) :info))

(defn call-ssr-handler-on-started-controllers [app-db-atom reporter start ssr-handler-done-cb]
  (let [wait-chan (chan)
        wait-count (loop [wait-count 0
                          start start]
                     (if-let [s (first start)]
{'fraction_non_alphanumeric': 0.12181164159581426, 'fraction_numerical': 0.00016350555918901244, 'mean_word_length': 2.418949133594187, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '110945', 'n_tokens_mistral': 3481, 'n_tokens_neox': 3403, 'n_words': 959}