(ns topdown2d.tileset
  (:require [topdown2d.collision :as coll]))

(def ^:dynamic tileset)

(defn next-animation-cycle [animation curr-cycle]
  (let [curr-ix (.indexOf animation curr-cycle)
        next-ix (inc curr-ix)
        next-ix (if (> next-ix (count animation))
                  0 next-ix)]
    (nth animation next-ix)))

(defn map-def->tileset [map-def tileset-id]
  (->> (:tilesets map-def)
       (filter #(= (name tileset-id) (:name %)))
       first))

(defn tick-animation [tileset-def anim-def now]
  (let [map-def (:def tileset-def)
        {:keys [ids last-cycle curr-id tileset]} anim-def
        animation (->> (map-def->tileset map-def tileset)
                       :tiles
                       (filter #(= curr-id (:id %)))
                       first
                       :animation)
        curr-cycle (filter #(= curr-id (:tileid %)) animation)
        trigger-cycle? (> (- now last-cycle)
                          (:duration curr-cycle))
        next-cycle (and trigger-cycle?
                        (next-animation-cycle animation curr-cycle))]
    (if trigger-cycle?
      (assoc anim-def
             :last-cycle now
             :curr-id (:tileid next-cycle))
      anim-def)))

(defn ix->coords [ix width height]
  (let [x (rem ix width)]
    [(dec x)
     (/ (- ix x) width)]))

(defn layer->dest [tileset layer]
  (map-indexed
   (fn [ix tile]
     (let [{:keys [width height]} layer
           [dxc dyc] (ix->coords ix width height)
           {:keys [tilewidth tileheight]} tileset]
       {:tile tile
        :x (* dxc tilewidth)
        :y (* dyc tileheight)
        :w tilewidth
        :h tileheight}))
   (:data layer)))

(defn draw-tile [ctx tileset image tileid dest]
  (let [{:keys [tileheight tilewidth
                tiles-x tiles-y]} tileset
        [x y] (ix->coords tileid tiles-x tiles-y)
        sx (* x tilewidth)
        sy (* y tileheight)]
    (.drawImage ctx image
                sx sy tilewidth tileheight
                (:x dest) (:y dest)
                tilewidth tileheight)))

(defn draw-viewport [map-def ctx viewport]
  (let [{:keys [images def]} map-def
        {:keys [tileheight tilewidth
                height width layers]} def
        tileset-id (:tileset viewport)
        image (tileset-id images)
        tileset (map-def->tileset def (:tileset viewport))]
    (doseq [layer layers]
      (doseq [dest layer
              :let [dx (- (:x dest) (:x viewport))
                    dy (- (:y dest) (:y viewport))]]
        (draw-tile ctx tileset image
                   (:tile dest)
                   {:x dx :y dy})))))
