content: -- |
  -- Module    : Where
  -- Copyright : 2003 Shae Erisson
  --
  -- License:     lGPL
  --
  -- Slightly specialised version of Where for associating projects with their urls.
  -- Code almost all copied.
  module Lambdabot.Plugin.Reference.Where (wherePlugin) where
  
  import Lambdabot.Plugin
  import Lambdabot.Util
  import qualified Data.ByteString.Char8 as P
  import Data.Char
  import qualified Data.Map as M
  
  type WhereState         = M.Map P.ByteString P.ByteString
  type WhereWriter        = WhereState -> Cmd Where ()
  type Where              = ModuleT WhereState LB
  
  wherePlugin :: Module (M.Map P.ByteString P.ByteString)
  wherePlugin = newModule
      { moduleDefState  = return M.empty
      , moduleSerialize = Just mapPackedSerial
  
      , moduleCmds = return
          [ (command "where")
              { help = say "where <key>. Return element associated with key"
              , process = doCmd "where"
              }
          , (command "url")
              { help = say "url <key>. Return element associated with key"
              , process = doCmd "url"
              }
          , (command "what")
              { help = say "what <key>. Return element associated with key"
              , process = doCmd "what"
              }
          , (command "where+")
              { help = say "where+ <key> <elem>. Define an association"
              , process = doCmd "where+"
              }
          ]
      }
  
  doCmd :: String -> String -> Cmd Where ()
  doCmd cmd rest = (say =<<) . withMS $ \factFM writer ->
      case words rest of
          []         -> return "@where <key>, return element associated with key"
          (fact:dat) -> processCommand factFM writer
                              (map toLower fact) cmd (unwords dat)
  
  ------------------------------------------------------------------------
  
  processCommand :: WhereState -> WhereWriter
                 -> String -> String -> String -> Cmd Where String
  
  processCommand factFM writer fact cmd dat = case cmd of
          "where"     -> return $ getWhere factFM fact
          "what"      -> return $ getWhere factFM fact -- an alias
          "url"       -> return $ getWhere factFM fact -- an alias
          "where+"    -> updateWhere True factFM writer fact dat
          _           -> return "Unknown command."
  
  getWhere :: WhereState -> String -> String
  getWhere fm fact =
      case M.lookup (P.pack fact) fm of
          Nothing -> "I know nothing about " ++ fact ++ "."
          Just x  -> P.unpack x
  
  updateWhere :: Bool -> WhereState -> WhereWriter -> String -> String -> Cmd Where String
  updateWhere _guard factFM writer fact dat
      | null dat = do
          writer $ M.delete (P.pack fact) factFM
          return "It is forgotten."
      | otherwise = do
          writer $ M.insert (P.pack fact) (P.pack dat) factFM
          randomSuccessMsg
  