             [metabase.driver :as driver]))
 
 
-(def tile-size 256)
-(def pixel-origin (float (/ tile-size 2)))
-(def pixel-per-lon-degree (float (/ tile-size 360.0)))
-(def pixel-per-lon-radian (float (/ tile-size (* 2 java.lang.Math/PI))))
+(def ^:const tile-size 256)
+(def ^:const pixel-origin (float (/ tile-size 2)))
+(def ^:const pixel-per-lon-degree (float (/ tile-size 360.0)))
+(def ^:const pixel-per-lon-radian (float (/ tile-size (* 2 java.lang.Math/PI))))
 
 (defn- radians->degrees [rad]
   (/ rad (float (/ java.lang.Math/PI 180))))

        {bot-rt-lat :lat bot-rt-lon :lon} (tile-lat-lon (+ x 1) (+ y 1) zoom)
        inside-filter ["INSIDE", lat-field-id, lon-field-id, top-lt-lat, top-lt-lon, bot-rt-lat, bot-rt-lon]]
    (update-in details [:filter]
      #(clojure.core.match/match %
        nil         inside-filter
        ["AND" & _] (conj % inside-filter)
        [& _]       (conj ["AND"] % inside-filter)))))


(defn- extract-points
  "Takes in a dataset query result object and pulls out the Latitude/Longitude pairs into nested `java.util.ArrayLists`.
   This is specific to the way we plan to feed data into `com.metabase.corvus.api.tiles.GoogleMapPinsOverlay`."
  [{{:keys [rows cols]} :data}]
  (if-not (> (count rows) 0)
    ;; if we have no rows then return an empty list of points
    (java.util.ArrayList. [])
    ;; otherwise we go over the data, pull out the lat/lon columns, and convert them to ArrayLists
    (let [find-col-idx (fn [special-type]
                         (->> (map-indexed (fn [idx itm] (when (= special-type (:special_type itm)) idx)) cols)
                              (filter identity)
                              (first)))
          lat-col-idx (find-col-idx "latitude")
          lon-col-idx (find-col-idx "longitude")]
      (->> (map (fn [row] (java.util.ArrayList. [(nth row lat-col-idx) (nth row lon-col-idx)])) rows)
           (java.util.ArrayList.)))))


;; This endpoints provides an image with the appropriate pins rendered given a json query
;; We evaluate the query and find the set of lat/lon pairs which are relevant and then render the appropriate ones
;; It's expected that to render a full map view several calls will be made to this endpoint in parallel
(defendpoint GET "/:zoom/:x/:y/:lat-field/:lon-field/:lat-col-idx/:lon-col-idx/"
  [zoom x y lat-field lon-field lat-col-idx lon-col-idx query :as request]
  {zoom String->Integer
   x String->Integer
   y String->Integer
   lat-field String->Integer
   lon-field String->Integer
   lat-col-idx String->Integer
   lon-col-idx String->Integer
   query String->Dict}
  ;; TODO - tried to use `query String->Dict` above, but got errors with json parsing for some reason
  (let [updated-query (assoc query :query (query-with-inside-filter (:query query) lat-field lon-field x y zoom))
        result (driver/dataset-query updated-query {:executed_by *current-user-id*
                                                    :synchronously true})

(ns metabase.api.tiles
  (:require [clojure.core.match :refer [match]]
            [clojure.data.json :as json]
            [clojure.tools.logging :as log]
            [compojure.core :refer [GET]]
            [metabase.api.common :refer :all]
