{-# LANGUAGE
NamedFieldPuns
, OverloadedStrings
, ScopedTypeVariables
, LambdaCase
, TypeFamilies
#-}
module Ditto.Generalized.Internal where
import Control.Monad.State.Class (get)
import Control.Monad.Trans (lift)
import Data.List (find)
import Data.List.NonEmpty (NonEmpty(..))
import Data.Traversable (for)
import Ditto.Backend
import Ditto.Core
import Ditto.Types
input :: forall m input err a view. (Environment m input, FormError input err)
=> FormState m FormId
-> (input -> Either err a)
-> (FormId -> a -> view)
-> a
-> Form m input err view a
input formSId fromInput toView initialValue =
Form (pure . fromInput) (pure initialValue) $ do
i <- formSId
v <- getFormInput' i
case v of
Default -> pure
( View $ const $ toView i initialValue
, Ok $ Proved
{ pos = unitRange i
, unProved = initialValue
}
)
Found inp -> case fromInput inp of
Right a -> pure
( View $ const $ toView i a
, Ok $ Proved
{ pos = unitRange i
, unProved = a
}
)
Left err -> pure
( View $ const $ toView i initialValue
, Error [(unitRange i, err)]
)
Missing -> pure
( View $ const $ toView i initialValue
, Error [(unitRange i, commonFormError (InputMissing i :: CommonFormError input) :: err)]
)
inputList :: forall m input err a view view'. (Monad m, FormError input err, Environment m input)
=> FormState m FormId
-> (input -> m (Either err [a]))
-> ([view] -> view')
-> [a]
-> view'
-> (a -> Form m input err view a)
-> Form m input err view' [a]
inputList formSId fromInput viewCat initialValue defView createForm =
Form fromInput (pure initialValue) $ do
i <- formSId
v <- getFormInput' i
case v of
Default -> do
let ivs' = case initialValue of
[] -> []
_ -> initialValue
views <- for ivs' $ \x -> do
(View viewF, _) <- formFormlet $ createForm x
pure $ viewF []
pure
( View $ const $ viewCat views
, Ok $ Proved
{ pos = unitRange i
, unProved = ivs'
}
)
Found inp -> lift (fromInput inp) >>= \case
Right xs -> do
views <- for xs $ \x -> do
(View viewF, _) <- formFormlet $ createForm x
pure $ viewF []
pure
( View $ const $ viewCat views
, Ok $ Proved
{ pos = unitRange i
, unProved = xs
}
)
Left err -> do
let err' = [(unitRange i, err)]
views <- for initialValue $ \x -> do
(View viewF, _) <- formFormlet $ createForm x
pure $ viewF err'
pure
( View $ const $ viewCat views
, Error err'
)
Missing -> do
pure
( View $ const defView
, Ok $ Proved
{ pos = unitRange i
, unProved = []
}
)
inputMaybe :: (Monad m, FormError input err, Environment m input)
=> FormState m FormId
-> (input -> Either err a)
-> (FormId -> Maybe a -> view)
-> Maybe a
-> Form m input err view (Maybe a)
inputMaybe i' fromInput toView initialValue =
Form (pure . fmap Just . fromInput) (pure initialValue) $ do
i <- i'
v <- getFormInput' i
case v of
Default -> pure
( View $ const $ toView i initialValue
, Ok ( Proved
{ pos = unitRange i
, unProved = initialValue
})
)
Found x -> case fromInput x of
Right a -> pure
( View $ const $ toView i (Just a)
, Ok $ Proved
{ pos = unitRange i
, unProved = (Just a)
}
)
Left err -> pure
( View $ const $ toView i initialValue
, Error [(unitRange i, err)]
)
Missing -> pure
( View $ const $ toView i initialValue
, Ok $ Proved
{ pos = unitRange i
, unProved = Nothing
}
)
inputNoData :: (Monad m)
=> FormState m FormId
-> (FormId -> view)
-> Form m input err view ()
inputNoData i' toView =
Form (successDecode ()) (pure ()) $ do
i <- i'
pure
( View $ const $ toView i
, Ok ( Proved
{ pos = unitRange i
, unProved = ()
})
)
inputFile :: forall m ft input err view. (Monad m, FormInput input, FormError input err, Environment m input, ft ~ FileType input, Monoid ft)
=> FormState m FormId
-> (FormId -> view)
-> Form m input err view (FileType input)
inputFile i' toView =
Form (pure . getInputFile') (pure mempty) $ do
i <- i'
v <- getFormInput' i
case v of
Default ->
pure
( View $ const $ toView i
, Error [(unitRange i, commonFormError (InputMissing i :: CommonFormError input) :: err)]
)
Found x -> case getInputFile' x of
Right a -> pure
( View $ const $ toView i
, Ok ( Proved
{ pos = unitRange i
, unProved = a
})
)
Left err -> pure
( View $ const $ toView i
, Error [(unitRange i, err)]
)
Missing ->
pure
( View $ const $ toView i
, Error [(unitRange i, commonFormError (InputMissing i :: CommonFormError input) ::err)]
)
where
getInputFile' :: (FormError input err) => input -> Either err (FileType input)
getInputFile' = getInputFile
inputMulti :: forall m input err view a lbl. (FormError input err, FormInput input, Environment m input, Eq a)
=> FormState m FormId
-> [(a, lbl)]
-> (input -> Either err [a])
-> (FormId -> [Choice lbl a] -> view)
-> (a -> Bool)
-> Form m input err view [a]
inputMulti i' choices fromInput mkView isSelected =
Form (pure . fromInput) (pure $ map fst choices) $ do
i <- i'
inp <- getFormInput' i
case inp of
Default -> do
let (choices', vals) =
foldr
( \(a, lbl) (cs, vs) ->
if isSelected a
then ((a, lbl, True) : cs, a : vs)
else ((a, lbl, False) : cs, vs)
)
([], [])
choices
view' <- mkView i <$> augmentChoices choices'
mkOk i view' vals
Missing -> do
view' <- mkView i <$> augmentChoices (map (\(x, y) -> (x, y, False)) choices)
mkOk i view' []
Found v -> do
let keys = either (const []) id $ fromInput v
(choices', vals) =
foldr
( \(a, lbl) (c, v0) ->
if a `elem` keys
then ((a, lbl, True) : c, a : v0)
else ((a, lbl, False) : c, v0)
)
([], []) $
choices
view' <- mkView i <$> augmentChoices choices'
mkOk i view' vals
where
augmentChoices :: (Monad m) => [(a, lbl, Bool)] -> FormState m [Choice lbl a]
augmentChoices choices' = mapM augmentChoice choices'
augmentChoice :: (Monad m) => (a, lbl, Bool) -> FormState m (Choice lbl a)
augmentChoice (a, lbl, selected) = do
i <- i'
pure $ Choice i lbl selected a
data Choice lbl a = Choice
{ choiceFormId :: FormId
, choiceLabel :: lbl
, choiceIsSelected :: Bool
, choiceVal :: a
}
inputChoice :: forall a m err input lbl view. (FormError input err, FormInput input, Monad m, Eq a, Monoid view, Environment m input)
=> FormState m FormId
-> (a -> Bool)
-> NonEmpty (a, lbl)
-> (input -> Either err a)
-> (FormId -> [Choice lbl a] -> view)
-> Form m input err view a
inputChoice i' isDefault choices@(headChoice :| _) fromInput mkView = do
let f = case find isDefault (fmap fst choices) of
Nothing -> Form (pure . fromInput) (pure $ fst headChoice)
Just defChoice -> Form (pure . fromInput) (pure defChoice)
f $ do
i <- i'
inp <- getFormInput' i
case inp of
Default -> do
let (choices', def) = markSelected choices
view' <- mkView i <$> augmentChoices choices'
mkOk' i view' def
Missing -> do
let (choices', def) = markSelected choices
view' <- mkView i <$> augmentChoices choices'
mkOk' i view' def
Found v -> do
case fromInput v of
Left err -> do
let choices' =
foldr
( \(a, lbl) c -> (a, lbl, False) : c )
[]
choices
view' <- mkView i <$> augmentChoices choices'
pure
( View $ const view'
, Error [(unitRange i, err)]
)
Right key -> do
let (choices', mval) =
foldr
( \(a, lbl) (c, v0) ->
if key == a
then ((a, lbl, True) : c, Just a)
else ((a, lbl, False) : c, v0)
)
([], Nothing) $
choices
view' <- mkView i <$> augmentChoices choices'
case mval of
Nothing -> pure
( View $ const view'
, Error [(unitRange i, commonFormError (InputMissing i :: CommonFormError input) :: err)]
)
Just val -> mkOk i view' val
where
mkOk' i view' (Just val) = mkOk i view' val
mkOk' i view' Nothing =
pure
( View $ const $ view'
, Error [(unitRange i, commonFormError (MissingDefaultValue :: CommonFormError input) :: err)]
)
markSelected :: Foldable f => f (a, lbl) -> ([(a, lbl, Bool)], Maybe a)
markSelected cs =
foldr
( \(a, lbl) (vs, ma) ->
if isDefault a
then ((a, lbl, True) : vs, Just a)
else ((a, lbl, False) : vs, ma)
)
([], Nothing)
cs
augmentChoices :: (Monad m) => [(a, lbl, Bool)] -> FormState m [Choice lbl a]
augmentChoices choices' = mapM augmentChoice choices'
augmentChoice :: (Monad m) => (a, lbl, Bool) -> FormState m (Choice lbl a)
augmentChoice (a, lbl, selected) = do
i <- i'
pure $ Choice i lbl selected a
label :: Monad m
=> FormState m FormId
-> (FormId -> view)
-> Form m input err view ()
label i' f = Form (successDecode ()) (pure ()) $ do
id' <- i'
pure
( View (const $ f id')
, ( Ok $ Proved
{ pos = unitRange id'
, unProved = ()
}
)
)
errors :: Monad m
=> ([err] -> view)
-> Form m input err view ()
errors f = Form (successDecode ()) (pure ()) $ do
range <- get
pure
( View (f . retainErrors range)
, ( Ok $ Proved
{ pos = range
, unProved = ()
}
)
)
childErrors :: Monad m
=> ([err] -> view)
-> Form m input err view ()
childErrors f = Form (successDecode ()) (pure ()) $ do
range <- get
pure
( View (f . retainChildErrors range)
, ( Ok $ Proved
{ pos = range
, unProved = ()
}
)
)
withChildErrors :: Monad m
=> (view -> [err] -> view)
-> Form m input err view a
-> Form m input err view a
withChildErrors f Form{formDecodeInput, formInitialValue, formFormlet} = Form formDecodeInput formInitialValue $ do
(View v, r) <- formFormlet
range <- get
pure
( View $ \x ->
let errs = retainChildErrors range x
in f (v x) errs
, r
)
withErrors :: Monad m
=> (view -> [err] -> view)
-> Form m input err view a
-> Form m input err view a
withErrors f Form{formDecodeInput, formInitialValue, formFormlet} = Form formDecodeInput formInitialValue $ do
(View v, r) <- formFormlet
range <- get
pure
( View $ \x ->
let errs = retainErrors range x
in f (v x) errs
, r
)