# -*- coding: utf-8 -*-
"""
Bot Components

Provides virtual windows, users, events etc. for the bot.

"""

import os
import sys
import time
import string
# import traceback

# Symbian S60 specific compatibility
s60 = False
if sys.platform == "symbian_s60":
    s60 = True
    sys.path.append("e:\\python")
    sys.path.append("c:\\python")
    sys.path.append("c:\\DATA\\python")

from helpers import *
from const import *


class Event:
    """Event object

    Stores events to facilitate passing events around easily

    """
    # TODO: make this more manageable
    def __init__(self, id, win=None, user=None, msg=None, modes=None, mode_oper=None, cmd=None, cmd_args=None, by=None, new_nick=None):
        self.time = time.time()
        self.id = id #FIXME: rename to 'type'
        self.type = id
        self.win = win
        self.user = user
        self.msg = msg

        self.modes = modes
        self.mode_oper = mode_oper

        self.cmd = cmd
        self.cmd_args = cmd_args
        self.by = by
        self.new_nick = new_nick

    def __str__(self):
        s = "Event("
        s += "," + str(self.id)
        s += "," + str(self.win)
        s += "," + str(self.user)
        s += "," + safe_escape(self.msg)

        s += "," + str(self.modes)
        s += "," + str(self.mode_oper)

        s += "," + str(self.cmd)
        s += "," + str(self.cmd_args)
        s += ")"
        return s


class Message:
    """Message object

    Stores an irc message and its details.

    """
    def __init__(self,nick,text,dest=""):
        self.time = time.time()
        self.nick = nick
        self.text = text
        self.dest = dest

    def __str__(self):
        return "["+time_stamp(self.time)+"] "+self.nick+" -> "+self.dest+" :"+self.text




#
# Users
#
class User:
    """User object

    Represents each user the bot is aware of.

    """
    def __init__(self, bot, nick=""):
        self.bot = bot
        self.nick = u""+nick
        self.hostname = u""
        self.ident = u""

        self.debug = 1
        
        self.online = 1
        self.created = time.time()
        
        self.went_online = None
        self.went_offline = None
        self.quit_reason = None
        
        self.last_active = None
        self.last_command = None

        self.account = False     # If False the user hasn't logged in

    def __repr__(self):
        return "<" + self
.nick + ">"
        
    def __str__(self):
        return "<" + self.nick + ">"
        
    def InfoStr(self):
        s = "<" + self.nick + "> "

        s += " hn:" + self.hostname
        s += " crtd:" + time_stamp_numeric(self.created)
        s += " online:" + str(self.online)
        if self.last_active:
            s += " act:" + time_stamp_numeric(self.last_active)
        if self.went_offline:
            s += " quit:" + time_stamp_numeric(self.went_offline)
        if self.account:
            s += " id:" + self.account["name"]
        return s
        
    def DebugLog(self, *args):
        args = map(arg_to_str, args)
        line = self.__str__() + " " + " ".join(args)
        if self.debug:
            self.bot.log.Log("user", line)

    #
    #   Events
    #
            
    def OnAction(self):
        self.online = 1
        self.last_active = time.time()
        pass
        
    def OnOnline(self): #FIXME implement
        self.AutoAuth()
        self.OnAction()
    
    def OnNickChanged(self, old, new):
        self.bot.HandleEvent(Event(IRC_EVT_USER_NICK_CHANGE, user=self, new_nick=new))
        self.OnAction()
        self.DebugLog("changed nick from", old, "to", new)
        self.nick = u"" + new
        
    def OnHostnameChanged(self, old, new):
        self.OnAction()
        self.DebugLog("HOST ", new)
        self.hostname = new
        if self.AutoAuth():
            return True
        self.Deauth()
        return True
        
    def OnQuit(self, reason):
        self.DebugLog("OnQuit(", reason, ")")
        if reason:
            self.quit_reason = reason
        self.went_offline = time.time()
        self.online = 0
        self.Deauth()
        
    def OnAuthed(self, account):
        self.OnAction()
        self.account = account
        self.bot.HandleEvent(Event(IRC_EVT_USER_AUTHED, user = self))
        
        
    #
    # Actions
    #
    
    def Privmsg(self, msg):
        self.bot.Privmsg(self.GetNick(), msg)
        
    def Notice(self, msg):
        self.bot.Notice(self.GetNick(), msg)
        
    def Send(self, msg):
        send = "privmsg"
        if self.bot.config["default_send"] == "notice":
            send = "notice"
        if send == "notice":
            self.bot.Notice(self.GetNick(), msg)
        else:
            self.bot.Privmsg(self.GetNick(), msg)
        
        
    #
    # Internal stuff
    #
            
    def AutoAuth(self):
        if not self.IsAuthed():
            if self.bot.AuthenticateHostname(self, self.hostname):
                return True
            return False
        return False

    def Deauth(self):
        if self.IsAuthed():
            self.account = False
            return True
        else:
            return False

    def IsAuthed(self):
        if self.account == False:
            return False
        return True

    def IsOnline(self):
        if self.online:
            return True
        return False

    #
    # Getters
    #
        
    def GetNick(self):
        return self.nick

    def GetQuery(self):
        return self.bot.GetWindow(self.GetNick())

    def GetPermission(self):
        if self.account == False:
            return 0
        else:
            return self.account["level"]

    def Channels(self):
        chans = []
        for win in self.bot.windows:
            if win.zone == IRC_ZONE_CHANNEL:
                if win.HasUser(self):
                    chans.append(win)
        return chans
            
    def HasOP(self, chan):
        return chan.UserHasMode(self, IRC_MODE_OP)

    def HasVoice(self, chan):
        return chan.UserHasMode(self, IRC_MODE_VOICE)

    def SetHostname(self, hostname):
        if hostname != self.hostname:
            self.OnHostnameChanged(self.hostname, hostname)
            return True
        if not self.IsOnline():
            self.OnOnline()
        return False


class Me(User):
    """Me object

    Represents the bot as an irc user and does nick management for the bot.

    """
    def __init__(self, bot):
        User.__init__(self, bot, bot.config["identity"]["nicks"][0])
        self.nick_index = 0
        self.attempted_nick = self.nick
        self.bot.SetNick(self.nick)
        
    def Nick(self, nick=None):
        if nick == None:
            nick = self.nick
        else:
            self.nick = nick
        self.attempted_nick = nick
        self.bot.ChangeNick(nick)
        
    def TryNewNick(self):
        self.DebugLog("TryNewNick()")
        self.attempted_nick = self.attempted_nick + self.bot.config["identity"]["nick_suffix"]
        # The attempted nick might not be available but we
        # store it as the current nick assuming it will succeed
        # (it eventually will anyway and then nick will be correct)
        # This is the easiest way to maintain the correct nick
        self.nick = self.attempted_nick
        self.bot.ChangeNick(self.attempted_nick)

class Admin(User):
    """Admin user

    Represents the command line user.

    """
    def __init__(self, bot):
        User.__init__(self, bot, "*admin*")
        self.account = {"level": 100}

    def Privmsg(self, msg):
        self.Send(msg)

    def Notice(self, msg):
        self.Send(msg)

    def Send(self, msg):
        self.bot.log.Info("bot", msg)

#
# Virtual windows
#

class BotWindow:
    """Window representing an IRC channel or query"""

    def __init__(self, bot, name=None):
        self.bot = bot
        self.name = name
        self.zone = None
        self.log = []
        self.debug = 1

    def __repr__(self):
        return "[" + self.GetName() + "]"

    def __str__(self):
        return "[" + self.GetName() + "]"
        
    def DebugLog(self, *args):
        args = map(arg_to_str, args)
