   (for [xi (tails x)]
     [(first xi) (second xi)]))
 
-(defn make-cs-loop [settings]
-  (if (settings :slices-first)
-    (for [channel (settings :channels) slice (settings :slices)]
-      {:channel channel :slice slice})
-    (for [slice (settings :slices) channel (settings :channels)]
-      {:channel channel :slice slice})))
+(defn nest-loop [events dim-vals dim]
+  (if dim-vals
+    (for [dim-val dim-vals event events]
+      (assoc event dim dim-val))
+    events))
 
-(defn make-fp-loop [cs-events settings]
-  (if (settings :time-first)
-    (for [position (settings :positions)
-          frame (settings :frames)
-          event cs-events]
-       (assoc event :position position :frame frame))
-    (for [frame (settings :frames)
-          position (settings :positions)
-          event cs-events]
-       (assoc event :position position :frame frame))))
+(defn make-dimensions []
+  (let [{:keys [slices channels frames positions
+                slices-first time-first]} settings
+        a [[slices :slice] [channels :channel]]
+        a (if slices-first a (reverse a))
+        b [[frames :frame] [positions :position]]
+        b (if time-first b (reverse b))]
+    (concat a b)))
 
-(defn make-main-loops [settings]
-  (-> (make-cs-loop settings) (make-fp-loop settings)))
+(defn create-loops [dimensions]
+  (reduce #(apply (partial nest-loop %1) %2) [{:task :snap}] dimensions))
 
-(defn manage-shutter [events settings]
+(defn make-main-loops []
+  (create-loops (make-dimensions)))
+
+(defn manage-shutter [events]
   (for [[e1 e2] (pairs events)]
     (assoc e1 :close-shutter
       (if e2 (or
-        (and
-          (not (settings :keep-shutter-open-channels))
-          (not= (e1 :channel) (e2 :channel)))
-        (and
-          (not (settings :keep-shutter-open-slices))
-          (not= (e1 :slice) (e2 :slice)))
-        (not= (e1 :frame) (e2 :frame))
-        (not= (e1 :position) (e2 :position)))
+               (and
+                 (not (settings :keep-shutter-open-channels))
+                 (not= (e1 :channel) (e2 :channel)))
+               (and
+                 (not (settings :keep-shutter-open-slices))
+                 (not= (e1 :slice) (e2 :slice)))
+               (not= (e1 :frame) (e2 :frame))
+               (not= (e1 :position) (e2 :position)))
         true))))
 
-(defn process-skip-z-stack [events settings]
+(defn process-skip-z-stack [events]
   (let [slices (settings :slices)
         middle-slice (nth slices (int (/ (count slices) 2)))]
     (filter
       #(or
-        (-> % :channel :z-stack)
-        (= middle-slice (% :slice)))
+         (nil? (% :channel))
+         (-> % :channel :use-z-stack)
+         (= middle-slice (% :slice)))
       events)))
 
-(defn process-channel-skip-frames [events settings]
+(defn process-channel-skip-frames [events]
   (filter
     #(or
+       (nil? (% :channel))
        (-> % :channel :skip-frames zero?)
        (not= 0 (mod (% :frame) (-> % :channel :skip-frames inc))))
     events))
 
-(defn compute-use-autofocus [event settings]
-  (assoc event :autofocus
-    (and (settings :use-autofocus)
-      (zero? (mod (event :frame) (inc (settings :autofocus-skip)))))))
+(defn process-use-autofocus [events]
+  (for [event events]
+    (assoc event :autofocus
+      (and (settings :use-autofocus)
+        (or
+          (nil? (event :frame))
+          (zero? (mod (event :frame) (inc (settings :autofocus-skip)))))))))
 
-(defn compute-wait-time [events settings]
+(defn process-wait-time [events]
   (cons
     (assoc (first events) :wait-time-ms 0)
     (for [[e1 e2] (pairs events) :when e2]


; Testing:

(def my-channels
  [(struct channel "Cy3" 100 0 true 0)
   (struct channel "Cy5"  50 0 false 0)
   (struct channel "DAPI" 50 0 true 0)])

(def test-settings
  (struct-map acq-settings
    :frames (range 100) :positions [{:name "a" :x 1 :y 2} {:name "b" :x 4 :y 5}]
    :channels my-channels :slices (range 5)
    :interval 5 :slices-first false
    :keep-shutter-open-slices false :keep-shutter-open-channels true
    :use-autofocus true :autofocus-skip 3 :relative-slices true :exposure 100
    :interval-ms 1000))

(def test-output (->  (make-main-loops test-acq)
                      (process-skip-z-stack test-acq)
                      (manage-shutter test-acq)
                      (process-use-autofocus test-acq)))

(ns sequence-generator
 ;(:require )
 ;(:use )
 ;(:import )
 [:gen-class]
 )

(defstruct channel :name :exposure :z-offset :use-z-stack :skip-frames)

(def my-channels
  [(struct channel "Cy3" 100 0 true 0)
   (struct channel "Cy5"  50 0 false 0)
   (struct channel "DAPI" 50 0 true 0)])

(defstruct acq-settings :frames :positions :channels :slices :slices-first
  :time-first :keep-shutter-open-slices :keep-shutter-open-channels
  :use-autofocus :autofocus-skip :relative-slices :exposure)

(def default-settings
  (struct-map acq-settings
    :frames (range 100) :positions [{:name "a" :x 1 :y 2} {:name "b" :x 4 :y 5}]
    :channels my-channels :slices (range 5)
    :interval 5 :slices-first true :time-first true
    :keep-shutter-open-slices false :keep-shutter-open-channels true
    :use-autofocus true :autofocus-skip 3 :relative-slices true :exposure 100
    :interval-ms 1000))

(def settings default-settings)

(defn tails [x]
  (loop [xi x tails []]
