content: -- | Provide help for plugins
  module Lambdabot.Plugin.Core.Help (helpPlugin) where
  
  import Lambdabot.Command
  import Lambdabot.Message (Message)
  import Lambdabot.Module
  import Lambdabot.Monad
  import Lambdabot.Plugin
  import Lambdabot.Util
  
  import Control.Monad.Reader
  
  helpPlugin :: Module ()
  helpPlugin = newModule
      { moduleCmds = return
          [ (command "help")
              { help = say "help <command>. Ask for help for <command>. Try 'list' for all commands"
              , process = \args -> withMsg $ \msg -> do
                  tgt <- getTarget
                  lb (doHelp msg tgt args) >>= mapM_ say
              }
          ]
      }
  
  moduleHelp :: (Monad m, Message a) =>
                Command m -> a -> Nick -> String -> m [String]
  moduleHelp theCmd msg tgt cmd =
      execCmd (help theCmd) msg tgt cmd
  
  --
  -- If a target is a command, find the associated help, otherwise if it's
  -- a module, return a list of commands that module implements.
  --
  doHelp :: Message t => t -> Nick -> [Char] -> LB [[Char]]
  doHelp msg tgt [] = doHelp msg tgt "help"
  doHelp msg tgt rest =
      withCommand arg                  -- see if it is a command
          (inModuleNamed arg           -- else maybe it's a module name
              (doHelp msg tgt "help")             -- else give up
              (do -- its a module
                  cmds <- moduleCmds =<< asks theModule
                  let ss = cmds >>= cmdNames
                  let s | null ss   = arg ++ " is a module."
                        | otherwise = arg ++ " provides: " ++ showClean ss
                  return [s]))
  
          -- so it's a valid command, try to find its help
          (\theCmd -> moduleHelp theCmd msg tgt arg)
  
      where (arg:_) = words rest
  