             [clj-wamp.server :as wamp]
             [clojure.string :refer (split)]
             [cheshire.core :as json]
-            [taoensso.timbre :as timbre])
+            [taoensso.timbre :as timbre]
+            [clojure.core.cache :as cache])
   (:import [java.net InetAddress URI]
            [java.util UUID]))
 (timbre/refer-timbre)


;;; Source implementation.

;; topics = (ref #{"topic"})
;; cache = (atom {"topic" (msg-3 msg-2 msg-1)})
;; open = (atom boolean)
;; config = {:cache-size long, :clean-cache-on-done boolean, :clean-summary-on-done boolean}
;; summaries (atom {"topic", summary})
(defrecord WebsocketSource [dirwriter stop-fn open topics cache uri config summary-fn summaries]
  Source
  (publish [this topic message]
    (let [uuid (UUID/randomUUID)]
      (debug "Requested to publishing message" uuid "on" topic)
      (trace "Message" uuid "-" message)
      (when @open
        (when (dosync
                (when-not (get @topics topic)
                  (alter topics conj topic)))
          (when @open
            (api/add-source dirwriter topic uri)
            (debug "Registered" uri "for topic" topic "in directory service.")))
        (wamp/send-event! topic message)
        (let [new-cache (swap! cache update-in [topic]
                               (fn [c] (take (config :cache-size) (conj c message))))]
          (debug "Message " uuid "published and cached.")
          (trace "Cache for" topic "after message" uuid "is:" (get new-cache topic)))
        (when summary-fn
          (let [new-summaries (swap! summaries update-in [topic] summary-fn message)]
            (debug "Summary for" topic "updated with message" uuid)
            (trace "Summary for" topic "after message" uuid "is:" (get new-summaries topic)))))))

  (done [this topic]
    (debug "Initiated 'done' for" topic)
    (when @open
      (when (dosync (when (get @topics topic)
                      (alter topics disj topic)))
        (when @open
          (when-let [done-payload (:done-payload config)]
            (debug "Sending done payload to" topic)
            (wamp/send-event! topic done-payload))
          (api/remove-source dirwriter topic uri)
          (debug "Unregistered" uri "for topic" topic "in directory service."))
        (when (:clean-cache-on-done config)
          (swap! cache dissoc topic)
          (debug "Cleaned cache for" topic))
        (when (and summary-fn (:clean-summary-on-done config))
          (swap! summaries dissoc topic)
          (debug "Cleaned summary for" topic))))))


(defn start-source

  (info "Starting websocket source with directory writer" directory-writer "and config" config)
  (let [uri (or uri (URI. (str "ws://" (. (InetAddress/getLocalHost) getHostName) ":" port)))
        stop-fn (atom nil)
        config (assoc config :cache-size cache-size :uri uri)
        summaries (when summary-fn
                    (if (< 0 summary-ttl)
                      (cache/ttl-cache-factory {} :ttl summary-ttl)
                      {}))
        source (WebsocketSource. directory-writer stop-fn (atom true) (ref {}) config
                                 (atom summaries))
        app (make-app source)
        wrapped-app (if wrap-fn (wrap-fn app) app)]
    (reset! stop-fn (http/run-server wrapped-app {:port port}))
