"""
Karma - handle karma (++ and --) tracking
Copyright (C) 2010  Brian S. Stephan

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import re
import sqlite3

from Module import Module

__author__ = "Mike Bloy <mike@bloy.org>"
__date__ = "$Oct 23, 2010 11:12:33 AM$"

class Karma(Module):

    def __init__(self, irc, config, server):
        """
        Upon creation, determine the save file location
        """

        Module.__init__(self, irc, config, server)

        pattern = "(?:(\S+)|\((.+)\))"
        karmapattern = pattern + '(\+\+|--|\+-|-\+)' + '(\s+|$)'
        querypattern = '^!rank\s+(.*)'
        reportpattern = '^!karma\s+report\s+(highest|lowest|positive|negative)'
        statpattern = '^!karma\s+stat\s+(.*)'

        self.karmare = re.compile(karmapattern)
        self.queryre = re.compile(querypattern)
        self.reportre = re.compile(reportpattern)
        self.statre = re.compile(statpattern)

    def db_init(self):
        # need to init the database if karma tables don't already exist
        version = self.db_module_registered(self.__class__.__name__)
        if (version == None):
            # have to create the database tables
            conn = self.get_db()
            try:
                conn.execute('''
                   CREATE TABLE karma_log (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        key TEXT NOT NULL,
                        delta INTEGER NOT NULL,
                        who TEXT NOT NULL,
                        userhost TEXT NOT NULL,
                        karmatime TEXT DEFAULT CURRENT_TIMESTAMP
                    )''')
                conn.execute('CREATE INDEX karma_log_key_ix ON karma_log (key)')
                conn.execute('CREATE INDEX karma_log_who_ix ON karma_log (who)')
                conn.execute('''
                    CREATE VIEW karma_values AS
                    SELECT key, SUM(delta) AS value
                    FROM karma_log
                    GROUP BY key''')

                sql = 'INSERT INTO drbotzo_modules VALUES (?,?)'
                conn.execute(sql, (self.__class__.__name__, 1))
                conn.commit()
                version = 1
            except sqlite3.Error as e:
                conn.rollback()
                print("sqlite error: " + str(e))
                raise
        if (version < 2):
            conn = self.get_db()
            try:
                conn.execute('''
                    CREATE VIEW karma_users AS
                    SELECT who, COUNT(NULLIF(delta, -1)) AS pos,
                        COUNT(NULLIF(delta, 1)) AS neg
                    FROM karma_log GROUP BY who''')
                sql = 'UPDATE drbotzo_modules SET version = ? WHERE module = ?'
                conn.execute(sql, (2, self.__class__.__name__))
                conn.commit()
                version = 2
            except sqlite3.Error as e:
                conn.rollback()
                print("sqlite error: " + str(e))
                raise

    def do(self, connection, event, nick, userhost, what, admin_unlocked):
        """look for karma strings at the start of messages"""

        if (self.karmare.search(what)):
            return self.handle_karma_change(connection, nick, userhost, what)
        elif (self.queryre.search(what)):
            return self.handle_karma_query(connection, nick, userhost, what)
        elif (self.statre.search(what)):
            return self.handle_stat_query(connection, nick, userhost, what)
        elif (self.reportre.search(what)):
            return self.handle_report_query(connection, nick, userhost, what)

    def handle_karma_change(self, connection, nick, userhost, what):
        """
        handle the karma change and storage.
        """
        match = self.karmare.search(what)
        key = match.group(1) if match.group(1) else match.group(2)
        value = match.group(3)
        if (value == '++'):
            return self.karma_modify(key, 1, nick, userhost)
        elif (value == '--'):
            return self.karma_modify(key, -1, nick, userhost)
        elif (value == '+-'):
            self.karma_modify(key, 1, nick, userhost)
            return self.karma_modify(key, -1, nick, userhost)
        elif (value == '-+'):
            self.karma_modify(key, -1, nick, userhost)
            return self.karma_modify(key, 1, nick, userhost)

    def karma_modify(self, key, value, nick, userhost):
        """
        Go out to the database and update the karma value.
        """

        conn = self.get_db()
        try:
            sql = '''
            INSERT INTO karma_log (key, delta, who, userhost)
            VALUES (?, ?, ?, ?)
            '''
            conn.execute(sql, (key, value, nick, userhost))
            conn.commit()
        except sqlite3.Error as e:
            conn.rollback()
            return "sqlite error: " + str(e)

    def handle_report_query(self, connection, nick, userhost, what):
        match = self.reportre.search(what)
        report = match.group(1)

        message = '{nick}: the desired report is not yet implemented'.format(nick=nick)
        query = None
        header = None
        if (report == 'highest'):
            query = 'SELECT key, value FROM karma_values ORDER BY value DESC LIMIT 5'
            header = 'Top 5 karma recipients:'
        elif (report == 'lowest'):
            query = 'SELECT key, value FROM karma_values ORDER BY value ASC LIMIT 5'
            header = 'Bottom 5 karma recipients:'
        elif (report == 'positive'):
            query = 'SELECT who, pos FROM karma_users ORDER BY pos DESC LIMIT 5'
            header = 'Top 5 Optimists:'
        elif (report == 'negative'):
            query = 'SELECT who, neg FROM karma_users ORDER BY neg DESC LIMIT 5'
            header = 'Top 5 Pessimists:'

        if (query != None):
            conn = self.get_db()
            list = []
            try:
                cursor = conn.execute(query)
                result = cursor.fetchone()
                while (result != None):
                    list.append("{key} ({value})".format(key=result[0], value=result[1]))
                    result = cursor.fetchone()
                list = ', '.join(list)
                message = '{header} {list}'.format(header=header, list=list)
            except sqlite3.Error as e:
                conn.rollback()
                return "sqlite error: " + str(e)
        return message

    def handle_stat_query(self, connection, nick, userhost, what):
        match = self.statre.search(what)
        statnick = match.group(1)

        conn = self.get_db()
        reply = '{nick}: {statnick} has never given karma'.format(nick=nick, statnick=statnick)
        try:
            query = '''
            SELECT pos, neg
            FROM karma_users
            WHERE who = :who
            '''
            value = conn.execute(query, {'who': statnick}).fetchone()
            if (value != None):
                pos = value[0]
                neg = value[1]
                total = pos+neg;
                reply = '{nick}: {statnick} has given {pos} postive karma and {neg} negative karma, for a total of {total} karma'.format(nick=nick, statnick=statnick, pos=pos, neg=neg, total=total)

        except sqlite3.Error as e:
            return "sqlite error: " + str(e)

        return reply

    def handle_karma_query(self, connection, nick, userhost, what):
        match = self.queryre.search(what)
        key = match.group(1)

        conn = self.get_db()
        reply = '{nick}: {key} has no karma'.format(nick=nick, key=key)
        try:
            query = '''
            SELECT value
            FROM karma_values
            WHERE key = :key
            '''
            value = conn.execute(query, {'key': key}).fetchone()

            if (value != None):
                query = '''
                SELECT count(*) FROM karma_values WHERE value > :value
                '''
                rank = conn.execute(query, {'value': value[0]}).fetchone()
                rank = rank[0] + 1;

                reply = '{nick}: {key} has {value[0]!s} points of karma (rank {rank})'.format(
                    nick=nick, key=key, value=value, rank=rank)
        except sqlite3.Error as e:
            return "sqlite error: " + str(e)

        return reply

if __name__ == "__main__":
    print "Hello World"

# vi:tabstop=4:expandtab:autoindent