;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC

(ns app.util.path.format
  (:require
   [app.common.svg.path.command :as upc]
   [app.common.svg.path.subpath :refer [pt=]]
   [app.util.array :as arr]))

(def path-precision 3)

(defn- join-params
  ([a]
   (js* "\"\"+~{}"
        (.toFixed a path-precision)))
  ([a b]
   (js* "\"\"+~{}+\",\"+~{}"
        (.toFixed a path-precision)
        (.toFixed b path-precision)))
  ([a b c]
   (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}"
        (.toFixed a path-precision)
        (.toFixed b path-precision)
        (.toFixed c path-precision)))
  ([a b c d]
   (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}"
        (.toFixed a path-precision)
        (.toFixed b path-precision)
        (.toFixed c path-precision)
        (.toFixed d path-precision)))
  ([a b c d e]
   (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}"
        (.toFixed a path-precision)
        (.toFixed b path-precision)
        (.toFixed c path-precision)
        (.toFixed d path-precision)
        (.toFixed e path-precision)))
  ([a b c d e f]
   (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}"
        (.toFixed a path-precision)
        (.toFixed b path-precision)
        (.toFixed c path-precision)
        (.toFixed d path-precision)
        (.toFixed e path-precision)
        (.toFixed f path-precision)))
  ([a b c d e f g]
   (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}"
        (.toFixed a path-precision)
        (.toFixed b path-precision)
        (.toFixed c path-precision)
        (.toFixed d path-precision)
        (.toFixed e path-precision)
        (.toFixed f path-precision)
        (.toFixed g path-precision))))

(defn- translate-params
  [command {:keys [x y] :as params}]
  (case command
    (:move-to :line-to :smooth-quadratic-bezier-curve-to)
    (join-params x y)

    :close-path
    ""

    (:line-to-horizontal :line-to-vertical)
    (:value params)

    :curve-to
    (let [{:keys [c1x c1y c2x c2y]} params]
      (join-params (or c1x x) (or c1y y) (or c2x x) (or c2y y) x y))

    (:smooth-curve-to :quadratic-bezier-curve-to)
    (let [{:keys [cx cy]} params]
      (join-params cx cy x y))

    :elliptical-arc
    (let [{:keys [rx ry x-axis-rotation large-arc-flag sweep-flag]} params]
      (join-params rx ry x-axis-rotation large-arc-flag sweep-flag x y))

    ""))

(defn- translate-command
  [cname]
  (case cname
    :move-to "M"
    :close-path "Z"
    :line-to "L"
    :line-to-horizontal "H"
    :line-to-vertical "V"
    :curve-to "C"
    :smooth-curve-to "S"
    :quadratic-bezier-curve-to "Q"
    :smooth-quadratic-bezier-curve-to "T"
    :elliptical-arc "A"
    ""))


(defn- command->string
  [{:keys [command relative params]}]
  (let [cmd (cond-> (translate-command command)
              relative (.toLowerCase))
        prm (translate-params command params)]
    (js* "~{} + ~{}" cmd prm)))

(defn- set-point
  [command {:keys [x y]}]
  (update command :params assoc :x x :y y))

(defn format-path [content]
  (try
    (let [result (make-array (count content))]
      (reduce (fn [last-move current]
                (let [point         (upc/command->point current)
                      current-move? (= :move-to (:command current))
                      last-move     (if current-move? point last-move)]

                  (if (and (not current-move?) (pt= last-move point))
                    (arr/conj! result (command->string (set-point current last-move)))
                    (arr/conj! result (command->string current)))

                  (when (and (not current-move?) (pt= last-move point))
                    (arr/conj! result "Z"))

                  last-move))
              nil
              content)
      (.join ^js result ""))

    (catch :default err
      (.error js/console err)
      nil)))
