module Eval ( eval )
where

  import Control.Monad.IO.Class (liftIO)
  import Data.Set               (fromList, toList, union, intersection, difference)

  import API
  import Monad
  import Types

  eval :: Comm -> StateError ()
  eval comm = do st <- get
                 s  <- liftIO $ runStateError (evalComm comm) st 
                 case s of
                   Left err      -> liftIO $ printError err 
                   Right (_,st') -> put st' 
  

  evalComm :: Comm -> StateError ()
  evalComm (Seq a b) = do evalComm a
                          evalComm b
  evalComm (Def name l) = do fl <- evalList l
                             update name fl
  evalComm (Add name l) = do l'  <- evalList (Var name)
                             l'' <- evalList l
                             update name (toList (fromList l' `union` fromList l''))
  evalComm (Rem name l) = do l'  <- evalList (Var name)
                             l'' <- evalList l
                             update name (toList (fromList l' `difference` fromList l''))


  evalList :: FList -> StateError [Film]
  evalList (New p) = do let params = genRequest p
                        fl <- liftIO (getResponse params)
                        case fl of
                          [] -> throw BadParams
                          _  -> return fl
  evalList (Var n) = do fl <- lookfor n
                        case fl of
                          [] -> throw (Undef n)
                          _  -> return fl
  evalList (And l l') = do fl  <- evalList l
                           fl' <- evalList l'
                           return (toList (fromList fl `intersection` fromList fl'))


  printError :: Error -> IO ()
  printError BadParams = putStrLn "Ninguna película satisface esos parámetros"
  printError (Undef n) = putStrLn ("La lista " ++ n ++ " no está definida.")
