    (->> opts
         (merge {:uri-context ""
                 ;; If you don't provide a renderer, one will be provided for you
-                :renderer (->PlainLoginFormRenderer)})
+                :renderer (->PlainLoginFormRenderer)
+                :fields
+                [{:id "username" :name "username" :type "input" :label "Username"}
+                         {:id "password" :name "password" :type "password" :label "password"}
+                         ]
+                :uid "username"})
         (s/validate new-login-form-schema)
         map->LoginForm)
    [:user-domain :session-store]))


(ns cylon.impl.login-form
  (:require
   [com.stuartsierra.component :as component]
   [bidi.bidi :refer (path-for ->WrapMiddleware)]
   [hiccup.core :refer (html)]
   [schema.core :as s]
   [clojure.tools.logging :refer :all]
   [ring.middleware.cookies :refer (wrap-cookies)]
   [cylon.user :refer (UserDomain verify-user)]
   [cylon.session :refer (SessionStore start-session! end-session!)]
   [ring.middleware.params :refer (wrap-params)]
   [modular.bidi :refer (WebService)]
   [clojure.tools.logging :refer :all]))

(defprotocol LoginFormRenderer
  (render-login-form [_ request requested-uri action login-status]))

(defrecord PlainLoginFormRenderer []
  LoginFormRenderer
  (render-login-form [_ request requested-uri action login-status]
    (html
     [:body
      [:form {:method "POST" :style "border: 1px dotted #555"
              :action action}
       (when (not-empty requested-uri)
         [:input {:type "hidden" :name :requested-uri :value requested-uri}])
       [:div
        [:label {:for "username"} "Username"]
        [:input {:id "username" :name "username" :type "input"}]]
       [:div
        [:label {:for "password"} "Password"]
        [:input {:id "password" :name "password" :type "password"}]]
       [:input {:type "submit" :value "Login"}]
       ]])))

(defn new-plain-login-form-renderer []
  (->PlainLoginFormRenderer))

(defn new-login-post-handler [& {:keys [user-domain session-store] :as opts}]
  (s/validate {:user-domain (s/protocol UserDomain)
               :session-store (s/protocol SessionStore)}
              opts)
  (fn [{{username "username" password "password" requested-uri "requested-uri"} :form-params
        routes :modular.bidi/routes}]

    (if (and username
             (not-empty username)
             (verify-user user-domain (.trim username) password))

      {:status 302
       :headers {"Location" (or requested-uri "/")} ; "/" can be parameterized (TODO)
       :cookies {"session" (start-session! session-store username)
                 "requested-uri" ""}}

      ;; Return back to login form
      {:status 302
       :headers {"Location" (path-for routes :login)}
       :cookies {"login-status" "failed"}})))

(defn new-logout-handler [session-store]
  (fn [{:keys [cookies]}]

  {(s/optional-key :uri-context) s/Str
   (s/optional-key :renderer) (s/protocol LoginFormRenderer)
   (s/optional-key :middleware) (s/=> 1)
   (s/required-key :uid) s/Str
   (s/required-key :fields) [{(s/optional-key :id) s/Str
                              (s/required-key :name) s/Str
                              (s/required-key :type) s/Str
                              (s/optional-key :label) s/Str
                              (s/optional-key :placeholder) s/Str
                              (s/optional-key :required) s/Bool}]
   })

(defn new-login-form [& {:as opts}]
