module Validations.Validator
  ( attach
  , attachM
  , Validator(..)
  , composeValidator
  ) 
    where

import Validations.Types.Checker(Checker, MonadicChecker)
import Control.Category(Category(..))

attach :: (Monad m) => Checker ev a b -> ek -> Validator ek ev m a b
attach validator fieldName = Validator $ \x -> case (validator x) of
  Right x' -> return $ Right x'
  Left  e   -> return $ Left (fieldName, e)

attachM :: (Monad m) => MonadicChecker ev m a b -> ek -> Validator ek ev m a b
attachM validator fieldName = Validator $ \x -> validator x >>= \y -> case y of
  Right y' -> return $ Right y'
  Left  e   -> return $ Left (fieldName, e)

newtype Validator errorKey errorValue monad a b  = Validator { runValidator :: a -> monad (Either (errorKey, errorValue) b) }

instance (Monad m) => Category (Validator ek ev m) where
  id = Validator (\x -> return (Right x))
  y . x = composeValidator x y


composeValidator :: (Monad m) => Validator ek ev m a b -> Validator ek ev m b c -> Validator ek ev m a c
composeValidator (Validator f) (Validator g) = Validator $ (\a -> f a >>= \rb -> case rb of
  Right b     -> g b
  Left   (fn,e) -> return (Left (fn, e)))