{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies, TemplateHaskell #-}

module Chatty.Interactor where

import Chatty.Printer
import Chatty.Scanner
import Chatty.Finalizer
import Chatty.Expansion
import Chatty.Extended.HTML
import Chatty.Extended.ANSI
import Chatty.Misc
import Chatty.Interactor.Templates
import Chatty.Spawn
import Chatty.Spawn.Overlay
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Identity

mkInteractor ''RecorderT mkScanner mkFinalizer mkExpander mkSpawn mkRandom mkClock
mkInteractor ''DeafT mkScanner mkFinalizer mkExpander mkSpawn mkRandom mkClock
mkInteractor ''OutRedirT mkScanner mkFinalizer mkExpander mkSpawn mkRandom mkClock
mkInteractor ''HandleCloserT mkScanner mkPrinter mkExpander mkSpawn mkRandom mkClock
mkInteractor ''ExpanderT mkScanner mkPrinter mkFinalizer mkSpawn mkRandom mkClock
mkInteractor ''HereStringT mkPrinter mkExpander mkSpawn mkRandom mkClock
mkInteractor ''QuietT mkPrinter mkExpander mkSpawn mkRandom mkClock
mkInteractor ''InRedirT mkPrinter mkExpander mkSpawn mkRandom mkClock
mkInteractor ''SpawnOverlayT mkPrinter mkScanner mkExpander mkFinalizer mkRandom mkClock
mkInteractor ''HtmlPrinterT mkScanner mkExpander mkFinalizer mkSpawn mkRandom mkClock
mkInteractor ''AnsiPrinterT mkScanner mkExpander mkFinalizer mkSpawn mkRandom mkClock

type IgnorantT m = QuietT (DeafT m)
type Ignorant = IgnorantT Identity
type ChattyT m = HereStringT (RecorderT m)
type Chatty = ChattyT Identity

runIgnorantT :: Monad m => IgnorantT m a -> m a
runIgnorantT = runDeafT . runQuietT

runIgnorant :: Ignorant a -> a
runIgnorant = runIdentity . runIgnorantT

runChattyT :: (Monad m,Functor m) => ChattyT m a -> String -> m (a,String,Replayable)
runChattyT m input = fmap (\((a,u),r) -> (a,u,r)) $ runRecorderT $ runHereStringT m input

runChatty :: Chatty a -> String -> (a,String,Replayable)
runChatty m = runIdentity . runChattyT m

-- Shell-like syntax
(.|.) :: (Monad m,Functor m) => RecorderT m a -> HereStringT m b -> m b
m1 .|. m2 = do
  (_,r) <- runRecorderT m1
  fmap fst $ runHereStringT m2 (replay r)

(.<$.) :: (Functor m,Monad m) => (String -> m b) -> RecorderT m a -> m b
m1 .<$. m2 = do
  (_,r) <- runRecorderT m2
  m1 $ replay r