from __future__ import absolute_import
import os
import random
import logger
import json
import time

import config
from db import session
from commands import BotCommand
import protocol as bot_protocols
import conversation
import memory
from nicks import Nicks, NickNotFound

class Bot(object):
    current_bot = None

    @classmethod
    def factory(cls, botname='snarkbot', protocol='cmd'):
        try:
            current_bot = cls.current_bot
            if isinstance(current_bot, cls):
                return current_bot
        except AttributeError:
            pass

        cls.current_bot = cls(botname=botname, protocol=protocol)
        return cls.current_bot

    def __init__(self,botname='snarkbot',protocol='cmd'):
        self.botname = botname
        try:
            p = getattr(bot_protocols, protocol)
            self.proto = p()
        except AttributeError:
            raise ValueError("Protocol %s does not exist" % protocol)

        self.mem = memory.Memory(history=config.max_history_lines) # initialize memory
        self.quiet_timer = 0
        self.be_quiet = False
        self.bot_said = []
        
        # ensure the factory() returns me
        self.__class__.current_bot = self

    def listen(self):
        try:
            randomizer = random.randint(config.min_wait_seconds,config.max_wait_seconds)
            snark_timer = int(time.time()) # checks against randomizer to know when to say something snarky
            while(True):

                # check if we're shut-up. If so just continue. SIGALRM will release us eventually
                if self.be_quiet:
                    continue

                response = None
                to_nick = None
                
                # cmd protocol in particular needs a timeout. We give it the randomizer so we can still get a snark
                (from_nick,_input) = self.proto.read(timeout=randomizer)

                # see if we've talked to this person before
                try:
                    from_nick = Nicks().get_by_name(from_nick)
                except NickNotFound:
                    from_nick = Nicks().add_nick(from_nick)

                if _input:
                    self.mem.add_history(from_nick, _input) # remember 
                    response = BotCommand.parse_command(from_nick, msg)

                    if not response:
                        # get the latest conversation or create a new conversation
                        c = conversation.Conversation(from_nick)
                        response = c.create_response(_input)

                    if response:
                        self.i_said(from_nick,response)
                        self.proto.send(response)
                        snark_timer = int(time.time()) # reset the snark timer
                        randomizer = random.randint(config.min_wait_seconds,config.max_wait_seconds)
                    to_nick = from_nick.name
                else:
                    now = int(time.time())
                    if (now - snark_timer) > randomizer:
                        response = conversation.Snark(self.mem) # pass memory to snark so we can snark somethign based on the last input
                        to_nick = 'channel'
                        snark_timer = int(time.time())
                        randomizer = random.randint(min_wait_seconds, max_wait_seconds)

                if response:
                    self.proto.send(response,to_nick)

        except KeyboardInterrupt:
            self.shutdown()
    
    def shutdown(self):
        self.proto.send('Exiting. Good bye.','channel')
        self.proto.close() # close the proto if needed

        self.mem.commit_history() # make sure we store all the history of this session
        session.close() # close out the db if needed

    def i_said(self, to_nick, response):
        self.bot_said.append('{} to {}'.format(response, to_nick))
    
    def get_last(self):
        return str(self.bot_said[-1])
