module Text.HTML.DOM.Form
  ( form
  -- | Attributes and values selected for submission
  , submission
  , submitButtons
  -- ** Element filters
  -- *** Submit buttons
  , submit
  , submitImage
  , imageSubmit
  -- *** Input fields
  , input
  , hidden
  , password
  , inputtext
  , textarea
  -- *** Single and multiple selection lists
  , select
  , option
  -- *** Radio buttons
  , radio
  -- *** Checkboxes
  , checkbox
  -- *** File dialogs
  , file
  -- ** Attributes
  -- *** Name and value
  , name
  , value
  , nameValue
  , nameMaybeValue
  , valueOrContent
  -- *** Attribute filters
  , post
  , readonly
  , disabled
  , multiple
  , selected
  , checked
  ) where

import Data.String ( fromString )
import Data.Text as Text ( Text, concat )

import Text.XML.Cursor
  ( Cursor
  , Axis
  , content
  , child
  , descendant
  )
import Text.XML.Cursor.CaseInsensitive
  ( element
  , attribute
  , hasAttribute
  , attributeIs
  )

form :: Axis
form = element "form"

submission :: Cursor -> [(Text, Text)]
submission c = hiddens
            ++ passwords
            ++ inputtexts
            ++ textareas
            ++ selects
            ++ radios
            ++ checkboxes
  where source = descendant c
        hiddens = source >>= hidden >>= nameMaybeValue
        passwords = source >>= password >>= nameMaybeValue
        inputtexts = source >>= inputtext >>= nameMaybeValue
        textareas = do
          ta <- source >>= textarea
          name <- name ta
          let value = Text.concat (child ta >>= content)
          return (name, value)
        selects = do
          sel <- source >>= select
          name <- name sel
          value <- child sel >>= option >>= selected >>= valueOrContent
          return (name, value)
        radios = source >>= radio >>= checked >>= nameValue
        checkboxes = source >>= checkbox >>= checked >>= nameValue

submitButtons :: Cursor -> [(Text, Text)]
submitButtons c  = submits
                ++ submitImages
                ++ imageSubmits
  where source = descendant c
        submits = source >>= submit >>= nameValue
        submitImages = source >>= submitImage >>= nameValue
        imageSubmits = source >>= imageSubmit >>= nameValue

submit :: Axis
submit c = input c >>= attributeIs "type" "submit"

submitImage :: Axis
submitImage c = input c >>= attributeIs "type" "image"

imageSubmit :: Axis
imageSubmit c = element "image" c >>= attributeIs "type" "submit"

input :: Axis
input = element "input"

hidden :: Axis
hidden c = input c >>= attributeIs "type" "hidden"

password :: Axis
password c = input c >>= attributeIs "type" "password"

inputtext :: Axis
inputtext c = input c >>= attributeIs "type" "text"

textarea :: Axis
textarea = element "textarea"

select :: Axis
select = element "select"

option :: Axis
option = element "option"

radio :: Axis
radio c = input c >>= attributeIs "type" "radio"

checkbox :: Axis
checkbox c = input c >>= attributeIs "type" "checkbox"

file :: Axis
file c = input c >>= attributeIs "type" "file"

name :: Cursor -> [Text]
name = attribute "name"

value :: Cursor -> [Text]
value = attribute "value"

nameValue :: Cursor -> [(Text, Text)]
nameValue c = do
  name  <- name c
  value <- value c
  return (name, value)

nameMaybeValue :: Cursor -> [(Text, Text)]
nameMaybeValue c
  | nv == []  = (flip (,) (fromString "")) `fmap` name c
  | otherwise = nv
  where nv = nameValue c

valueOrContent :: Cursor -> [Text]
valueOrContent c
  | values /= []  = values
  | otherwise     = contents
  where values = value c
        contents = [Text.concat (child c >>= content)]

post :: Axis
post = attributeIs "method" "post"

readonly :: Axis
readonly = hasAttribute "readonly"

disabled :: Axis
disabled = hasAttribute "disabled"

multiple :: Axis
multiple = hasAttribute "multiple"

selected :: Axis
selected = hasAttribute "selected"

checked :: Axis
checked = hasAttribute "checked"

-- vim: ft=haskell:sts=2:sw=2:et:nu:ai
