from direct.directnotify import DirectNotifyGlobal
from direct.showbase import DirectObject
from pandac.PandaModules import *
import sys
import time

from otp.chat.ChatGlobals import *
from otp.chat.TalkGlobals import *
from otp.chat.TalkHandle import TalkHandle
from otp.chat.TalkMessage import TalkMessage
from otp.otpbase import OTPGlobals
from otp.otpbase import OTPLocalizer
from otp.speedchat import SCDecoders
from toontown.chat.ChatGlobals import *
from toontown.chat.TTWhiteList import TTWhiteList


ThoughtPrefix = '.'


class TalkAssistant(DirectObject.DirectObject):
    notify = DirectNotifyGlobal.directNotify.newCategory('TalkAssistant')

    def __init__(self):
        self.logWhispers = 1
        self.whiteList = None
        self.clearHistory()
        self.zeroTimeDay = time.time()
        self.zeroTimeGame = globalClock.getRealTime()
        self.floodThreshold = 10.0
        self.useWhiteListFilter = base.config.GetBool('white-list-filter-openchat', 0)
        self.lastWhisperDoId = None
        self.lastWhisper = None
        self.SCDecoder = SCDecoders
        self.whiteList = TTWhiteList()
        return

    def clearHistory(self):
        self.historyComplete = []
        self.historyOpen = []
        self.historyUpdates = []
        self.historyByDoId = {}
        self.historyByDISLId = {}
        self.floodDataByDoId = {}
        self.spamDictByDoId = {}
        self.handleDict = {}
        self.messageCount = 0
        self.shownWhiteListWarning = 0

    def delete(self):
        self.ignoreAll()
        self.clearHistory()

    def start(self):
        pass

    def stop(self):
        pass

    def countMessage(self):
        self.messageCount += 1
        return self.messageCount - 1

    def getOpenText(self, numLines, startPoint = 0):
        return self.historyOpen[startPoint:startPoint + numLines]

    def getSizeOpenText(self):
        return len(self.historyOpen)

    def getCompleteText(self, numLines, startPoint = 0):
        return self.historyComplete[startPoint:startPoint + numLines]

    def getCompleteTextFromRecent(self, numLines, startPoint = 0):
        start = len(self.historyComplete) - startPoint
        if start < 0:
            start = 0
        backStart = max(start - numLines, 0)
        text = self.historyComplete[backStart:start]
        text.reverse()
        return text

    def getAllCompleteText(self):
        return self.historyComplete

    def getAllHistory(self):
        return self.historyComplete

    def getSizeCompleteText(self):
        return len(self.historyComplete)

    def getHandle(self, doId):
        return self.handleDict.get(doId)

    def doWhiteListWarning(self):
        pass

    def addToHistoryDoId(self, message, doId, scrubbed = 0):
        if message.getTalkType() == TALK_WHISPER and doId != localAvatar.doId:
            self.lastWhisperDoId = doId
            self.lastWhisper = self.lastWhisperDoId
        if doId not in self.historyByDoId:
            self.historyByDoId[doId] = []
        self.historyByDoId[doId].append(message)
        if not self.shownWhiteListWarning and scrubbed and doId == localAvatar.doId:
            self.doWhiteListWarning()
            self.shownWhiteListWarning = 1
        if doId not in self.floodDataByDoId:
            self.floodDataByDoId[doId] = [0.0, self.stampTime(), message]
        else:
            oldTime = self.floodDataByDoId[doId][1]
            newTime = self.stampTime()
            timeDiff = newTime - oldTime
            oldRating = self.floodDataByDoId[doId][0]
            contentMult = 1.0
            if len(message.getBody()) < 6:
                contentMult += 0.2 * float(6 - len(message.getBody()))
            if self.floodDataByDoId[doId][2].getBody() == message.getBody():
                contentMult += 1.0
            floodRating = max(0, 3.0 * contentMult + oldRating - timeDiff)
            self.floodDataByDoId[doId] = [floodRating, self.stampTime(), message]
            if floodRating > self.floodThreshold:
                if oldRating < self.floodThreshold:
                    self.floodDataByDoId[doId] = [floodRating + 3.0, self.stampTime(), message]
                    return 1
                else:
                    self.floodDataByDoId[doId] = [oldRating - timeDiff, self.stampTime(), message]
                    return 2
        return 0

    def addToHistoryDISLId(self, message, dISLId, scrubbed = 0):
        if dISLId not in self.historyByDISLId:
            self.historyByDISLId[dISLId] = []
        self.historyByDISLId[dISLId].append(message)

    def addHandle(self, doId, message):
        if doId == localAvatar.doId:
            return
        handle = self.handleDict.get(doId)
        if not handle:
            handle = TalkHandle(doId, message)
            self.handleDict[doId] = handle
        else:
            handle.addMessageInfo(message)

    def stampTime(self):
        return globalClock.getRealTime() - self.zeroTimeGame

    def findAvatarName(self, id):
        info = base.cr.identifyAvatar(id)
        
        return info.getName() if info else ''

    def whiteListFilterMessage(self, text):
        if not self.useWhiteListFilter:
            return text
        elif not base.whiteList:
            return 'no list'
        words = text.split(' ')
        newwords = []
        for word in words:
            if word == '' or base.whiteList.isWord(word):
                newwords.append(word)
            else:
                newwords.append(base.whiteList.defaultWord)

        newText = ' '.join(newwords)
        return newText

    def colorMessageByWhiteListFilter(self, text):
        if not base.whiteList:
            return text
        words = text.split(' ')
        newwords = []
        for word in words:
            if word == '' or base.whiteList.isWord(word):
                newwords.append(word)
            else:
                newwords.append('\x01WLRed\x01' + word + '\x02')

        newText = ' '.join(newwords)
        return newText

    def isThought(self, message):
        if not message:
            return 0
        elif len(message) == 0:
            return 0
        elif message.find(ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
            return 1
        else:
            return 0

    def removeThoughtPrefix(self, message):
        if self.isThought(message):
            return message[len(ThoughtPrefix):]
        else:
            return message

    def printHistoryComplete(self):
        print 'HISTORY COMPLETE'
        for message in self.historyComplete:
            print '%s %s %s\n%s\n' % (message.getTimeStamp(),
             message.getSenderAvatarName(),
             message.getSenderAccountName(),
             message.getBody())

    def checkOpenTypedChat(self):
        if base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
            return True
        return False

    def checkAnyTypedChat(self):
        if base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
            return True
        if base.localAvatar.canChat():
            return True
        return False

    def checkOpenSpeedChat(self):
        return True

    def checkWhisperTypedChatAvatar(self, avatarId):
        remoteAvatar = base.cr.doId2do.get(avatarId)
        if remoteAvatar:
            if remoteAvatar.isUnderstandable():
                return True
        if base.localAvatar.commonChatFlags & OTPGlobals.SuperChat:
            return True
        remoteAvatarOrHandleOrInfo = base.cr.identifyAvatar(avatarId)
        if remoteAvatarOrHandleOrInfo and hasattr(remoteAvatarOrHandleOrInfo, 'isUnderstandable'):
            if remoteAvatarOrHandleOrInfo.isUnderstandable():
                return True
        if base.cr.getFriendFlags(avatarId) & OTPGlobals.FriendChat:
            return True
        return False

    def checkWhisperSpeedChatAvatar(self, avatarId):
        return True

    def checkOpenSpeedChat(self):
        return True

    def checkWhisperSpeedChatAvatar(self, avatarId):
        return True

    def receiveOpenTalk(self, senderAvId, avatarName, accountId, accountName, message, scrubbed = 0):
        error = None
        if not avatarName and senderAvId:
            localAvatar.sendUpdate('logSuspiciousEvent', ['receiveOpenTalk: invalid avatar name (%s)' % senderAvId])
            avatarName = self.findAvatarName(senderAvId)
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, avatarName, accountId, accountName, None, None, None, None, TALK_OPEN, None)
        if senderAvId != localAvatar.doId:
            self.addHandle(senderAvId, newMessage)
        reject = 0
        if senderAvId:
            reject = self.addToHistoryDoId(newMessage, senderAvId, scrubbed)
        if accountId:
            self.addToHistoryDISLId(newMessage, accountId)
        if reject == 1:
            newMessage.setBody(OTPLocalizer.AntiSpamInChat)
        if reject != 2:
            isSpam = self.spamDictByDoId.get(senderAvId) and reject
            if not isSpam:
                self.historyComplete.append(newMessage)
                self.historyOpen.append(newMessage)
                messenger.send('NewOpenMessage', [newMessage])
            if newMessage.getBody() == OTPLocalizer.AntiSpamInChat:
                self.spamDictByDoId[senderAvId] = 1
            else:
                self.spamDictByDoId[senderAvId] = 0
        return error

    def receiveWhisperTalk(self, avatarId, avatarName, accountId, accountName, toId, toName, message, scrubbed = 0):
        error = None
        if not avatarName and avatarId:
            avatarName = self.findAvatarName(avatarId)
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, toId, toName, None, None, TALK_WHISPER, None)
        if avatarId == localAvatar.doId:
            self.addHandle(toId, newMessage)
        else:
            self.addHandle(avatarId, newMessage)
        self.historyComplete.append(newMessage)
        if avatarId:
            self.addToHistoryDoId(newMessage, avatarId, scrubbed)
        if accountId:
            self.addToHistoryDISLId(newMessage, accountId)
        messenger.send('NewOpenMessage', [newMessage])
        return error

    def receiveThought(self, avatarId, avatarName, accountId, accountName, message, scrubbed = 0):
        error = None
        if not avatarName and avatarId:
            avatarName = self.findAvatarName(avatarId)
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, None, None, AVATAR_THOUGHT, None)
        if avatarId != localAvatar.doId:
            self.addHandle(avatarId, newMessage)
        reject = 0
        if avatarId:
            reject = self.addToHistoryDoId(newMessage, avatarId, scrubbed)
        if accountId:
            self.addToHistoryDISLId(newMessage, accountId)
        if reject == 1:
            newMessage.setBody(OTPLocalizer.AntiSpamInChat)
        if reject != 2:
            self.historyComplete.append(newMessage)
            self.historyOpen.append(newMessage)
            messenger.send('NewOpenMessage', [newMessage])
        return error

    def receiveGameMessage(self, message):
        error = None
        if not self.isThought(message):
            newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_GAME, None)
            self.historyComplete.append(newMessage)
            self.historyUpdates.append(newMessage)
        messenger.send('NewOpenMessage', [newMessage])
        return error

    def receiveSystemMessage(self, message):
        error = None
        if not self.isThought(message):
            newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_SYSTEM, None)
            self.historyComplete.append(newMessage)
            self.historyUpdates.append(newMessage)
        messenger.send('NewOpenMessage', [newMessage])
        return error

    def receiveFriendUpdate(self, friendId, friendName, isOnline):
        if isOnline:
            onlineMessage = OTPLocalizer.FriendOnline
        else:
            onlineMessage = OTPLocalizer.FriendOffline
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, friendId, friendName, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, UPDATE_FRIEND, None)
        self.addHandle(friendId, newMessage)
        self.historyComplete.append(newMessage)
        self.historyUpdates.append(newMessage)
        messenger.send('NewOpenMessage', [newMessage])
        return

    def receiveFriendAccountUpdate(self, friendId, friendName, isOnline):
        if isOnline:
            onlineMessage = OTPLocalizer.FriendOnline
        else:
            onlineMessage = OTPLocalizer.FriendOffline
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, None, None, friendId, friendName, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, UPDATE_FRIEND, None)
        self.historyComplete.append(newMessage)
        self.historyUpdates.append(newMessage)
        messenger.send('NewOpenMessage', [newMessage])
        return

    def receiveOpenSpeedChat(self, type, messageIndex, senderAvId, name = None):
        error = None
        if not name and senderAvId:
            name = self.findAvatarName(senderAvId)
        if type == SPEEDCHAT_NORMAL:
            message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
        elif type == SPEEDCHAT_EMOTE:
            message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
        elif type == SPEEDCHAT_CUSTOM:
            message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
        if message in (None, ''):
            return
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, name, None, None, None, None, None, None, TALK_OPEN, None)
        self.historyComplete.append(newMessage)
        self.historyOpen.append(newMessage)
        self.addToHistoryDoId(newMessage, senderAvId)
        messenger.send('NewOpenMessage', [newMessage])
        return error

    def receiveAvatarWhisperSpeedChat(self, type, messageIndex, senderAvId, name = None):
        error = None
        if not name and senderAvId:
            name = self.findAvatarName(senderAvId)
        if type == SPEEDCHAT_NORMAL:
            message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
        elif type == SPEEDCHAT_EMOTE:
            message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
        elif type == SPEEDCHAT_CUSTOM:
            message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
        newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, name, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, TALK_WHISPER, None)
        self.historyComplete.append(newMessage)
        self.historyOpen.append(newMessage)
        self.addToHistoryDoId(newMessage, senderAvId)
        messenger.send('NewOpenMessage', [newMessage])
        return error

    def sendOpenTalk(self, message):
        error = None
        doId = base.localAvatar.doId
        if base.config.GetBool('want-talkative-tyler', False):
            if base.localAvatar.zoneId == 2000:
                tyler = base.cr.doFind('Talkative Tyler')
                if tyler:
                    tyler.sendUpdate('talkMessage', [doId, message])
        if base.cr.wantMagicWords and len(message) > 0 and message[0] == '~':
            messenger.send('magicWord', [message])
        else:
            chatFlags = CFSpeech | CFTimeout
            if self.isThought(message):
                chatFlags = CFThought
            base.cr.chatAgent.sendChatMessage(message)
            messenger.send('chatUpdate', [message, chatFlags])
        return error

    def sendWhisperTalk(self, message, receiverAvId):
        modifications = []
        words = message.split(' ')
        offset = 0
        WantWhitelist = config.GetBool('want-whitelist', 1)
        for word in words:
            if word and not self.whiteList.isWord(word) and WantWhitelist:
                modifications.append((offset, offset+len(word)-1))
            offset += len(word) + 1

        cleanMessage = message
        for modStart, modStop in modifications:
            cleanMessage = cleanMessage[:modStart] + '*'*(modStop-modStart+1) + cleanMessage[modStop+1:]

        message, scrubbed = base.localAvatar.scrubTalk(cleanMessage, modifications)

        base.cr.ttuFriendsManager.sendUpdate('sendTalkWhisper', [receiverAvId, message])

    def sendOpenSpeedChat(self, type, messageIndex):
        error = None
        if type == SPEEDCHAT_NORMAL:
            messenger.send(SCChatEvent)
            messenger.send('chatUpdateSC', [messageIndex])
            base.localAvatar.b_setSC(messageIndex)
        elif type == SPEEDCHAT_EMOTE:
            messenger.send('chatUpdateSCEmote', [messageIndex])
            messenger.send(SCEmoteChatEvent)
            base.localAvatar.b_setSCEmote(messageIndex)
        elif type == SPEEDCHAT_CUSTOM:
            messenger.send('chatUpdateSCCustom', [messageIndex])
            messenger.send(SCCustomChatEvent)
            base.localAvatar.b_setSCCustom(messageIndex)
        return error

    def sendAvatarWhisperSpeedChat(self, type, messageIndex, receiverId):
        error = None
        if type == SPEEDCHAT_NORMAL:
            base.localAvatar.whisperSCTo(messageIndex, receiverId)
            message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
        elif type == SPEEDCHAT_EMOTE:
            base.localAvatar.whisperSCEmoteTo(messageIndex, receiverId)
            message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, localAvatar.getName())
        elif type == SPEEDCHAT_CUSTOM:
            base.localAvatar.whisperSCCustomTo(messageIndex, receiverId)
            message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
        if self.logWhispers:
            avatarName = None
            accountId = None
            avatar = base.cr.identifyAvatar(receiverId)
            if avatar:
                avatarName = avatar.getName()
            newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, receiverId, avatarName, None, None, TALK_WHISPER, None)
            self.historyComplete.append(newMessage)
            self.addToHistoryDoId(newMessage, localAvatar.doId)
            messenger.send('NewOpenMessage', [newMessage])
        return error