;; 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 Sucursal en España SL

(ns app.plugins.ruler-guides
  (:require
   [app.common.data.macros :as dm]
   [app.common.files.helpers :as cfh]
   [app.common.schema :as sm]
   [app.main.data.workspace.guides :as dwgu]
   [app.main.store :as st]
   [app.plugins.format :as format]
   [app.plugins.register :as r]
   [app.plugins.system-events :as se]
   [app.plugins.utils :as u]
   [app.util.object :as obj]))

(def shape-proxy identity)
(def shape-proxy? identity)

(defn ruler-guide-proxy? [p]
  (obj/type-of? p "RulerGuideProxy"))

(defn ruler-guide-proxy
  [plugin-id file-id page-id id]
  (obj/reify {:name "RulerGuideProxy"}
    :$plugin {:enumerable false :get (constantly plugin-id)}
    :$file {:enumerable false :get (constantly file-id)}
    :$page {:enumerable false :get (constantly page-id)}
    :$id {:enumerable false :get (constantly id)}

    :board
    {:this true
     :enumerable false
     :get
     (fn [self]
       (let [board-id (-> self u/proxy->ruler-guide :frame-id)]
         (when board-id
           (shape-proxy plugin-id file-id page-id board-id))))

     :set
     (fn [self value]
       (let [shape (u/locate-shape file-id page-id (obj/get value "$id"))]
         (cond
           (not (shape-proxy? value))
           (u/not-valid plugin-id :board "The board is not a shape proxy")

           (not (cfh/frame-shape? shape))
           (u/not-valid plugin-id :board "The shape is not a board")

           (not (r/check-permission plugin-id "content:write"))
           (u/not-valid plugin-id :board "Plugin doesn't have 'content:write' permission")

           (not (u/page-active? page-id))
           (u/not-valid plugin-id :board "Cannot modify a page that is not currently active")

           :else
           (let [board-id (when value (obj/get value "$id"))
                 guide    (-> self u/proxy->ruler-guide)]
             (st/emit! (-> (dwgu/update-guides (assoc guide :frame-id board-id))
                           (se/add-event plugin-id)))))))}

    :orientation
    {:this true
     :get #(-> % u/proxy->ruler-guide :axis format/axis->orientation)}

    :position
    {:this true
     :get
     (fn [self]
       (let [guide (u/proxy->ruler-guide self)]
         (if (:frame-id guide)
           (let [objects   (u/locate-objects file-id page-id)
                 board-pos (dm/get-in objects [(:frame-id guide) (:axis guide)])
                 position  (:position guide)]
             (- position board-pos))

           ;; No frame
           (:position guide))))
     :set
     (fn [self value]
       (cond
         (not (sm/valid-safe-number? value))
         (u/not-valid plugin-id :position "Not valid position")

         (not (r/check-permission plugin-id "content:write"))
         (u/not-valid plugin-id :position "Plugin doesn't have 'content:write' permission")

         (not (u/page-active? page-id))
         (u/not-valid plugin-id :position "Cannot modify a page that is not currently active")

         :else
         (let [guide (u/proxy->ruler-guide self)
               position
               (if (:frame-id guide)
                 (let [objects   (u/locate-objects file-id page-id)
                       board-pos (dm/get-in objects [(:frame-id guide) (:axis guide)])]
                   (+ board-pos value))

                 value)]
           (st/emit! (-> (dwgu/update-guides (assoc guide :position position))
                         (se/add-event plugin-id))))))}

    :color
    {:this true
     :get
     (fn [self]
       (-> self u/proxy->ruler-guide :color))

     :set
     (fn [self value]
       (cond
         (not (r/check-permission plugin-id "content:write"))
         (u/not-valid plugin-id :color "Plugin doesn't have 'content:write' permission")

         (not (u/page-active? page-id))
         (u/not-valid plugin-id :color "Cannot modify a page that is not currently active")

         :else
         (let [guide (u/proxy->ruler-guide self)]
           (st/emit! (dwgu/update-guides (assoc guide :color value))))))}

    :remove
    (fn []
      (cond
        (not (u/page-active? page-id))
        (u/not-valid plugin-id :remove "Cannot modify a page that is not currently active")

        :else
        (let [guide (u/locate-ruler-guide file-id page-id id)]
          (st/emit! (-> (dwgu/remove-guide guide)
                        (se/add-event plugin-id))))))))
