 (defn- text-node? [dom-node]
   (identical? (.-nodeType dom-node) 3))
 
-(defn- replace-child [parent new-elem-spec cur-elem]
-  (let [cur-dom-node cur-elem                                       ;;
-  ;; (get-dom-node cur-elem)
-        new-virtual-dom (get-virtual-dom new-elem-spec)]
-    (if (and
-          (string? new-virtual-dom)
-          (text-node? cur-dom-node))
+(def enable-diffing false)
+
+(defn- can-diff-element [parent new-elem-spec cur-elem])
+
+(defn- normalize-virtual-element [dom-vec]
+  (let [tag (first dom-vec)
+        tag-ns (namespace tag)
+        [_ tag id class] (re-matches re-tag (name tag))
+        class (when class (.replace class "." " "))
+        attrs? (second dom-vec)
+        attrs (when (map? attrs?) attrs?)
+        children (if attrs (nnext dom-vec) (next dom-vec))]
+    (if (or id class)
+      (into [(keyword tag-ns tag) (merge attrs {:id id :class class})]
+            children)
+      dom-vec)))
+
+(defn- replace-node-completly [parent new-elem-spec cur-dom-node]
+  (let [new-elem (build-element new-elem-spec)]
+        (.replaceChild parent new-elem cur-dom-node)
+        (dispose-node cur-dom-node)
+        new-elem))
+
+(declare replace-child)
+
+(declare replace-or-append-child)
+
+(declare append-children!)
+
+(defn- try-diff-subseq [parent cur-child new-children]
+  (loop [cur-child cur-child
+         new-child (first new-children)
+         more (rest new-children)]
+    (if new-child
+      (if cur-child
+        (if (and (sequential? new-child) (not (keyword? (first new-child))))
+          (let [cur-child (try-diff-subseq parent cur-child new-child)]
+            (recur cur-child (first more) (rest more)))
+          (do
+            (replace-child parent new-child cur-child false)
+            (recur (.-nextSibling cur-child) (first more) (rest more))))
+        (do
+          (append-children! parent new-children)
+          nil))
+      cur-child)))
+
+(defn- try-diff [parent vdom cur-dom-node top-level]
+  (let [cur-vdom (get-virtual-dom cur-dom-node)
+        vdom (normalize-virtual-element vdom)]
+    (if (keyword-identical? (first vdom) (first cur-vdom))
+      (let [old-attrs? (second cur-vdom)
+            new-attrs? (second vdom)
+            new-attrs (when (map? new-attrs?) new-attrs?)]
+        (replace-attrs! cur-dom-node
+                        (when (map? old-attrs?) old-attrs?)
+                        new-attrs)
+        (when-not top-level
+          (dispose-child-state (get-element-state cur-dom-node) "-reactive"))
+        (reset-element-spec! cur-dom-node vdom)
+        (let [new-children (if new-attrs (nnext vdom) (next vdom))
+              dangling-child (try-diff-subseq cur-dom-node (.-firstChild cur-dom-node) new-children)]
+          (loop [cur-child dangling-child]
+            (when cur-child
+              (let [next-sib (.-nextSibling cur-child)]
+                (.removeChild cur-dom-node cur-child)
+                (recur next-sib)))))
+        cur-dom-node)
+      (replace-node-completly parent vdom cur-dom-node))))
+
+(defn- replace-child [parent new-elem-spec cur-dom-node top-level]
+  (let [new-virtual-dom (get-virtual-dom new-elem-spec)]
+    (if
+      (and (string? new-virtual-dom)
+           (text-node? cur-dom-node))
       (do
         (set! (.-textContent cur-dom-node) new-virtual-dom)
-        ;(reset-element-spec! cur-dom-node new-elem-spec)
-        cur-elem)
-      (let [new-elem (build-element new-elem-spec)]
-        (.replaceChild
-          ;(get-dom-node parent)
-          ;(get-dom-node new-elem)
-          parent
-          new-elem
-          cur-dom-node)
-        (dispose-node cur-dom-node)
-        new-elem))))
+        cur-dom-node)
+
+      (if enable-diffing
+        (if top-level
+          (do
+            (println "starting diff replace")
+            (time
+              (try-diff parent new-virtual-dom cur-dom-node top-level)))
+          (try-diff parent new-virtual-dom cur-dom-node top-level))
+
+        (if top-level
+          (do
+            (println "starting full replace")
+            (time
+              (replace-node-completly parent new-elem-spec cur-dom-node))))
+        (replace-node-completly parent new-elem-spec cur-dom-node)))))
 
 (defn- append-child [parent new-elem]
   (let [new-elem (build-element new-elem)]

    (enter-transition element old-state)))

(defn set-data-state!
  ([element _ state] (set-data-state! element state))
  ([element state]
    (let [cur-state (get-data-state element)
          state (name state)]

      ;(set! (.-cur-element state)
      ;      (transition-element parent (or (non-reactively @child-ref) [:span]) nil))
      (when-let [parent-state (get-element-state parent)]
        (register-with-parent-state parent-state "-reactive" state))
      state)
    (transition-element parent @child-ref nil)))

