(ns yenu.helpers.images
  (:require [image-resizer.core :refer :all]
            [image-resizer.util :as utils]
            [image-resizer.format :refer :all]
            [image-resizer.crop :refer :all]
            [image-resizer.resize :refer :all]
            [image-resizer.scale-methods :refer :all]
            [clojure.java.io :as io]
            [clojure.string :as s]
            [digest :as digest]
            [me.raynes.fs :as fs]
            [clj-exif-orientation.core :as exif]
            [yenu.config :refer [env]]))

;;; HINT: To use the env function, the webserver need to be started with
;;; (start) in the 'user namespace.
(defn data-path
  ([] (data-path ""))
  ([& args]
   (let [postfix (apply io/file args)]
     (.getPath (io/file (env :user-dir) "data" postfix)))))

(defn create-needed-folders []
  (if-not (fs/exists? (data-path "to-process"))
    (fs/mkdirs (data-path "to-process")))
  (if-not (fs/exists? (data-path "gallery"))
    (run! #(fs/mkdirs (data-path "gallery" %))
          ["normal" "raw" "thumbnails"])))

(defn target-image-filename [image-file-path]
  (let [file (io/file image-file-path)]
    (str (.lastModified file) "-" (digest/md5 file))))

(defn delete-image! [image-hash]
  (run! #(fs/delete (data-path "gallery" % image-hash))
        ["normal" "raw" "thumbnails"]))

(defn scale-thumbnail [width]
  #(let [image-file % [orig-width orig-height] (dimensions (utils/buffered-image image-file))]
     (if (< orig-width orig-height)
       (let [resized-img ((resize-width-fn width ultra-quality) image-file)
             [w h] (dimensions resized-img)
             crop-margin (quot (- h width) 2)]
         (crop-from resized-img 0 crop-margin width width))
       (let [resized-img ((resize-height-fn width ultra-quality) image-file)
             [w h] (dimensions resized-img)
             crop-margin (quot (- w width) 2)]
         (crop-from resized-img crop-margin 0 width width)))))

(defn scale-normal [width height]
  #(let [image-file % [orig-width orig-height] (dimensions (utils/buffered-image image-file))]
     (if (and (< orig-width width) (< orig-height height))
       ((resize-fn orig-width orig-height ultra-quality) %)
       ((resize-fn width height ultra-quality) %))))

(defn remove-metadata [filepath file]
  (if (contains? #{".jpg" ".jpeg" ".jpe"} (s/lower-case (fs/extension filepath)))
    (let [new-file (exif/without-exif file)]
      (if (= (fs/size new-file) 0)
        (do
          (.delete new-file)
          file)
        new-file))
    file))

(defn save [fn params filepath target-filepath]
  (let [file (remove-metadata filepath (io/file filepath))]
    (try
      (do
        (as-file ((apply fn params) file)
                 target-filepath
                 :verbatim)
        (if (= (fs/extension file) ".tmp")
          (fs/delete file))
        true)
      (catch Exception e
        (fs/delete file)
        false))))

(defn remove-temp-image [filepath]
  (fs/delete filepath))

(defn scale-image-and-save [filepath]
  (let [image-hash (target-image-filename filepath)
        file-extension (fs/extension filepath)
        new-file-name (str image-hash file-extension)]
    (fs/copy filepath (data-path "gallery" "raw" new-file-name))
    (if (every? true?
                [(save scale-normal [1024 768] filepath (data-path "gallery" "normal" new-file-name))
                 (save scale-thumbnail [250] filepath (data-path "gallery" "thumbnails" new-file-name))])
      new-file-name
      false)))

(defn process-all-images []
  (pmap scale-image-and-save (fs/list-dir (data-path "to-process"))))
