 
 
 
+;; TOTAL-ORDERING COMPARATOR
+
+(defn total-order
+  "Comparator function that provides a total-ordering of EDN values."
+  [a b]
+  (compare (pr-str a) (pr-str b))) ; FIXME: dirty hack
+
+
+
+;; EDN-TAGGED PROTOCOL
+
+(defprotocol TaggedValue
+  (edn-tag [this] "Return the tag symbol to apply to the value.")
+  (edn-value [this] "Return the value to pass to the tag."))
+
+
+(extend-protocol TaggedValue
+  java.util.Date
+  (edn-tag [this] 'inst)
+  (edn-value [this]
+    (let [utc-format (doto (java.text.SimpleDateFormat.
+                             "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00")
+                       (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))]
+      (.format utc-format this))))
+
+
+
 ;; DISPATCH MULTIMETHOD
+
+(defn- canonize-dispatch
+  [value]
+  (if (extends? TaggedValue (class value))
+    :tagged-value
+    (type value)))
+
 
 (defmulti canonize
   "Converts the given value into a 'canonical' structured document, suitable
   for printing with fipp. This method also supports ANSI color escapes for
   syntax highlighting if desired."
-  type)
+  #'canonize-dispatch)
 
 
 (defmacro ^:private color-primitive

     (color-text (pr-str value#) ~@codes)))


(color-primitive nil :red)
(color-primitive java.lang.Boolean :bold :blue)
(color-primitive java.lang.Number :cyan)
(color-primitive java.lang.Character :bold :magenta)
(color-primitive java.lang.String :bold :magenta)
(color-primitive clojure.lang.Keyword :bold :yellow)


(defmethod canonize clojure.lang.ISeq
  [s]
  [:group
   (delimiter "(")
   [:align (interpose :line (map canonize s))]
   (delimiter ")")])


; vector

; Maps should print their entries in sorted key order.

; Canonical sets should print their entries in sorted order.



(defmethod canonize :default
  [value]
  [:text (str \< (.getName (class value)) \space (pr-str value) \>)])


(defprinter cprint canonize {:width 80})

(defn- color-text
  "Constructs a text doc, which may be colored if *colored-output* is true."
  [text & codes]
  (if (and *colored-output* (not (empty? codes)))
    [:span [:pass (ansi/esc codes)] text [:pass (ansi/escape :none)]]
    text))

