(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])

; ---- taken from
(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. "test dialog"))
(.addNumericField gd "vertex threshold ∈ [0,1]"   0.5 4)
(.addNumericField gd "membrane threshold ∈ [0,1]" 0.1 4)
(.addNumericField gd "max_path_score < [val] × log₂ cellsize : val ∈ [0,∞)" 2000 5)
(.showDialog gd)
(def vthresh (.getNextNumber gd))
(def mthresh (.getNextNumber gd))
(def small_cell_factor (.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))
     :vthresh    (* vthresh pixval)
     :distc      (* 1000 pixval)
     ; :mpvc       14
     :minarea    (fn [x]
                   (if (#{0 1} x)
                     0
                     (* small_cell_factor (/ (Math/log (- x 1)) (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

; ---- Hardcode The Set Of Images ----

(def home "/Users/colemanbroaddus/Desktop/PKS_Work/MyersLab/Path_Finder/src/")
(def folder "/Users/colemanbroaddus/Desktop/PKS_Work/MyersLab/tests/PaperImages/dagmars_results/bestSoFar/")
(def origs
  ["/grayscale/a_20150127_EVLvsInner01_slice11-normalized.tif"
   "/grayscale/b_20150127_EVLvsInner10_slice9-normalized.tif"
   "/grayscale/c_20150128_fig10_slice10-normalized.tif"
   "/grayscale/d_20150211_mex3b_sox19a_domes03_slice9-normalized.tif"
   "/grayscale/e_20150211_mex3b_sox19a_domes04_slice10-normalized.tif"
   "/grayscale/f_20150211_mex3b_sox19a_domes09_slice9-normalized.tif"
   "/grayscale/g_20150215_fig3_sphere_repeat16_slice9-normalized.tif"])
(def membrane_imgs
  ["/membrane/level#1_image#00_membraneProb.tif"
   "/membrane/level#1_image#01_membraneProb.tif"
   "/membrane/level#1_image#02_membraneProb.tif"
   "/membrane/level#1_image#03_membraneProb.tif"
   "/membrane/level#1_image#04_membraneProb.tif"
   "/membrane/level#1_image#05_membraneProb.tif"
   "/membrane/level#1_image#06_membraneProb.tif"])
(def vertex_imgs
  ["/vertex/level#1_image#00_vertex.tif"
   "/vertex/level#1_image#01_vertex.tif"
   "/vertex/level#1_image#02_vertex.tif"
   "/vertex/level#1_image#03_vertex.tif"
   "/vertex/level#1_image#04_vertex.tif"
   "/vertex/level#1_image#05_vertex.tif"
   "/vertex/level#1_image#06_vertex.tif"])
(def vertex_imgs_32
  ["/vertex_32/level#1_image#00_probs2.tif"
   "/vertex_32/level#1_image#01_probs2.tif"
   "/vertex_32/level#1_image#02_probs2.tif"
   "/vertex_32/level#1_image#03_probs2.tif"
   "/vertex_32/level#1_image#04_probs2.tif"
   "/vertex_32/level#1_image#05_probs2.tif"
   "/vertex_32/level#1_image#06_probs2.tif"])

; (def orig_id 6)
; (def orig_str (str folder (origs orig_id)))
; (def mem_str  (str folder (membrane_imgs orig_id)))
; (def vtx_str  (str folder (vertex_imgs_32 orig_id)))

; (do-everything params mem_str vtx_str orig_str)

; 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 image folder")))
(def vert_seq (filter img? (filesq-from-dirchooser "vertex image folder")))

(doseq [[o m v] (map (vec (map list orig_seq memb_seq vert_seq)) [0 1 2 3 4 5 6])]
  (def orig_str (.getPath o))
  (def mem_str  (.getPath m))
  (def vtx_str  (.getPath v))
  (println o)
  (println m)
  (println v)
  (println)
  (do-everything params mem_str vtx_str orig_str))

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

; ---- Use File Chooser To Get Images One-at-a-time ----
; (def orig_str (.getPath (OpenDialog. "Original Image - 16bit")))
; (def mem_str  (.getPath (OpenDialog. "Membrane Image - 16bit")))
; (def vtx_str  (.getPath (OpenDialog. "Vertex Image - two-valued")))
; (do-everything params mem_str vtx_str orig_str)
