-- | This is the logger module, it logs both IRC messages and activities
-- the bot performs such as plugin invocation, recompilation, etc.. It logs
-- these things into the /Log\// directory and names the file by
-- date in the form /month-day-year/, and irc messages are stored
-- in files under /Log\/irc\// in the form 
-- /Log\/irc\/server\/channel\/date\//.
--
-- Plugin logs are stored in the same convention as regular logs inside
-- \"Log\", but they have the suffix of '.plugin' attached.
module Infinity.Log (
 Status(..),
 logs,
 plog, mlog,
 irclog
) where
import qualified Control.Exception as Ex
import Control.Concurrent.STM
import System.IO.Unsafe
import System.Directory
import System.FilePath
import Infinity.Util
import Control.Monad
import Text.Printf
import System.Time
import Data.List

logd :: String
logd = "Log"
ircd :: String
ircd = "Log" </> "irc"

-- kludge :/
loglock :: TMVar Bool
loglock = unsafePerformIO newEmptyTMVarIO

ploglock :: TMVar Bool
ploglock = unsafePerformIO newEmptyTMVarIO

-- | These are the log status codes all log functions must give
-- to indicate the nature of the log
data Status
    = Normal 
    | Error
 deriving (Show,Eq)

-- | The general logger function, which will log to the appropriate
-- file inside Log/
logs :: Status -> String -> IO ()
logs stat str = do
  outstr <- mkoutstr stat str
  date   <- mkdate

  putStr outstr
  atomically $ putTMVar loglock True
  write (logd </> date) outstr
  atomically $ takeTMVar loglock
  return ()

-- | Function the monitor thread uses to log
mlog :: Status -> String -> IO ()
mlog stat str = do
  outstr <- mkoutstr stat ("[MONITOR]   "++str)
  date   <- mkdate

  putStr outstr
  atomically $ putTMVar loglock True
  write (logd </> date) outstr
  atomically $ takeTMVar loglock
  return ()

-- | This is the plugin logger function that all plugins should use to
-- log to files.
plog :: Status -> String -> IO ()
plog stat str = do
  outstr <- mkoutstr stat str
  date   <- mkdate

  putStr outstr
  atomically $ putTMVar ploglock True
  write (logd </> (date++".plugins")) outstr
  atomically $ takeTMVar ploglock
  return ()

-- | This logs lines that get sent in over IRC
irclog :: String -> (String,String,String) -> IO ()
irclog server (user,chan,str) = do
  unless (null str) $ do
    time <- mktime
    date <- mkdate
    let dirs = [ ircd,
                 joinPath [ircd,server], 
                 joinPath [ircd,server,chan] ]
        file = (joinPath [ircd,server,chan,date])
        s    = unwords [time,"::",("<"++user++">"),str]
    mapM_ mkdir dirs
    write file (printf "%s\n" s :: String)



-- convenience functions
write :: FilePath -> String -> IO ()
write f str = do
  b <- doesFileExist f
  let g = if b then appendFile else writeFile
  Prelude.catch (g f str) (\_ -> return ())

mkoutstr :: Status -> String -> IO String
mkoutstr stat str = do
  time <- liftM calendarTimeToString $ getClockTime >>= toCalendarTime
  let outstr = printf "%s[%s]:\t\t%s\n" (show stat) time str :: String
  return outstr
