# gozerplugs/plugs/popcon.py
#
#

""" enlists your bot in the popularity contest page at %s (if enabled with 
 popcon-enable)
"""

__author__ = "Wijnand 'tehmaze' Modderman - http://tehmaze.com"
__license__ = 'BSD'

from gozerbot.commands import cmnds
from gozerbot.config import config
from gozerbot.examples import examples
from gozerbot.fleet import fleet
from gozerbot.generic import geturl2, rlog, useragent, getversion
from gozerbot.persistconfig import PersistConfig
from gozerbot.periodical import periodical, hourly
from gozerbot.plugins import plugins
from gozerbot.plughelp import plughelp
import os, sys, time
import urllib, urllib2

cfg = PersistConfig()
cfg.define('url', 'http://plugins.gozerbot.org/popcon/')
for opt in ['add-url', 'set-url', 'chk-url', 'get-url', 'setplugs-url']:
    cfg.undefine(opt)
cfg.define('enabled', False)
cfg.define('bot-id', '')

plughelp.add('popcon', 'gozerbots popularity contest at %s' % cfg.get('url'))

def shutdown():
    """ kill popcon periodicals """
    periodical.kill()
    return 1

class PopCon(object):

    """ popcon object """

    def __init__(self):
        if not cfg.get('enabled'):
            return
        self.start()

    def start(self):
        """ register bot with popcon .. start update loop """
        if not self.check():
            rlog(10, 'popcon', 'registering this bot')
            try:
                self.register()
            except urllib2.HTTPError, e:
                rlog(10, 'popcon', 'failed to register the bot: %s' % str(e))
        self.update()

    def check(self):
        """ check if bot is registered """
        if not cfg.get('bot-id'):
            return False
        try:
            data = geturl2('%schk/?id=%s' % (cfg.get('url'), \
cfg.get('bot-id')))
        except Exception, ex:
            data = 'ERROR: %s' % str(ex)
        if data.startswith('OK'):
            rlog(5, 'popcon', 'register check ok')
            return True
        if data.startswith('NOT FOUND'):
            rlog(5, 'popcon', 'register check failed, bot not registered \
(no bot-id match)')
            return self.register()
        rlog(10, 'popcon', 'register check failed, error!')
        return False

    def register(self):
        """ register the bot """
        data = self._data()
        data.update({
            'uuid': 'new'
            })
        req = urllib2.Request(url='%sadd/' % cfg.get('url'), \
data=urllib.urlencode(data))
        req.add_header('User-agent', useragent())
        reply = urllib2.urlopen(req).read()
        if reply.startswith('OK '):
            cfg.set('bot-id', reply.split()[1].strip())
            rlog(10, 'popcon', 'registered bot with id %s' % cfg.get('bot-id'))
            return True
        rlog(10, 'popcon', 'error registering bot: %s' % reply)
        return False
    
    @hourly
    def update(self):
        """ call update function every hour """
        self._update()

    # "manual" update
    def _update(self):
        """ update popcon data """
        data = self._data()
        req = urllib2.Request(url='%sset/' % cfg.get('url'), \
data=urllib.urlencode(data))
        req.add_header('User-agent', useragent())
        try:
            reply = urllib2.urlopen(req).read()
        except Exception, e:
            reply = 'ERROR %s' % str(e)
        if reply.startswith('OK '):
            rlog(5, 'popcon', 'submitted new data')
        else:
            rlog(10, 'popcon', 'failed to submit updated data: %s' % str(reply))
            return
        data = {
            'uuid': data['uuid'],
            'plugins': ','.join(plugins.list())
        }
        req = urllib2.Request(url='%ssetplugs/' % cfg.get('url'), \
data=urllib.urlencode(data))
        req.add_header('User-agent', useragent())
        try:
            reply = urllib2.urlopen(req).read()
        except Exception, e:
            reply = 'ERROR %s' % str(e)
        if reply.startswith('OK'):
            rlog(5, 'popcon', 'submitted new plugins data')
        else:
            rlog(10, 'popcon', 'failed to submit plugins data: %s' % \
str(reply))

    def geturl(self):
        """ return url for the bots entry in the popcon """
        return geturl2('%sget/?id=%s' % (cfg.get('url'), cfg.get('bot-id')))

    def _data(self):
        """ gather popcon data from the bot """
        uname = os.uname()
        bottype  = 'tarball'
        ver = getversion()
        if ' HG revision ' in ver:
            bottype = 'hg'
        elif ' SVN ' in ver:
            bottype = 'svn'
        data = {
            'uuid':             cfg.get('bot-id'),
            'version':          config['version'],
            'type':             bottype,
            'python_version':   '.'.join(str(x) for x in sys.version_info[:3]),
            'os_type':          uname[0],
            'os_version':       uname[1],
            'os_arch':          uname[4],
            'uptime':           str(int(getattr(fleet.getmainbot(), \
'starttime', time.time()))),
            }
        return data

popcon = None
if cfg.get('enabled'):
    popcon = PopCon()

def handle_popcon(bot, ievent):
    """ show whether the bot is participating in the popcon """
    if cfg.get('enabled'):
        ievent.reply('bot is participating in the popularity contest')
    else:
        ievent.reply('bot is not participating in the popularity contest, \
use popcon-enable to enable it')

cmnds.add('popcon', handle_popcon, 'OPER')
examples.add('popcon', 'show whether the bot is participating in the popcon', \
'popcon')

def handle_popcon_enable(bot, ievent):
    """ enable popcon """
    global popcon
    if not cfg.get('enabled'):
        cfg.set('enabled', True)
        popcon = PopCon()
        ievent.reply('ok')
    else:
        ievent.reply('already enabled')

cmnds.add('popcon-enable', handle_popcon_enable, 'OPER')
examples.add('popcon-enable', 'join the popularity contest', 'popcon-enable')

def handle_popcon_update(bot, ievent):
    """ update bots popcon data """
    if popcon and popcon.check():
        popcon._update()
        ievent.reply('ok')
    else:
        ievent.reply('bot is not participating in the popularity contest, \
use popcon-enable to enable it')

cmnds.add('popcon-update', handle_popcon_update, 'OPER')
examples.add('popcon-update', 'update bots popcon data', 'popcon-update')

def handle_popcon_url(bot, ievent):
    """ get the url pointing to the entry of the bot in popcon """
    if popcon:
        ievent.reply(popcon.geturl())
    else:
        ievent.reply('bot is not participating in the popularity contest, \
use popcon-enable to enable it')

cmnds.add('popcon-url', handle_popcon_url, 'OPER')
examples.add('popcon-url', "shows your bot's entry in the popularity contest \
(if enabled)", 'popcon-url')
