 
 (defui ^:once CommitRoot
   static uc/InitialAppState
-  (initial-state [this _] {:new-person (uc/initial-state Person {:db/id 2346})
-                           :person     (uc/initial-state Person {})})
+  (initial-state [this _] {:person (uc/initial-state Person {:db/id 1})})
   static om/IQuery
   (query [this] [:ui/react-key
-                 {:new-person (om/get-query Person)}
                  {:person (om/get-query Person)}])
   Object
   (render [this]
     (let [{:keys [ui/react-key new-person person]} (om/props this)]
       (dom/div #js {:key react-key}
-        (ui-person new-person)
         (ui-person person)))))
 
-(defn api-read [{:keys [state]} k params]
-  {:value 42})
+(defcard-doc
+  "# Forms -- Field Interactions
 
-(defn api-mutate [{:keys [state]} k params]
-  (js/console.log "api-mutate:" k params)
-  {:action (fn [] (swap! state assoc [k :seen/delta] params))})
+  Many forms need logic that updates the UI in some non-local way as form interactions take place.
+  Simple field validations can be local to a field, but some UI changes require who-form reasoning
+  or cross-field interactions.
 
-(defonce server-state (atom {:FAKE true}))
-(defonce mock-network (make-mock-network server-state {:read api-read :mutate api-mutate}))
+  Some simple examples:
 
-(defcard mock-server-state
-  "This card shows the server state atom *live*!"
-  server-state
-  {:watch-atom   true
-   :inspect-data true})
+  - Verification fields (two fields must contain the same data to ensure they typed it correctly)
+  - Triggering a server-side check of a value (e.g. is that username in use?)
+  - Making other UI elements appear/disappear according to field changes
 
-(defcard CommitEntity
+  We accomplish these things in the form support by allowing you to declare an entry in your
+  `IForm` list that names an Untangled mutation to run as changes are detected in the form/subform
+  set.
+
+")
+
+(defcard form-changes
+  "# Verifying Username Sample
+
+  The following sample uses a mock server to do a full-stack form interaction example that uses
+  `on-form-change` to check is a username is available. The already known usernames are 'tony' and
+  'sam'.
+
+  On blur, the server will be asked if the username is available (with a simulated 1s network latency).
+
+  The load will trigger UI refresh and show the message.
+
+  TODO: Fix the CSS/rendering to be prettier
+  "
   (untangled-app CommitRoot
-    :started-callback (fn [app] '...)
-    :networking mock-network)
+    :networking (map->MockNetwork {}))
   {}
-  {:inspect-data true})
+  {:inspect-data false})
 
-(defcard-doc "##on-form-change")
-
-(defn notify-form-changed [state {:keys [form-id field value]}]
-  (assoc-in state (conj form-id :form-change/notification)
-    (str "Field: " field " changed to: " value)))
-
-(defmethod m/mutate 'form-changed/notify [{:keys [state]} k {:as params :keys [form-id field value]}]
-  {:action (fn [] (swap! state notify-form-changed params))})
-
-(defui ^:once ChangePlexer
-  static uc/InitialAppState
-  (initial-state [this _] (f/build-form this {:db/id 1}))
-  static f/IForm
-  (form-spec [this]
-    [(f/on-form-change 'form-changed/notify)
-     (f/id-field :db/id)
-     (f/text-input :some/text :default-value "some text")])
-  static om/IQuery
-  (query [this] [f/form-key f/form-root-key
-                 :db/id :some/text :form-change/notification])
-  static om/Ident
-  (ident [this props] [:change-plexer/by-id (:db/id props)])
-  Object
-  (render [this]
-    (let [{:keys [form-change/notification] :as props} (om/props this)]
-      (dom/div nil
-        (when notification (dom/p nil (str "on-form-change notification: " notification)))
-        (f/form-field this props :some/text)))))
-
-(def ui-change-plexer (om/factory ChangePlexer))
-
-(defui ^:once ChangeRoot
-  static uc/InitialAppState
-  (initial-state [this _] {:change-plexer (uc/initial-state ChangePlexer {})})
-  static om/IQuery
-  (query [this] [:ui/react-key {:change-plexer (om/get-query ChangePlexer)}])
-  Object
-  (render [this]
-    (let [{:keys [ui/react-key change-plexer]} (om/props this)]
-      (dom/div #js {:key react-key}
-        (ui-change-plexer change-plexer)))))
-
-(defcard-doc
-  "Here's the source code for a component that uses on-form-change"
-  (dc/mkdn-pprint-source ChangePlexer)
-
-  "To trigger a mutation whenever your form changes simply
-   add a `(on-form-change 'your/mutation)` to your `form-spec`,
-   and any renders that support it will transact! on `'your/mutation`."
-  (dc/mkdn-pprint-source notify-form-changed))
-
-(defcard on-form-change-sample
-  "Change the text value to see the on-change notification."
-  (untangled-app ChangeRoot)
-  {}
-  {:inspect-data true})

    [om.dom :as dom]
    [om.next :as om :refer [defui]]
    [untangled.client.core :as uc]
    [untangled.client.mutations :as m]
    [untangled.ui.forms :as f]
    [untangled.ui.simulated-server :refer [make-mock-network]]))

(defcard-doc
  "# Forms -- Field Interactions

  Many forms need logic that updates the UI as form interactions take place. Simple field validations can
  be local to a field, but some UI changes require who-form reasoning or cross-field interactions.

  Some simple examples:

  - Verification fields (two fields must contain the same data to ensure they typed it correctly)
  -

")

(defn field-with-label
  "A non-library helper function, written by you to help lay out your form."

     (when (and validation-message (f/invalid? form name))
       (dom/span #js {:className (str "col-sm-offset-2 col-sm-10" name)} validation-message)))))

(defui NameInUseQuery
  static om/IQuery
  (query [this] []))

(defmutation check-username-available
  "Sample mutation that simulates legal username check"
  [{:keys [form-id kind field]}]
  (action [{:keys [state]}]
    (js/console.log field kind)
    (when (and (= kind :blur) (= :person/name field))
      ; you could do this with a remote/post mutation sequence...
      (let [value (get-in @state (conj form-id field))]
        (df/load-action state :name-in-use nil {:target  (conj form-id :ui/name-status)
                                                :refresh [f/form-root-key]
                                                :params  {:name value}}))))
  (remote [env] (df/remote-load env)))

(defui ^:once Person
  static uc/InitialAppState
  (initial-state [this params] (f/build-form this (or params {})))
  static f/IForm
  (form-spec [this] [(f/id-field :db/id)
                     (f/on-form-change `check-username-available)
                     (f/text-input :person/name)
                     (f/integer-input :person/age)])
  static om/IQuery
  (query [this] [f/form-root-key f/form-key
                 :db/id :person/name :person/age :ui/name-status])
  static om/Ident
  (ident [this props] [:person/by-id (:db/id props)])
  Object
  (render [this]
    (let [{:keys [ui/name-status] :as props} (om/props this)]
      (dom/div #js {:className "form-horizontal"}
        (field-with-label this props :person/name "Username:" "Please enter your first and last name.")
        (case name-status
          :duplicate (dom/span nil "That username is in use.")
          :ok (dom/span nil "OK" (untangled.icons/icon :check))
          (dom/span nil ""))
        (field-with-label this props :person/age "Age:" "That isn't a real age!")
        (dom/div #js {:className "button-group"}
          (dom/button #js {:className "btn btn-default"
