(ns Path_Finder.main_
  [:require [clojure.java.io :as io]]
  [:use     Path_Finder.pathfinder]
  [:use     clojure.stacktrace]  
  [:use     [clojure.pprint :only [print-table pprint]]]
  [:import  ij.io.OpenDialog
            ij.io.DirectoryChooser
            ij.plugin.ImageCalculator
            java.lang.Math
            ij.gui.Plot
            ij.gui.GenericDialog])

; ---- from Stack Overflow
(defmacro defsource
  "Similar to clojure.core/defn, but saves the function's definition in the var's
   :source meta-data."
  {:arglists (:arglists (meta (var defn)))}
  [fn-name & defn-stuff]
  `(do (defn ~fn-name ~@defn-stuff)
       (alter-meta! (var ~fn-name) assoc :source (quote ~&form))
       (var ~fn-name)))

(def gd (GenericDialog. "Segmentation parameters"))
(.addNumericField gd "vertex threshold in [0,1]"   0.5 5)
(.addNumericField gd "membrane path threshold in [0,1]" 0.1 5)
(.addNumericField gd "small-cell-removal scale factor" 2000 5)
(.addNumericField gd "membrane pixel threshold in [0,1]" 0.01 5)
(.showDialog gd)
(def vthresh (.getNextNumber gd))
(def mthresh (.getNextNumber gd))
(def small_cell_factor (.getNextNumber gd))
(def mpixthresh (.getNextNumber gd))

; (.getValue gd "vertex threshold ∈ [0,1]")

(def params
  (let [pixval 65535]

    ; log converts sum of probabilities along path into product. This allows us to think of the distance as the probability of the path.
    #_(defsource metricfunc [x]
      (let [factor (/ pixval (Math/log (/ 1 pixval)))]
        ((comp
           int                         ; convert back to 16-bit ints
           #(* % factor)               ; ∈ [0, large positive ≈ 11]
           #(Math/log %)               ; ∈ [large negative, 0]
           #(/ % (+ 1 pixval))
           #(+ % 1)                    ; epsilon. small compared to pixval
           z)
        x)))
    
    (defsource metricfunc [x] (- pixval x))

    ; (def xs [0 100 1000 5000 20000 50000 65535] #_(range 0 pixval))
    ; (.show (Plot. "title" "xaxis" "Yaxis" (float-array xs) (float-array (map metricfunc xs))))

    {
     :cutoff     (metricfunc (* mthresh pixval))
     :mpixcutoff (metricfunc (* mpixthresh pixval))
     :vthresh    (* vthresh pixval)
     :distc      (* 1000 pixval)
     ; :mpvc       14
     :minarea    (fn [x]
                   (if (< x 11)
                     0
                     (* small_cell_factor (/ (Math/log (- x 10)) (Math/log 2)))))
     :metricfunc metricfunc
     :metrifnsrc (:source (meta #'metricfunc))
     :degc       (vec (map (partial * pixval) [1 1 0.5 0.0 0]))
    }
  )
)

; Really, we want a function :: [cell_area weakest_path_score] → keep | delete
; maxscore for path for paths at a vertex ordered by score
; serves as the function     :: [path_degree_rank path_score] → keep  | delete

; Get a set of three fileseq's and pair images via alphabetical ordering

(defn filesq-from-dirchooser [& [title]]
  (let [title (or title "pick directory")
        m1    (DirectoryChooser. title)
        m2    (.getDirectory m1)
        m3    (io/file m2)]
    (file-seq m3)))

(defn img? [x]
  (and
    (.endsWith (.getPath x) ".tif")
    #_(println (.getParent x))
    (not (.contains (-> x .getParent io/file .getParentFile .getName) "results"))))

(def orig_seq (filter img? (filesq-from-dirchooser "original image folder")))
(def memb_seq (filter img? (filesq-from-dirchooser "membrane_probability image folder")))
(def vert_seq (filter img? (filesq-from-dirchooser "vertex_probability image folder")))

(doseq [[o m v] (vec (map list orig_seq memb_seq vert_seq))]
  (println o)
  (println m)
  (println v)
  (println)
  (do-everything params (.getPath m) (.getPath v) (.getPath o)))

(let [f1 (io/file (.getPath (first orig_seq)))
      base (.getParent f1)
      sep java.io.File/separator
      newbase (str base sep "results")]
  (spit
    (str newbase sep "params.txt")
    (with-out-str (pprint params))))
