(ns swank.util.io
  (:use [swank util]
        [swank.util.concurrent thread])
  (:import [java.io StringWriter Reader PrintWriter]))

(defn read-chars
  ([rdr n] (read-chars rdr n false))
  ([#^Reader rdr n throw-exception]
     (let [cbuf (make-array Character/TYPE n)]
       (loop [i 0]
	 (let [size (.read rdr cbuf i (- n i))]
	   (cond
	    (neg? size) (if throw-exception
			  (throw throw-exception)
			  (String. cbuf 0 i))
	    (= (+ i size) n) (String. cbuf)
	    :else (recur (+ i size))))))))

(defn call-on-flush-stream
  "Creates a stream that will call a given function when flushed."
  ([flushf]
     (let [closed? (atom false)
           #^PrintWriter stream
           (PrintWriter.
            (proxy [StringWriter] []
              (close [] (reset! closed? true))
              (flush []
                     (let [#^StringWriter me this
                           len (.. me getBuffer length)]
                       (when (> len 0)
                         (flushf (.. me getBuffer (substring 0 len)))
                         (.. me getBuffer (delete 0 len)))))))]
       (dothread
        (thread-set-name "Call-on-write Stream")
        (continuously
         (Thread/sleep 200)
         (when-not @closed?
           (.flush stream))))
       stream))
  {:tag PrintWriter})