module Bot.Modules.Hooks
    ( defaultHooks
    , adjustHook
    , matches
    , execute
    ) where

import Bot.Core.Types
import Bot.Core.Base (io, reply)
import Bot.Modules.Records
import Interfaces.HTML (isHTML, titleHTML)

import Control.Monad.State (gets, when, modify)
import Text.Regex.Posix
import qualified Data.Map.Strict as Map

privmsg :: Predicate
privmsg = ((==) "PRIVMSG", msg)

userstate :: Predicate
userstate = (flip elem ["JOIN", "PART", "QUIT"], src)

defaultHooks = Map.fromList [
    ("seen",   Hook All                 privmsg   ".*" seenHook),
    ("http",   Hook (Not  ["#kitinfo"]) privmsg   "https?://\\S+" httpHook),
    ("kitbot", Hook (Only ["#kitinfo"]) userstate "Kitbot" kitbotHook)
    ]

-- |Enable or disable a hook in the given map.
adjustHook :: String -> HookMap -> Access -> HookMap
adjustHook k m a = Map.adjust (\s -> s { haccess = a }) k m

-- |Return "True" if a Packet matches a given Hook, "False" otherwise.
matches :: Hook -> Packet -> Bool
matches h p = ctype h (cmd p) && (chunk h p =~ regex h)
            where
                ctype = fst . predicate
                chunk = snd . predicate

-- |A convienence function that executes the "HookFunction" on a "Packet".
execute :: Hook -> Packet -> Bot ()
execute h = hook h (regex h)

seenHook r p = do
        rec <- io $ composeRecord p
        cs  <- gets chans
        let public = dst p `elem` cs in
            when public $ updateWith (dst p, src p) rec

httpHook r p = do
        valid <- io (isHTML s)
        when valid (io (titleHTML s) >>= reply p)
        where s = msg p =~ r :: String

kitbotHook r p = do
        hs <- gets hooks
        modify $ if cmd p == "JOIN" then
            \s -> s { hooks = adjustHook "http" hs (Not ["#kitinfo"]) } else
            \s -> s { hooks = adjustHook "http" hs All }
