{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ViewPatterns #-}

-- | Validating indexed formlet with auto-generated input names.

module Descriptive.Formlet
  (-- * Combinators
   indexed
  ,FormletState(..)
  -- * Description
  ,Formlet(..))
  where

import           Descriptive

import           Control.Monad.State.Strict
import           Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import           Data.Text (Text)

-- | Description of a formlet.
data Formlet
  = Index !Integer
  | Constrained !Text
  deriving (Show,Eq)

-- | State used when running a formlet.
data FormletState =
  FormletState {formletMap :: (Map Integer Text)
               ,formletIndex :: !Integer}
  deriving (Show,Eq)

-- | Consume any character.
indexed :: Monad m => Consumer FormletState Formlet m Text
indexed =
  consumer (do i <- nextIndex
               return (d i))
           (do i <- nextIndex
               s <- get
               return (case M.lookup i (formletMap s) of
                         Nothing -> Failed (d i)
                         Just a -> Succeeded a))
  where d = Unit . Index
        nextIndex :: MonadState FormletState m => m Integer
        nextIndex =
          do i <- gets formletIndex
             modify (\s ->
                       s {formletIndex = formletIndex s + 1})
             return i
