content: --------------------------------------------------------------------------------
  {-# LANGUAGE GADTs #-}
  -- | Provides a datatype to differentiate between regular urlencoding and
  -- multipart encoding for the content of forms and functions to determine
  -- the content types of forms.
  module Text.Digestive.Form.Encoding
      ( FormEncType (..)
      , formTreeEncType
      ) where
  
  
  --------------------------------------------------------------------------------
  import           Control.Monad.Identity             (Identity)
  import           Data.Maybe                         (mapMaybe)
  import           Data.Monoid                        (Monoid (..), mconcat)
  import           Data.Semigroup                     (Semigroup (..))
  
  
  --------------------------------------------------------------------------------
  import           Text.Digestive.Form.Internal
  import           Text.Digestive.Form.Internal.Field
  
  
  --------------------------------------------------------------------------------
  -- | Content type encoding of the form, either url encoded
  -- (percent-encoding) or multipart encoding. For details, see:
  -- <http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4>
  data FormEncType
      = UrlEncoded
      | MultiPart
      deriving (Eq)
  
  
  --------------------------------------------------------------------------------
  instance Show FormEncType where
      show UrlEncoded = "application/x-www-form-urlencoded"
      show MultiPart  = "multipart/form-data"
  
  
  --------------------------------------------------------------------------------
  -- Semigroup instance for encoding types: prefer UrlEncoded, but fallback to
  -- MultiPart when needed
  instance Semigroup FormEncType where
      UrlEncoded <> x = x
      MultiPart  <> _ = MultiPart
  
  
  --------------------------------------------------------------------------------
  -- Monoid instance for encoding types: prefer UrlEncoded, but fallback to
  -- MultiPart when needed
  instance Monoid FormEncType where
      mempty  = UrlEncoded
      mappend = (<>)
  
  
  --------------------------------------------------------------------------------
  -- Only file uploads require the multipart encoding
  fieldEncType :: Field v a -> FormEncType
  fieldEncType File = MultiPart
  fieldEncType _    = UrlEncoded
  
  
  --------------------------------------------------------------------------------
  -- Retrieves all fields from a form tree
  fieldList :: FormTree Identity v m a -> [SomeField v]
  fieldList = mapMaybe toField' . fieldList' . SomeForm
    where
      fieldList' (SomeForm f) = SomeForm f : concatMap fieldList' (children f)
      toField' (SomeForm f)   = toField f
  
  
  --------------------------------------------------------------------------------
  -- | Determines the encoding type of a "FormTree"
  formTreeEncType :: FormTree Identity v m a -> FormEncType
  formTreeEncType = mconcat . map fieldEncType' . fieldList
    where
      fieldEncType' (SomeField f) = fieldEncType f
  