# plugs/core.py
#
#

__copyright__ = 'this file is in the public domain'
__gendocskip__ = ['userhostcache', ]

from gozerbot.generic import getwho, die, reboot, elapsedstring, \
reboot_stateful, getversion
from gozerbot.exit import globalshutdown
from gozerbot.commands import cmnds
from gozerbot.examples import examples
from gozerbot.callbacks import callbacks
from gozerbot.redispatcher import rebefore, reafter
from gozerbot.plugins import plugins
from gozerbot.users import users
from gozerbot.partyline import partyline
from gozerbot.fleet import fleet
from gozerbot.config import config
from gozerbot.statdict import Statdict
from gozerbot.aliases import aliases, aliasreverse, aliasset
from gozerbot.partyline import partyline
from gozerbot.plughelp import plughelp
from gozerbot.eventhandler import mainhandler
from gozerbot.runner import cbrunners, cmndrunners
from sets import Set
import time, threading, sys, re

plughelp.add('core', 'core commands for the bot')

def handle_whatperms(bot, ievent):
    """ show possible permissions """
    ievent.reply("the following permission are available: ", \
plugins.whatperms())

cmnds.add('whatperms', handle_whatperms, ['USER', 'OPER', 'ANON'])
examples.add('whatperms', 'show what permissions are available', 'whatperms')

def handle_encoding(bot, ievent):
    """ show default encoding """
    ievent.reply('default encoding is %s' % sys.getdefaultencoding())

cmnds.add('encoding', handle_encoding, ['USER', 'OPER', 'ANON'])
examples.add('encoding', 'show default encoding', 'encoding')

def handle_uptime(bot, ievent):
    """ show uptime """
    ievent.reply("uptime is %s" % elapsedstring(time.time()-bot.starttime))

cmnds.add('uptime', handle_uptime, ['USER', 'WEB', 'JCOLL', 'ANON'])
examples.add('uptime', 'show uptime of the bot', 'uptime')
aliasset('up', 'uptime')

def handle_userhostcache(bot, ievent):
    """ show bots userhost cache """
    ievent.reply(str(bot.userhosts.data))

cmnds.add('userhostcache', handle_userhostcache, 'OPER')

def handle_list(bot, ievent):
    """ list [<plugin>] .. list loaded plugins or list commands provided by \
        plugin """
    try:
        what = ievent.args[0]
    except:
        # no arguments given .. show plugins
        ievent.reply('\002loaded plugins:\002 ', plugins.list())
        return
    # show commands of <what> plugin
    result = []
    for i, j in cmnds.items():
        if what == j.plugname:
            txt = ""
            alias = aliasreverse(i)
            if alias:
                txt += "%s (%s)" % (i, alias)
            else:
                txt = i
            if txt:
                result.append(txt)
    if result:
        result.sort()
        ievent.reply('%s has the following commands: ' % what, result)
    else:
        ievent.reply('no commands found for plugin %s' % what)

cmnds.add('list', handle_list, ['USER', 'WEB', 'ANON'], threaded=True)
examples.add('list', 'list registered plugins or list commands in \
plugin', '1) list 2) list rss')

def handle_available(bot, ievent):
    """ available .. show what plugins are available """
    l = Set(plugins.list())
    ondisk = Set(plugins.available())
    diff = list(ondisk - l)    
    diff.sort()
    ievent.reply('\002available plugins:\002 (reload to enable): ', diff)

cmnds.add('available', handle_available, ['USER', 'WEB', 'ANON'])
examples.add('available', 'show what plugins are available but not loaded \
(see the list command for loaded plugins)', 'available')
aliasset('avail', ' available')
aliasset('plugins', 'available')

def doquit(bot, ievent):
    """ quit .. quit the bot """
    globalshutdown()

cmnds.add('quit', doquit, 'OPER')
examples.add('quit', 'quit the bot', 'quit')
aliasset('shutdown', 'quit')
aliasset('exit', 'quit')
aliasset('halt', 'quit')

def handle_reboot(bot, ievent):
    """ reboot .. reboot the bot """
    ievent.reply('rebooting')
    global backupstop
    stateful = True
    if ievent.rest == 'cold':
        stateful = False
    time.sleep(2)
    try: 
        backupstop = 1
        if not stateful:
            fleet.exitall()
        plugins.exit()
    finally:
        if stateful:
            mainhandler.put(0, reboot_stateful, bot, ievent, fleet, partyline)
        else:
            mainhandler.put(0, reboot)

cmnds.add('reboot', handle_reboot, 'OPER')
examples.add('reboot', 'restart the bot', 'reboot')

def handle_commands(bot, ievent):
    """ commands <plugin> .. show commands of <plugin> """
    try:
        plugin = ievent.args[0].lower()
    except IndexError:
        ievent.missing('<plugin> .. see the list command for available \
plugins')
        return
    if not plugins.plugs.has_key(plugin):
        ievent.reply('no %s plugin is loaded .. see the available command for \
available plugins (reload to enable)' % plugin)
        return
    result = []
    for i, j in cmnds.iteritems():
        if plugin == j.plugname:
            txt = ""
            alias = aliasreverse(i)
            if alias:
                txt += "%s (%s)" % (i, alias)
            else:
                txt = i
            if txt:
                result.append(txt)
    if result:
        result.sort()
        ievent.reply('%s has the following commands: ' % plugin, result, \
dot=True)
    else:
        ievent.reply('no commands found for plugin %s' % plugin)

cmnds.add('commands', handle_commands, ['USER', 'WEB', 'ANON'])
examples.add('commands', 'show commands of <plugin>', '1) commands core')

def handle_perm(bot, ievent):
    """ perm <command> .. get permission of command """
    try:
        cmnd = ievent.args[0]
    except IndexError:
        ievent.missing("<cmnd>")
        return
    try:
        cmnd = aliases.data[cmnd]
    except KeyError:
        pass
    perms = cmnds.perms(cmnd)
    if perms:
        ievent.reply("%s command needs %s permission" % (cmnd, perms))
        return
    ievent.reply("can't find perm for %s" % cmnd)

cmnds.add('perm', handle_perm, ['USER', 'WEB', 'ANON'])
examples.add('perm', 'show permission of command', 'perm quit')

def handle_cc(bot, ievent):
    """ cc [<controlchar>] .. set/get control character of channel """
    try:
        chan = ievent.args[1]
    except IndexError:
        chan = ievent.channel
    try:
        what = ievent.args[0]
        if not users.allowed(ievent.userhost, 'OPER'):
            return
        if len(what) > 1:
            ievent.reply("only one character is allowed")
            return
        try:
            bot.channels[chan]['cc'] = what
        except (KeyError, TypeError):
            ievent.reply("no channel %s in database" % chan)
            return
        bot.channels.save()
        ievent.reply('control char set to %s' % what)
    except IndexError:
        # no argument given .. show cc of channel command is given in
        try:
            cchar = bot.channels[chan]['cc']
            ievent.reply('control character(s) for channel %s are/is %s' % \
(chan, cchar))
        except (KeyError, TypeError):
            ievent.reply("default cc is !")

cmnds.add('cc', handle_cc, 'USER', allowqueue=False)
examples.add('cc', 'set control char of channel or show control char of \
channel','1) cc ! 2) cc')

def handle_ccadd(bot, ievent):
    """ add a control char to the channels cc list """
    try:
        chan = ievent.args[1]
    except IndexError:
        chan = ievent.channel
    try:
        what = ievent.args[0]
        if not users.allowed(ievent.userhost, 'OPER'):
            return
        if len(what) > 1:
            ievent.reply("only one character is allowed")
            return
        try:
            bot.channels[chan]['cc'] += what
        except (KeyError, TypeError):
            ievent.reply("no channel %s in database" % chan)
            return
        bot.channels.save()
        ievent.reply('control char %s added' % what)
    except IndexError:
        ievent.missing('<cc> [<channel>]')

cmnds.add('cc-add', handle_ccadd, 'OPER', allowqueue=False)
examples.add('cc-add', 'cc-add <control char> .. add control character', 'cc-add #')

def handle_ccdel(bot, ievent):
    """ remove a control char from the channels cc list """
    try:
        chan = ievent.args[1]
    except IndexError:
        chan = ievent.channel
    try:
        what = ievent.args[0]
        if not users.allowed(ievent.userhost, 'OPER'):
            return
        if len(what) > 1:
            ievent.reply("only one character is allowed")
            return
        try:
            bot.channels[chan]['cc'] = \
bot.channels[chan]['cc'].replace(what, '')
        except KeyError:
            ievent.reply("no channel %s in database")
            return
        except TypeError:
            ievent.reply("no channel %s in database" % chan)
            return
        bot.channels.save()
        ievent.reply('control char %s deleted' % what)
    except IndexError:
        ievent.missing('<cc> [<channel>]')

cmnds.add('cc-del', handle_ccdel, 'OPER')
examples.add('cc-del', 'cc-del <control character> .. remove cc', 'cc-del #')

def handle_intro(bot, ievent):
    """ intro <nick> .. do whois on nick to sync userhosts cache """
    try:
        who = ievent.args[0]
    except IndexError:
        ievent.reply("intro <nick>")
        return
    bot.whois(who)
    ievent.reply('whois command send')

cmnds.add('intro', handle_intro, 'OPER')
examples.add('intro', 'do a whois of <nick> to sync userhost into the \
userhost cache', 'intro dunker')

def handle_loglevel(bot, ievent):
    """ loglevel <level> .. get or set loglevel .. the lower the more the \
        bot logs """
    if len(ievent.args) == 0:
        ievent.reply('loglevel is %s' % config['loglevel'])
        return
    try:
        level = int(ievent.args[0])
    except ValueError:
        ievent.reply('i need a integer argument')
        return
    config.set('loglevel', level)
    ievent.reply('loglevel is now %s' % config['loglevel'])

cmnds.add('loglevel', handle_loglevel,'OPER')
examples.add('loglevel', 'get/set current loglevel .. the lower the loglevel \
the more the bot logs', '1) loglevel 2) \
loglevel 100')

def handle_partylist(bot, ievent):
    """ partylist .. show users on partylist """
    partynicks = partyline.list_nicks()
    if partynicks:
        ievent.reply("people on partyline: ", partynicks)
    else:
        ievent.reply('no party yet!')

cmnds.add('partylist', handle_partylist, ['USER', 'WEB', 'ANON'])
examples.add('partylist', 'show connected partylist users', 'partylist')

def handle_partysilent(bot, ievent):
    """ party-silent .. disable partyline noise """
    partyline.silent(ievent.nick)
    ievent.reply('partyline put to silent mode')

cmnds.add('party-silent', handle_partysilent, ['USER', ])
examples.add('party-silent', 'disable partyline noise', 'party-silent')

def handle_partyloud(bot, ievent):
    """ party-loud .. enable partyline noise """
    partyline.loud(ievent.nick)
    ievent.reply('partyline put to loud mode')

cmnds.add('party-loud', handle_partyloud, ['USER', ])
examples.add('party-loud', 'enable partyline noise', 'party-loud')

def handle_threads(bot, ievent):
    """ thread .. show running threads """
    stats = Statdict()
    threadlist = threading.enumerate()
    for thread in threadlist:
        stats.upitem(thread.getName())
    result = []
    for item in stats.top():
        result.append("%s = %s" % (item[0], item[1]))
    result.sort()
    ievent.reply("threads running: ", result)

cmnds.add('threads', handle_threads, ['USER', 'OPER', 'ANON'])
examples.add('threads', 'show running threads', 'thread')

def handle_running(bot, ievent):
    """ running .. show running jobs on the runner """
    stats = [Statdict() for i in range(10)]
    teller = 0
    for runners in cbrunners:
        for runner in runners.running():
            stats[teller].upitem(runner)
        teller += 1
    teller = 0
    for runners in cmndrunners:
        for runner in runners.running():
            stats[teller].upitem(runner)
        teller += 1
    result = []
    for i in range(teller):
        for item in stats[i].top():
            result.append("%s.%s = %s" % (item[0], 10-i, item[1]))
    result.sort()
    ievent.reply("runners: ", result)

cmnds.add('running', handle_running, ['USER', 'OPER', 'ANON'])
examples.add('running', 'show running jobs', 'running')

def handle_save(bot, ievent):
    """ save .. save data to disk """
    ievent.reply('saving')
    plugins.save()
    fleet.save()
    config.save()
    ievent.reply('done')

cmnds.add('save', handle_save, 'OPER')
examples.add('save', 'save bot data', 'save')

def handle_version(bot, ievent):
    """ version .. show bot's version """
    ievent.reply(getversion())

cmnds.add('version', handle_version, ['USER', 'WEB', 'JCOLL', 'ANON', 'CLOUD'])
examples.add('version', 'show version of the bot', 'version')
aliasset('v', 'version')

def handle_whereis(bot, ievent):
    """ whereis <cmnd> .. locate a command """
    try:
        cmnd = ievent.args[0]
    except IndexError:
        ievent.missing('<cmnd>')
        return
    plugs = plugins.whereis(cmnd)
    if plugs:
        ievent.reply("%s command is in: " %  cmnd, plugs)
    else:
        ievent.reply("can't find " + cmnd)

cmnds.add('whereis', handle_whereis, ['USER', 'WEB', 'ANON'])
examples.add('whereis', 'whereis <cmnd> .. show in which plugins <what> \
is', 'whereis test')

def handle_help(bot, ievent):
    """ help [<cmnd>|<plugin>] .. show help on plugin/command or show \
        basic help msg  """
    try:
        what = ievent.args[0]
    except IndexError:
        ievent.reply('help <cmnd> or help <plugin> .. see the !list \
command for a list of available plugins or see !available command for a list \
of plugins to be reloaded')
        return
    phelp = plughelp.get(what)
    cmndresult = []
    if phelp:
        ievent.reply('plugin description: %s' % phelp)
        perms = users.getperms(ievent.userhost)
        for i, j in cmnds.iteritems():
            if what == j.plugname:
                for perm in j.perms:
                    if perm in perms:
                        if i not in cmndresult:
                            cmndresult.append(i)
        if cmndresult:
            cmndresult.sort()
            resultstr = ""
            for i in cmndresult:
                alias = aliasreverse(i)
                if alias:
                    resultstr += "%s (%s) .. " % (i, alias)
                else:
                    resultstr += "%s .. " % i
            ievent.reply('commands: %s'\
 % resultstr[:-4])
        else:
            ievent.reply('no commands available for permission %s' % \
str(perms))
        result = []
        for i in rebefore.relist:
            if what == i.plugname:
                if users.allowed(ievent.userhost, i.perms):
                    result.append(i.regex)
        for i in reafter.relist:
            if what == i.plugname:
                if users.allowed(ievent.userhost, i.perms):
                    result.append(i.regex)
        if result:
            resultstr = ""
            for i in result:
                resultstr += '"%s" .. ' % i
            ievent.reply('regular expressions: %s' % resultstr[:-4])
        else:
            pass
        result = []
        for i, j in callbacks.cbs.items():
            for z in j:
                if what == z.plugname:
                    result.append(i)
        if result:
            resultstr = ""
            for i in result:
                resultstr += "%s .. " % i
            ievent.reply('callbacks: %s' % resultstr[:-4])
        else:
            pass
        if not cmndresult:
            return
    if what in aliases.data:
        ievent.reply('%s is an alias for %s' % (what, aliases.data[what]))
        what = aliases.data[what]
    try:
        example = examples[what]
    except KeyError:
        return
    ievent.reply('%s .. alias: %s .. examples: %s' % (example.descr, \
aliasreverse(what), example.example))

cmnds.add('help', handle_help, ['USER', 'WEB', 'ANON'])
examples.add('help', 'get help on <cmnd> or <plugin>', '1) help test 2) \
help misc')

def handle_apro(bot, ievent):
    """ apro <cmnd> .. apropos for command """
    try:
        what = ievent.args[0]
    except IndexError:
        ievent.missing('<what>')
        return
    result = []
    teller = 1
    perms = users.getperms(ievent.userhost)
    for i in cmnds.apropos(re.escape(what), perms=perms):
        alias = aliasreverse(i)
        if alias:
            result.append('%s) %s (%s)' % (str(teller), i, alias))
        else:
            result.append('%s) %s' % (str(teller), i))
        teller += 1
    if result:
        ievent.reply("commands matching %s: " % what, result)
    else:
        ievent.reply('no matching commands found for %s' % what)

cmnds.add('apro', handle_apro, ['USER', 'WEB', 'ANON'])
aliases.data['apropos'] = 'apro'
examples.add('apro', 'apro <what> .. search for commands that contain \
<what>', 'apro com')

def handle_u(bot, ievent):
    """ u <nick> .. show userhost entry in cache """
    try:
        nick = ievent.args[0]
    except IndexError:
        ievent.missing('<nick>')
        return
    result = getwho(bot, nick)
    if result:
        ievent.reply(result)
    else:
        ievent.reply("can't get userhost for %s" % nick)

cmnds.add('u', handle_u, ['USER', 'ANON'])
examples.add('u', 'u <nick> .. get userhost cache entry for <nick>', \
'u dunker')

def handle_less(bot, ievent):
    """ get entry from the output cache """
    try:
        if len(ievent.args) == 3:
            (who, index1, index2) = ievent.args
        elif len(ievent.args) == 2:
            if bot.jabber:
                who = ievent.userhost
            else:
                who = ievent.nick
            (index1, index2) = ievent.args
        else:
            if bot.jabber:
                who = ievent.userhost
            else:
                who = ievent.nick
            index1 = 0
            index2 = ievent.args[0]
        index1 = int(index1)
        index2 = int(index2)
    except IndexError:
        ievent.missing('[<who>] [<index1>] <index2>')
        return
    except ValueError:
        ievent.reply('i need integers as arguments')
        return
    txt = bot.less.get(who, index1, index2)
    if not txt:
        ievent.reply('no data available for %s %s %s' % \
(who, index1, index2))
        return
    if bot.jabber:
        bot.say(ievent.userhost, txt)
    else:
        ievent.reply(txt)

cmnds.add('less', handle_less, ['USER', 'ANON'])
examples.add('less', "less [<who>] [<index1>] <index2> .. get txt from bots \
output cache", '1) less 0 2) less 0 2 3) less bart 1 0')

def handle_lesssize(bot, ievent):
    """ show size of output cache """
    try:
        who = ievent.args[0]
    except IndexError:
        who = ievent.nick
    ievent.reply(bot.less.size(who))

cmnds.add('less-size', handle_lesssize, ['USER', 'ANON'])
examples.add('less-size', "show sizes of data in bot's ouput cache", \
'less-size')

def handle_more(bot, ievent):
    """ pop message from the output cache """
    try:
        who = ievent.args[0]
    except IndexError:
        if bot.jabber:
            who = ievent.userhost
        else:
            who = ievent.nick
    what, size = bot.less.more(who, 0)
    if not what:
        ievent.reply('no more data available for %s' % who)
        return
    if bot.jabber:
        if size:
            bot.say(ievent.userhost, "%s (+%s)" % (what, size))
        else:
            ievent.reply(what)
        return      
    if size:
        bot.output(ievent.printto, "%s \002(+%s)\002" % (what, size))
    else:
        ievent.reply(what)

cmnds.add('more', handle_more, ['USER', 'ANON'])
examples.add('more', 'return txt from output cache', '1) more 2) more test')

def handle_whatcommands(bot, ievent):
    if not ievent.rest:
        ievent.missing('<perm>')
        return
    result = cmnds.list(ievent.rest)
    result.sort()
    if not result:
        ievent.reply('no commands known for permission %s' % ievent.rest)
    else:
        ievent.reply('commands known for permission %s: ' % ievent.rest, result)

cmnds.add('whatcommands', handle_whatcommands, 'USER')
examples.add('whatcommands', 'show commands with permission <perm>', \
'whatcommands USER')
