   (^:private modified? [_] "Check if session is modified"))
 
 (defprotocol ISessionStorage
-  (^:private load-data [_ key] "")
-  (^:private persist-data [_ key data] ""))
+  (^:private read-session [_ key] "")
+  (^:private write-session [_ key data] "")
+  (^:private delete-session [_ key] ""))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Types

(defn- context->session
  [context {:keys [storage cookie-name]
            :or {cookie-name default-cookie-name}}]
  (let [cookies (ct/get-cookies context)
        cookie (get cookies (keyword cookie-name) nil)
        sid (:value cookie)]
    (if sid
      (let [data (load-data storage sid)]
        [sid (session sid data)])
      (let [sid (codecs/bytes->safebase64 (nonce/random-nonce 48))]
        [sid (session sid)]))))

(defn- patch-vary-headers
  [response])


(defn session-handler
  [{:keys [storage cookie-name]
    :or {storage :inmemory cookie-name default-cookie-name}
    :as options}]
  (let [storage (lookup-storage storage)
        options (assoc options :storage storage)]
    (fn [context]
      (let [[sid session] (context->session context options)]
        (ct/before-send context (fn [^ResponseMetaData response]
                                  (cond
                                    (empty? session)
                                    (let [cookie (-> (make-cookie sid options)
                                                     (assoc :max-age 0))]
                                      (ct/set-cookies! context {cookie-name cookie}))

                                    (modified? session)
                                    (let [cookie (make-cookie sid options)]
                                      (persist-data storage sid @session)
                                      (patch-vary-headers response)
                                      (ct/set-cookies! context {cookie-name cookie}))

                                    (accessed? session)
                                    (patch-vary-headers response))))
        (ct/delegate context {:session session})))))


(alter-meta! #'->Session assoc :private true)

(defn- ->session
  "A session object constructor."
  ([sessionid] (->session sessionid {}))
  ([sessionid data]
   (Session. (atom data)
             sessionid
             (atomic/boolean false)
             (atomic/boolean false))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Storages
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn memory-storage
  "In memmory session storage constructor."
  []
  (let [internalstore (atom {})]
    (reify ISessionStorage
      (read-session [_ key]
        (let [key (keyword key)]
          (get @internalstore key nil)))
      (write-session [_ key data]
        (let [key (keyword key)]
          (swap! internalstore assoc key data)))
      (delete-session [_ key]
        (let [key (keyword key)]
          (swap! internalstore dissoc key))))))

(defn lookup-storage
  "A helper for create session storages with
  helpfull shortcuts."
  {:no-doc true}
  [storage]
  (case storage
    :inmemory (memory-storage)
