module Text.Digestive.Validate
    ( Validator
    , validate
    , validateMany
    , check
    , checkM
    ) where
import Prelude hiding (id)
import Control.Monad (liftM2)
import Data.Monoid (Monoid (..))
import Control.Category (id)
import Text.Digestive.Types
import Text.Digestive.Transform
newtype Validator m e a = Validator {unValidator :: Transformer m e a a}
instance Monad m => Monoid (Validator m e a) where
    mempty = Validator id
    v1 `mappend` v2 = Validator $ Transformer $ \inp ->
        liftM2 eitherPlus (unTransformer (unValidator v1) inp)
                          (unTransformer (unValidator v2) inp)
      where
        eitherPlus (Left e) (Left i) = Left $ e ++ i
        eitherPlus (Left e) (Right _) = Left e
        eitherPlus (Right _) (Left e) = Left e
        eitherPlus (Right a) (Right _) = Right a
validate :: Monad m => Form m i e v a -> Validator m e a -> Form m i e v a
validate form = transform form . unValidator
validateMany :: Monad m => Form m i e v a -> [Validator m e a] -> Form m i e v a
validateMany form = validate form . mconcat
check :: Monad m
      => e                
      -> (a -> Bool)      
      -> Validator m e a  
check error' = checkM error' . (return .)
checkM :: Monad m
       => e                
       -> (a -> m Bool)    
       -> Validator m e a  
checkM error' f = Validator $ Transformer $ \x -> do
    valid <- f x
    return $ if valid then Right x else Left [error']