 (defn writer
   [f refs]
   (->BAIWriter (DataOutputStream. (FileOutputStream. (file f)))
-               (writer-status refs)
+               refs
                f))
 
 (defn write-index
   [^BAIWriter wtr alns]
   (try
     (let [w (.writer wtr)
-          s (.status wtr)]
+          refs (.refs wtr)]
       ;; magic
       (lsb/write-bytes w (.getBytes bai-magic))
       ;; n_ref
-      (lsb/write-int w (count (:refs s)))
-      ;; TODO this is new implementation
-      (pprint (make-index (:refs s) alns))
-      (doseq [aln alns] (write-index* w s aln))
-      ;; Write data about last ref
-      (write-ref! w s)
-      (write-no-coordinate-alns-count w @(:meta s)))
+      (lsb/write-int w (count refs))
+      (let [indices (make-index refs alns)]
+        (doseq [ref refs]
+          (let [index (get indices (:name ref))]
+            ;; bins
+            (if (zero? (count (:bins index)))
+              (lsb/write-int w 0)
+              (do
+                (let [bins (filter #(not (nil? %)) (:bins index))]
+                  ;; # of bins
+                  (lsb/write-int w (inc (count bins)))
+                  (doseq [bin bins]
+                    (write-bin w bin))
+                  ;; meta data
+                  (write-meta-data w (:meta index)))))
+            ;; linear index
+            (lsb/write-int w (count (:lidx index)))
+            (doseq [l (:lidx index)]
+              (lsb/write-long w l))))
+        ;; no coordinate alignments
+        (lsb/write-long w (:no-coordinate-alns indices))))
     (catch Exception e (do
                          (let [f (file (.f wtr))]
                            (when (.exists f)

  (+ (nth level-starts  (dec (count level-starts)))
     (bit-shift-right seq-len 14)))

(def max-lidx-size (- (inc max-bins) (last level-starts)))

;;
;; BAIWriterStatus
;;

(defrecord BAIWriterStatus
    [valid refs ref-name max-idx idx bins bins-seen lidx largest-lidx-seen meta])

(defn- current-ref
  [^BAIWriterStatus s]
  (nth (:refs s) @(:idx s)))

(defn- bin-count
  [refs idx]
  (-> (nth refs idx)
      :len
      max-bin-num
      inc))

(defn- has-next?
  [s]
  (> (:max-idx s) @(:idx s)))

(defn- writer-status
  [refs]
  (BAIWriterStatus. (atom true)
                    refs
                    (atom (:name (first refs)))
                    (dec (count refs))
                    (atom 0)
                    (atom (gen-vec (bin-count refs 0)))
                    (atom 0)
                    (atom (gen-vec max-lidx-size 0))
                    (atom -1)
                    (atom {:first-offset -1
                           :last-offset 0
                           :aligned-alns 0
                           :unaligned-alns 0
                           :no-coordinate-alns 0})))
;;
;; BAIWriter
;;

(deftype BAIWriter [writer status f]
  java.io.Closeable
  (close [this]
    (.. this writer close)))

  (lsb/write-long w (:aligned-alns meta-data))
  (lsb/write-long w (:unaligned-alns meta-data)))

;;
;; index
;;

(defn- make-index!
  [refs alns]
  (let [indices (atom {})
        ref-name (atom nil)
        bins (atom nil)
        bins-seen (atom 0)
        lidx (atom (gen-vec max-lidx-size 0))
        largest-lidx-seen (atom -1)
        meta (atom {:first-offset -1
                    :last-offset 0
                    :aligned-alns 0
                    :unaligned-alns 0})
        no-coordinate-alns (atom 0)]
    ;; meta data
    (doseq [aln alns]
      (when (nil? @ref-name)
        (reset! ref-name (:rname aln))
        (reset! bins (gen-vec (bin-count refs (:rname aln)))))
      (when-not (= (:rname aln) @ref-name)
        (swap! indices assoc @ref-name {:meta @meta
                                        :bins @bins
                                        :lidx (optimize-lidx lidx @largest-lidx-seen)})
        (reset! ref-name (:rname aln))
        (reset! bins (gen-vec (bin-count refs (:rname aln))))
        (reset! bins-seen 0)
        (reset! lidx (gen-vec max-lidx-size 0))
        (reset! largest-lidx-seen -1)
        (reset! meta {:first-offset -1
                      :last-offset 0
                      :aligned-alns 0
                      :unaligned-alns 0}))
      (if (zero? (:pos aln))
        (swap! no-coordinate-alns inc)
        (do (if-not (zero? (bit-and (:flag aln) 4))
              (swap! meta update-in [:unaligned-alns] inc)
              (swap! meta update-in [:aligned-alns] inc))
