(ns Path_Finder.src.pathfinder)

; java stuff
(require '[clojure.reflect :as r])

; our stuff
(use 'Path_Finder.src.drawing)
(use 'Path_Finder.src.tinycell)

(import PathFinder)

(defn do-everything [params
                     mem_str
                     vtx_str
                     orig_str]

  (def pthfdr  (PathFinder.))
  (def orig    (ij.IJ/openImage orig_str))
  (def mem     (ij.IJ/openImage mem_str))
  (.invert (.getProcessor mem))
  (def vtx (label-vertices (ij.IJ/openImage vtx_str)))
  (def vertex_list (.getBlobCenters pthfdr vtx))
  (.close vtx)
  (def vor (make-16bit-img "Voronoi Tessellation" "3-3-2 RGB" (.getWidth mem) (.getHeight mem)))
  ; `conn` updates `vor` in-place)
  (def conn      (.buildVoronoiImageAndConnections pthfdr vertex_list mem vor (params :distc)))
  (def edges     (get-path-edges vertex_list conn))
  (def end_links      (for [[i j start end] edges] (.buildPath pthfdr start end mem vor (params :distc))))
  (def paths     (vec (for [e end_links] (.getPath pthfdr e))))
  (def scores    (vec (for [p paths] (qualityscore p))))

  (comment
    ; path_tuple is lazy, but non computed twice because of clojure's auto-memoization?)
    ; must use vec to lookup paths by id)
    (def path_tuple  (get-pathinfo-from-edges pthfdr edges mem vor (params :distc)))
    (def paths   (vec (map first path_tuple)))
    (def scores  (vec (map last  path_tuple))))

  (defn paths_and_scores [ids]
    (map (fn [id] [(paths id) (scores id)]) ids))

  ; (def vtxmap  (get-vtxmap path_tuple))
  (def vtxmap  (get-vtxmap-2 scores edges))

  ; a list of path_ids that pass degree_cutoff
  (def good_path_ids (make-good-path-list vtxmap (params :degc)))

  ; plot results of first round
  (def path_img  (make-16bit-img "Paths" "blue orange icb" (.getWidth mem) (.getHeight mem)))
  (def path_proc (.getProcessor path_img))
  (draw-paths (paths_and_scores good_path_ids) path_proc)

  ; first time removes ≈ 400
  (def bad_ids (remove-tiny-cells
                     path_img
                     good_path_ids
                     paths
                     scores
                     (params :minarea)))
  (def path_img_2  (make-16bit-img "path_img_2" "blue orange icb" (.getWidth mem) (.getHeight mem)))
  (def path_proc_2 (.getProcessor path_img_2))
  (def goodids2 (clojure.set/difference good_path_ids bad_ids))
  (draw-paths (paths_and_scores goodids2) path_proc_2)

  ; 2nd time removes ≈ 50
  (def bad_ids_2 (remove-tiny-cells
                     path_img_2
                     goodids2
                     paths
                     scores
                     (params :minarea)))
  (def path_img_3  (make-16bit-img "path_img_3" "blue orange icb" (.getWidth mem) (.getHeight mem)))
  (def path_proc_3 (.getProcessor path_img_3))
  (def goodids3 (clojure.set/difference good_path_ids bad_ids bad_ids_2))
  (draw-paths (paths_and_scores goodids3) path_proc_3)

  ; 3rd times the charm
  (def bad_ids_3 (remove-tiny-cells
                     path_img_3
                     goodids2
                     paths
                     scores
                     (params :minarea)))
  (def path_img_4  (make-16bit-img "path_img_4" "blue orange icb" (.getWidth mem) (.getHeight mem)))
  (def path_proc_4 (.getProcessor path_img_4))
  (def goodids4 (clojure.set/difference good_path_ids bad_ids bad_ids_2 bad_ids_3))
  (draw-paths (paths_and_scores goodids4) path_proc_4)

  ; Final Segmentation After Three Rounds Of Bad-edge-removal
  (def final (get-cell-img path_img_4))

  ; Scale The Resulting Paths Back Up To Original Size And Overlay On Orig
  (def scaled_up_img (get-scaled-up-img orig mem (paths_and_scores goodids4)))
  (.. scaled_up_img getProcessor invert)
  (def scaled_cells (get-cell-img scaled_up_img))
  (def proc (.. scaled_cells getProcessor (convertToShort false)))
  (.. scaled_cells (setProcessor proc))
  ; (.show scaled_cells)
  (def scaled_stack (.getStack scaled_cells))
  (.addSlice scaled_stack "Original" (.getProcessor orig))
  (.addSlice scaled_stack "Paths" (.. scaled_up_img getProcessor (convertToShort true)))
  (.setStack scaled_cells scaled_stack)

  ; ---- Find Overlap Points (after Removing Small Cells) ----
  (def overlap_points (get-overlap-points pthfdr (paths_and_scores goodids4) path_proc_4 (params :mpvc)))
  (ij.IJ/log (str "There are " (count overlap_points) " overlap points."))
  ; (def s1 (set (map #(into [] %) vertex_list)))
  ; (def s2 (set (map #(into [] %) overlap_points)))
  ;; plot vertices and overlap points
  (def simple_verts (make-16bit-img "Pixel Vertices" "Grays" (.getWidth mem) (.getHeight mem)))
  (doseq [px vertex_list :let [proc (.getProcessor simple_verts)]]
    (.set proc (aget px 0) (aget px 1) 6000))
  (doseq [px overlap_points :let [proc (.getProcessor simple_verts)]]
    (.set proc (aget px 0) (aget px 1) 12000))

  ; ---- Make Downscaled Original ----
  (def origproc (.getProcessor orig))
  (def origproc_small (.resize origproc (.getWidth mem) (.getHeight mem) true))

  ; ---- Plot Everything In One Stack ----
  (def pathStack (.getStack simple_verts))
  (.addSlice pathStack "Path Scores" path_proc)
  (.addSlice pathStack "Small Cells Removed 1" path_proc_2)
  (.addSlice pathStack "Small Cells Removed 2" path_proc_3)
  ; (.addSlice pathStack "Small Cells Removed 3" path_proc_4)
  (.addSlice pathStack "Original" origproc_small) ; (.. mem getProcessor (convertToShort true))) ; TODO: use real orig image. do scaling automatically.
  (.addSlice pathStack "Segmented" (.. final getProcessor (convertToShort false)))
  (.setStack simple_verts pathStack)

  (ij.IJ/save simple_verts  (clojure.string/replace orig_str ".tif" "_stackfinal.tif"))
  (ij.IJ/save scaled_cells  (clojure.string/replace orig_str ".tif" "_scaled.tif"))

  ; ; Now iterate on the path_proc_3
  ; (def good_path_ids (make-good-path-list vtxmap [55536 55536 32000 31625 5312])) ; (params :degc)))
  ; (def goodids3 (clojure.set/difference good_path_ids bad_ids bad_ids_2))
  ; (.setValue path_proc_3 500.0)
  ; (def p (path-to-poly (paths 10) 1.0))
  ; (.draw path_proc_3 p)
  ; (draw-paths (paths_and_scores goodids3) path_proc_3)

  ; (.setProcessor pathStack path_proc_3 4)
  ; (.setStack simple_verts pathStack)

  ; ---- TEAR EVERYTHING DOWN ----
  (map #(.close %) [mem vor path_img path_img_2 path_img_3 path_img_4 scaled_up_img scaled_cells final])

)