 (ns rum.server-render
   (:require [clojure.string :as str])
-  (:import [clojure.lang IPersistentVector ISeq Named]))
+  (:import [clojure.lang IPersistentVector ISeq Named]
+           [java.util.zip Adler32]))
 
 ;; From Weavejester's Hiccup
 ;; https://github.com/weavejester/hiccup/blob/master/src/hiccup/compiler.clj#L32

  [tag-attrs attrs]
  (let [attrs (for [[k v] attrs
                    :let [k (react-attr->html k)]
                    :when (not (.startsWith k "on"))]
                [k v])
        class (if (:class tag-attrs)
                (str (:class tag-attrs) " " (:class attrs))

;;; render html

(defprotocol HtmlRenderer
  (-render-html [this parent path]
    "Turn a Clojure data type into a string of HTML with react ids."))

(defn -render-element
  "Render an element vector as a HTML element."
  [element path]
  (let [[tag attrs content] (normalize-element element)
        path                (if (attrs "key")
                              (conj (subvec path 0 (dec (count path)))
                                "$" (attrs "key"))
                              path)
        attrs               (assoc attrs "key" nil
                              "data-reactid" (str/join "" path))]
    (if (container-tag? tag content)
      (str "<" tag (render-attr-map attrs) ">"
           (-render-html content element path)
           "</" tag ">")
      (str "<" tag (render-attr-map attrs) "/>"))))

(extend-protocol HtmlRenderer
  IPersistentVector
  (-render-html [this parent path]
    (-render-element this path))
  ISeq
  (-render-html [this parent path]
    (if (= 1 (count this))
      (-render-html (first this) this path)
      (let [separator (if (and (not (vector? parent))
                               (not= this (first parent)))
                        ":" ".")]
        (->> this
          (map-indexed #(-render-html %2 this (conj path separator %1)))
          (apply str)))))
  Named
  (-render-html [this parent path]
    (name this))
  String
  (-render-html [this parent path]
    this)
  Object
  (-render-html [this parent path]
    (str this))
  nil
  (-render-html [this parent path]
    ""))

(defn render-html [src]
  (let [result   (-render-html src nil ["." 0])
        checksum (adler32 result)]
    (str/replace-first result ">"
      (str " data-react-checksum=\"" checksum "\">"))))
