 
 (defn- handle-connection
   [conn]
-  (let [reader (BufferedReader. (InputStreamReader. (.getInputStream conn)))]
-    (if-let [message (read-request reader)]
+  (let [rdr (BufferedReader. (InputStreamReader. (.getInputStream conn)))]
+    (if-let [message (read-request rdr)]
       (do (when (not= message "ready")
-            (return message))
-          (swap! server-state (fn [old] (assoc old :connection conn)))))))
+            (return-value message))
+          (set-connection conn)))))
 
 (defn- server-loop
   [server-socket]

    "Content-Length: 27"
    "Content-Type: application/x-www-form-urlencoded"])
)

(defn parse-headers [header-lines]
  (apply hash-map
   (mapcat
    (fn [line]
      (let [[k v] (str/split line #":" 2)]
        [(keyword (str/lower-case k)) (str/triml v)]))
    header-lines)))

;;; assumes first line already consumed
(defn read-headers [rdr]

;   You must not remove this notice, or any other, from this software.

(ns cljs.browser-repl
  (:require [clojure.string :as str]
            [cljs.compiler :as comp])
  (:import java.io.BufferedReader
           java.io.BufferedWriter
           java.io.InputStreamReader
           java.io.OutputStreamWriter
           java.net.Socket
           java.net.ServerSocket))

;; The main purpose of this namespace is to implement the server side
;; of the browser-connected repl. This server will push data to the
;; browser to be evaluated and receive return values. Server push is
;; implemented through long polling. Requests sent from the browser
;; are expected to be HTTP Post requests.

(defonce server-state (atom {:socket nil
                             :connection nil
                             :promised-conn nil
                             :return-value-fn nil}))

(defn connection
  "Promise to return a connection when one is available. If a
  connection is not available, store the promise in server-state."
  []
  (let [p (promise)
        conn (:connection @server-state)]
    (if (and conn (not (.isClosed conn)))
      (do (deliver p conn)
          p)
      (do (swap! server-state (fn [old] (assoc old :promised-conn p)))
          p))))

(defn set-connection
  "Given a new available connection, either use it to deliver the
  connection which was promised or store the connection for later
  use."
  [conn]
  (if-let [promised-conn (:promised-conn @server-state)]
    (do (swap! server-state (fn [old] (-> old
                                         (assoc :connection nil)
                                         (assoc :promised-conn nil))))
        (deliver promised-conn conn))
    (swap! server-state (fn [old] (assoc old :connection conn)))))

(defn set-return-value-fn
  "Save the return value function which will be called when the next
  return value is received."
  [f]
  (swap! server-state (fn [old] (assoc old :return-value-fn f))))

(defn send-and-close
  "Use the passed connection to send a form to the browser."
  [conn form]
  (with-open [writer (BufferedWriter.
                      (OutputStreamWriter. (.getOutputStream conn)))]
    (do (.write writer form)
        (.write writer "\r\n") ;; remove this
        (.flush writer)
        (.close conn))))

(defn send-for-eval
  "Given a form and a return value function, send the form to the
  browser for evaluation. The return value function will be called
  when the return value is received."
  [form return-value-fn]
  (do (set-return-value-fn return-value-fn)
      (send-and-close @(connection) form)))

(defn return-value
  "Called by the server when a return value is received."
  [val]
  (when-let [f (:return-value-fn @server-state)]
    (f val)))

(defn parse-headers
  "Parse the headers of an HTTP POST request."
  [header-lines]
  (apply hash-map
   (mapcat
    (fn [line]
      (let [[k v] (str/split line #":" 2)]
        [(keyword (str/lower-case k)) (str/triml v)]))
    header-lines)))

(comment

