module Hsbot.Irc.Config
    ( IrcConfig(..)
    , ircDefaultConfig
    , getIrcConfig
    ) where

import qualified Data.ConfigFile as C
import Data.Either.Utils
import Network
import System.Exit
import System.Posix.Files

-- | Configuration data type
data IrcConfig = IrcConfig
    { ircConfigAddress       :: String   -- the server's address
    , ircConfigPort          :: PortID   -- the server's port
    , ircConfigChannels      :: [String] -- the Channels to join on start
    , ircConfigNickname      :: String   -- the hsbot's nickname
    , ircConfigPassword      :: String   -- the hsbot's password, optional
    , ircConfigRealname      :: String   -- the hsbot's real name, optional
    , ircConfigCommandPrefix :: Char     -- the prefix the ircbot will recognize as commands
    , ircConfigPlugins       :: [String] -- the ircPlugins to load
    }

instance Show IrcConfig where
    show (IrcConfig address port channels nickname password realname commandPrefix plugins) = unlines $
        concat [ "Address: ", address ] :
        concat [ "Port: ", case port of
                            PortNumber num -> show num
                            Service s      -> show s
                            UnixSocket u   -> show u ] :
        concat [ "Channels: ", show channels ] :
        concat [ "Nickname: ", nickname ] :
        concat [ "Password: ", password ] :
        concat [ "Realname: ", realname ] :
        concat [ "CommandPrefix: ", show commandPrefix ] :
        [ "Plugins: ", show plugins ]

-- | User configuration
ircDefaultConfig :: IrcConfig
ircDefaultConfig = IrcConfig
    { ircConfigAddress       = "localhost"
    , ircConfigPort          = PortNumber 6667
    , ircConfigChannels      = ["#hsbot"]
    , ircConfigNickname      = "hsbot"
    , ircConfigPassword      = ""
    , ircConfigRealname      = "The One True bot, with it's haskell soul."
    , ircConfigCommandPrefix = '@'
    , ircConfigPlugins       = ["Ping"]
    }

-- | config file retrieving
getIrcConfig :: Maybe String -> IO (IrcConfig)
getIrcConfig maybePath =
    case maybePath of
        Just path -> do
            doesFileExists <- fileExist path
            case doesFileExists of
                True -> do
                    fileStatus <- getFileStatus path
                    case isRegularFile $ fileStatus of
                        True -> compileIrcConfig ircDefaultConfig path
                        False -> do
                            putStrLn "Invalid configuration file path."
                            exitWith $ ExitFailure 1
                False -> do
                    putStrLn "The specified configuration file does not exists."
                    exitWith $ ExitFailure 1
        Nothing -> return ircDefaultConfig  -- TODO : try defaults like $HOME/.hsbotrc, /etc/hsbotrc or /usr/local/etc/hsbotrc

-- | config file parsing
compileIrcConfig :: IrcConfig -> String -> IO (IrcConfig)
compileIrcConfig ircConfig path = do
    val <- C.readfile C.emptyCP path
    let cp = forceEither val
    let address = case C.get cp "IRC" "address" of
         Right this -> this
         Left _ -> ircConfigAddress ircConfig
    let port = case C.get cp "IRC" "port" of
         Right this -> PortNumber $ fromIntegral (read this :: Int) -- TODO error handling
         Left _ -> ircConfigPort ircConfig
    let channels = case C.get cp "IRC" "channels" of
         Right this -> map (lstrip ' ') (split this ',')
         Left _ -> ircConfigChannels ircConfig
    let nickname = case C.get cp "IRC" "nickname" of
         Right this -> this
         Left _ -> ircConfigNickname ircConfig
    let password = case C.get cp "IRC" "password" of
         Right this -> this
         Left _ -> ircConfigPassword ircConfig
    let realname = case C.get cp "IRC" "realname" of
         Right this -> this
         Left _ -> ircConfigRealname ircConfig
    let commandPrefix = case C.get cp "IRC" "commandPrefix" of
         Right this -> head this -- TODO error handling
         Left _ -> ircConfigCommandPrefix ircConfig
    let plugins = case C.get cp "IRC" "plugins" of
         Right this -> map (lstrip ' ') (split this ',')
         Left _ -> ircConfigPlugins ircConfig
    return ircConfig { ircConfigAddress       = address
                     , ircConfigPort          = port
                     , ircConfigChannels      = channels
                     , ircConfigNickname      = nickname
                     , ircConfigPassword      = password
                     , ircConfigRealname      = realname
                     , ircConfigCommandPrefix = commandPrefix
                     , ircConfigPlugins       = plugins }
  where
    split :: String -> Char -> [String]
    split [] _ = [""]
    split (c:cs) delim
       | c == delim = "" : rest
       | otherwise = (c : head rest) : tail rest
      where rest = split cs delim
    lstrip :: Char -> String -> String
    lstrip x (c:cs) = if (x == c) then (lstrip x cs) else c:(lstrip x cs)
    lstrip _ [] = []