            (java.nio.channels FileChannel$MapMode))
   (:require [org.micromanager.mm :as mm])
   (:use [org.micromanager.mm :only (core)]))
+
+(defn stop []
+  (core stopSequenceAcquisition))
+
+(defn status []
+  {:running (core isSequenceRunning)
+   :remaining-images (core getRemainingImageCount)
+   :overflow (core isBufferOverflowed)
+   :exposure (core getExposure)
+   :camera (core getCameraDevice)
+   :width (core getImageWidth)
+   :height (core getImageHeight)
+   :bytes-per-pixel (core getBytesPerPixel)
+   :image-size (core getImageBufferSize)
+   :roi (mm/get-camera-roi)})
+
+;; bucket brigade
+
+(defn bucket-node [input-queue function output-queue]
+  (future
+    (loop []
+      (let [item (.take input-queue)]
+        (if (= item input-queue)
+          (.put output-queue output-queue)
+          (do (.put output-queue (function item))
+              (recur)))))))
+
+(defn first-node [n function output-queue]
+  (future
+    (dotimes [i n]
+      (.put output-queue (function)))
+    (.put output-queue output-queue)))
+
+(defn last-node [input-queue function]
+  (loop []
+    (let [item (.take input-queue)]
+      (when (not= item input-queue)
+        (function item)
+        (recur)))))
+        
+
+(defn bucket-brigade [n & functions]
+  (let [first-queue (LinkedBlockingQueue.)
+        first-node (first-node n (first functions) first-queue)]
+    (loop [remaining-functions (rest functions) input-queue first-queue]
+      (let [f (first remaining-functions)]
+        (if-let [n (next remaining-functions)]
+          (let [output-queue (LinkedBlockingQueue.)]
+            (bucket-node input-queue f output-queue)
+            (recur n output-queue))
+          (last-node input-queue f))))))
 
 (defn queuify
   "Runs zero-arg function n times on another thread. Returns

(def corePop-memo (memoize #(core popNextImage)))

(defn acquire-and-write-to-disk [num-images]
  (let [filename (str "D:/AcquisitionData/deleteMe" (rand-int 100000) ".dat")]
    (println "\nto disk:" filename)
    (with-open [file (RandomAccessFile. filename "rw")]
               (time (let [channel (.getChannel file)
                           image-queue (queuify num-images 5 #(core getImage))
                           filled-buffer-queue (queuify num-images 5 #(image-to-byte-buffer
                                                                        (.take image-queue)))
                           ]
                       ;(println image-queue empty-buffer-queue filled-buffer-queue)
                       (dotimes [_ num-images]
                         (write-buf channel (.take filled-buffer-queue))))))))


(defn write-test [num-images]
  (let [filename (str "D:/AcquisitionData/deleteMe" (rand-int 100000) ".dat")
        buf (image-to-byte-buffer (core getImage) (byte-buffer (* 2 n)))]
    (println "\nparallel:" filename)
    (with-open [file (RandomAccessFile. filename "rw")]
               (time (let [channel (.getChannel file)]
                       (dotimes [_ num-images]
                         (write-buf channel buf)))))))

(defn acquire-and-write-parallel [num-images]
  (let [filename (str "D:/AcquisitionData/deleteMe" (rand-int 100000) ".dat")]
    (println "\nparallel:" filename)
    (with-open [file (RandomAccessFile. filename "rw")]
               (time (let [channel (.getChannel file)
                           n (count (core getImage))
                           image-queue (queuify num-images 5 #(core getImage))
                           empty-buffer-queue (queuify 10 10 #(byte-buffer (* 2 n)))
                           filled-buffer-queue (queuify num-images 5 #(image-to-byte-buffer
                                                                        (.take image-queue)
                                                                        (.take empty-buffer-queue)))
                           ]
                       ;(println image-queue empty-buffer-queue filled-buffer-queue)
                       (dotimes [_ num-images]
                         (let [buf (.take filled-buffer-queue)]
                           (write-buf channel buf)
                           (.offer empty-buffer-queue buf))))))))
        
  

;; other tests

(defn monitor-circular-buffer []
  (while (not (core isSequenceRunning))
    (Thread/sleep 100))
  (while (core isSequenceRunning)
    (println (core getRemainingImageCount))
    (Thread/sleep 1000)))

(defn drain-queue [blocking-queue]
  (future (loop [i 0]

  ([pix]
    (if (instance? ByteBuffer pix)
      pix
      (pixels-to-byte-buffer pix (byte-buffer (* 2 (count pix)))))))


;; writing to disk
