 
 (defn create-attributes [simple-attributes & {:keys [names]}]
   (let [attribute-names (or names (repeatedly simple-attributes #(random-word 5)))
-        generators (cycle attribute-generators)
+        generators (cycle *attribute-generators*)
         attributes (map #(vector %1 %2) attribute-names generators)]
     attributes))
 
+(defn generate-smile-stream
+  "Returns a SMILE-encoded writer for the given Clojure object.
+  Takes an optional date format string that Date objects will be encoded with.
+
+  The default date format (in UTC) is: yyyy-MM-dd'T'HH:mm:ss'Z'"
+  ([obj ^OutputStream os]
+   (generate-smile-stream obj nil os))
+  ([obj opt-map ^OutputStream os]
+   (let [generator (.createGenerator ^SmileFactory
+                                     cheshire.factory/smile-factory
+                                     ^OutputStream os)]
+     (cheshire.generate/generate generator obj (or (:date-format opt-map)
+                                     cheshire.factory/default-date-format)
+                   (:ex opt-map)
+                   (:key-fn opt-map))
+     (.flush generator)
+     os)))
+
+(defn generate-smile [obj]
+  (let [baos (ByteArrayOutputStream.)]
+    (.toByteArray (generate-smile-stream obj baos))))
+
+
+(defn texify-feature [feature]
+  (walk/postwalk
+    (fn [e]
+      (cond (instance? LocalDateTime e)
+            (texify-moment e)
+            (instance? LocalDate e)
+            (texify-date e)
+            (and (instance? MapEntry e) (= :_validity (first e)))
+            (MapEntry. :_validity (texify-validity (second e)))
+            :else e))
+    feature))
+
+(add-encoder LocalDate
+             (fn [c ^SmileGenerator smile-generator]
+               (doto smile-generator
+                 (.writeStartArray 2)
+                 (.writeString "D")
+                 (.writeNumber (to-long c))
+                 (.writeEndArray))))
+(add-encoder LocalDateTime
+             (fn [c ^SmileGenerator smile-generator]
+               (doto smile-generator
+                 (.writeStartArray 2)
+                 (.writeString "M")
+                 (.writeNumber (to-long c))
+                 (.writeEndArray))))
+
 (defn random-json-features [out-stream dataset collection total & args]
-  (let [{:keys [change? close? delete? start-with-delete? nested geometry? ids]
+  (let [{:keys [change? close? delete? start-with-delete? nested geometry? ids smile?]
          :or {change? false close? false delete? false
               start-with-delete? false nested 0 geometry? true
               ids (repeatedly #(random-word 10))}} args

        "</gml:Polygon> ")})

(defn random-date []
  (let [date (local-now)
        date-string (tf/unparse date-formatter date)]
    ["~#date", [date-string]]))

(defn random-moment []
  (let [moment (local-now)
        date-time-string (tf/unparse date-time-formatter moment)]
    ["~#moment", [date-time-string]]))

(def attribute-generators [#(random-word 5) random-date random-moment])

(defn new-feature [collection id]
   {:_action "new"
    :_collection collection
    :_id id
    :_validity (tf/unparse date-time-formatter (local-now))
    :_geometry (if *difficult-geometry?* difficult-geometry (random-geometry))})

(defn transform-to-change [feature]
  (-> feature
      (assoc :_action "change")
      (assoc :_current_validity (:_validity feature))
      (assoc :_validity (tf/unparse date-time-formatter
                          (t/plus (tf/parse date-time-formatter (:_validity feature)) (t/minutes 1))))))

(defn transform-to-close [feature]
  (-> feature
      (assoc :_action "close")
      (assoc :_current_validity (:_validity feature))
      (assoc :_validity (tf/unparse date-time-formatter
                          (t/plus (tf/parse date-time-formatter (:_validity feature)) (t/minutes 1))))))

(defn transform-to-delete [{:keys [_dataset _collection _id _validity]}]
  {:_action "delete"

(ns pdok.featured.generator
  (:require [cheshire
             [core :as json]
             [generate :refer [add-encoder]]]
            [clj-time
             [core :as t]
             [format :as tf]
             [local :refer [local-now]]
             [coerce :refer [to-long to-date-time to-local-date to-local-date-time]]]
            [clojure.walk :as walk])
  (:import [java.io PipedInputStream PipedOutputStream OutputStream InputStream ByteArrayOutputStream]
           (com.fasterxml.jackson.dataformat.smile SmileFactory SmileGenerator)
           (org.joda.time LocalDateTime LocalDate)
           (clojure.lang MapEntry)))

(def ^:dynamic *difficult-geometry?* false)

