from otp.ai.AIBase import *
from direct.interval.IntervalGlobal import *
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import ClockDelta
from direct.task import Task
from otp.level import DistributedEntityAI
from otp.level import BasicEntities
from toontown.coghq import BattleBlockerAI
from direct.distributed.ClockDelta import *
from toontown.toonbase import ToontownBattleGlobals
from .GolfGreenGameGlobals import *
import random, time

class DistributedGolfGreenGameAI(BattleBlockerAI.BattleBlockerAI, NodePath, BasicEntities.NodePathAttribs):

    def __init__(self, level, entId):
        BattleBlockerAI.BattleBlockerAI.__init__(self, level, entId)
        random.seed(time.time() * entId)
        node = hidden.attachNewNode('DistributedLaserFieldAI')
        NodePath.__init__(self, node)
        if not hasattr(self, 'switchId'):
            self.switchId = 0
        self.gridScale = 1
        self.enabled = 1
        self.hasShownSuits = 0
        self.healReady = 1
        self.playedSound = 0
        self.canButton = 1
        self.allBoardsClear = 0
        self.challengeDefeated = False
        self.title = 'MemTag: This is a golfGreenGame %s' % random.random()
        self.translateData = {}
        self.translateData['r'] = 0
        self.translateData['b'] = 1
        self.translateData['g'] = 2
        self.translateData['w'] = 3
        self.translateData['k'] = 4
        self.translateData['l'] = 5
        self.translateData['y'] = 6
        self.translateData['o'] = 7
        self.translateData['a'] = 8
        self.translateData['s'] = 9
        self.translateData['R'] = 10
        self.translateData['B'] = 11
        self.preData = []
        self.boardList = []
        self.joinedToons = []
        self.everJoinedToons = []
        self.startTime = None
        self.totalTime = 1180.0
        self.DamageOnFailure = 20.0
        return

    def announceGenerate(self):
        BattleBlockerAI.BattleBlockerAI.announceGenerate(self)
        self.totalTime = self.timeToPlay
        numToons = 0
        if hasattr(self, 'level'):
            numToons = len(self.level.presentAvIds)
        numBoards = self.puzzleBase + numToons * self.puzzlePerPlayer
        boardSelect = list(range(0, len(gameBoards)))
        didGetLast = 1
        for index in range(numBoards):
            choice = random.choice(boardSelect)
            if not didGetLast:
                didGetLast = 1
                choice = len(gameBoards) - 1
            self.preData.append(gameBoards[choice])
            boardSelect.remove(choice)
            self.boardList.append([[], index, index, None])

        self.boardData = []
        self.attackPatterns = []
        self.processPreData()
        return

    def processPreData(self):
        for board in self.preData:
            x = []
            for rowIndex in range(1, len(board)):
                for columnIndex in range(len(board[rowIndex])):
                    color = self.translateData.get(board[rowIndex][columnIndex])
                    if color != None:
                        x.append((len(board[rowIndex]) - (columnIndex + 1), rowIndex - 1, color))

            self.boardData.append(x)

        for board in self.preData:
            attackString = board[0]
            attackPattern = []
            for ball in attackString:
                color = self.translateData.get(ball)
                if color or color == 0:
                    place = random.choice(list(range(0, len(attackPattern) + 1)))
                    attackPattern.insert(place, color)
                    place = random.choice(list(range(0, len(attackPattern) + 1)))
                    attackPattern.insert(place, color)

            self.attackPatterns.append(attackPattern)

        return

    def startTimer(self):
        self.startTime = globalClockDelta.getFrameNetworkTime()
        taskMgr.doMethodLater(self.totalTime, self.__handleTimeOut, self.taskName('GolfGreenGameTimeout'))
        self.sendUpdate('setTimerStart', [self.totalTime, self.startTime])

    def __printTime(self, task):
        print('Time Left %s' % self.getTimeLeft())
        taskMgr.doMethodLater(1.0, self.__printTime, self.taskName('GolfGreenGameTimeout Print'))
        return task.done

    def __handleTimeOut(self, task=None):
        taskMgr.remove(self.taskName('GolfGreenGameTimeout'))
        self.__handleFinsihed(0)
        return task.done

    def getTimeLeft(self):
        if self.startTime == None:
            return self.totalTime
        else:
            timePassed = globalClockDelta.localElapsedTime(self.startTime)
            timeLeft = self.totalTime - timePassed
            return timeLeft
        return

    def choosePattern(self):
        dataSize = len(self.boardData)
        indexChoice = int(random.random() * dataSize)
        boardToAssign = None
        for boardIndex in range(len(self.boardList)):
            board = self.boardList[boardIndex]
            if self.boardList[boardIndex][0] == 'closed':
                pass
            elif boardToAssign == None or len(self.boardList[boardIndex][0]) < len(self.boardList[boardToAssign][0]):
                boardToAssign = boardIndex
            elif len(self.boardList[boardIndex][0]) == len(self.boardList[boardToAssign][0]):
                choice = random.choice(list(range(2)))
                if choice:
                    boardToAssign = boardIndex

        if boardToAssign == None:
            pass
        return boardToAssign

    def checkForAssigned(self, avId):
        for index in range(len(self.boardList)):
            board = self.boardList[index]
            if board[0] == 'closed':
                pass
            elif avId in board[0]:
                return index

        return None

    def leaveGame(self):
        senderId = self.air.getAvatarIdFromSender()
        if senderId in self.joinedToons:
            self.joinedToons.remove(senderId)
            self.sendUpdate('acceptJoin', [self.totalTime, self.startTime, self.joinedToons])
        for boardDatum in self.boardList:
            if boardDatum[0] == 'closed':
                pass
            elif senderId in boardDatum[0]:
                boardDatum[0].remove(senderId)

    def requestJoin(self):
        if self.allBoardsClear:
            self.sendUpdate('acceptJoin', [0.0, 0.0, [0]])
            return
        senderId = self.air.getAvatarIdFromSender()
        if senderId not in self.joinedToons:
            if self.startTime == None:
                self.startTimer()
            self.joinedToons.append(senderId)
            if senderId not in self.everJoinedToons:
                self.everJoinedToons.append(senderId)
            self.sendUpdate('acceptJoin', [self.totalTime, self.startTime, self.joinedToons])
            self.sendScoreData()
        return

    def requestBoard(self, boardVerify):
        senderId = self.air.getAvatarIdFromSender()
        assigned = self.checkForAssigned(senderId)
        if assigned != None:
            if self.boardList[assigned][0] == 'closed':
                return
            if boardVerify:
                toon = simbase.air.doId2do.get(senderId)
                if toon:
                    self.addGag(senderId)
                    self.sendUpdate('helpOthers', [senderId])
                for avId in self.boardList[assigned][0]:
                    if avId != senderId:
                        self.sendUpdateToAvatarId(avId, 'boardCleared', [senderId])

                self.boardList[assigned][0] = 'closed'
                self.boardList[assigned][3] = senderId
                self.sendScoreData()
            else:
                self.boardList[assigned][0].remove(senderId)
        boardIndex = self.choosePattern()
        if boardIndex == None:
            self.__handleFinsihed(1)
        else:
            self.boardList[boardIndex][0].append(senderId)
            self.sendUpdateToAvatarId(senderId, 'startBoard', [self.boardData[self.boardList[boardIndex][1]], self.attackPatterns[self.boardList[boardIndex][2]]])
        return

    def addGag(self, avId):
        av = simbase.air.doId2do.get(avId)
        if av:
            level = ToontownBattleGlobals.LAST_REGULAR_GAG_LEVEL
            track = int(random.random() * ToontownBattleGlobals.NUM_GAG_TRACKS)
            while not av.hasTrackAccess(track):
                track = int(random.random() * ToontownBattleGlobals.NUM_GAG_TRACKS)

            maxGags = av.getMaxCarry()
            av.inventory.calcTotalProps()
            numGags = av.inventory.totalProps
            numReward = min(1, maxGags - numGags)
            while numReward > 0 and level >= 0:
                result = av.inventory.addItem(track, level)
                if result <= 0:
                    level -= 1
                else:
                    numReward -= 1
                    self.sendUpdateToAvatarId(avId, 'informGag', [track, level])

            av.d_setInventory(av.inventory.makeNetString())

    def __handleFinsihed(self, success):
        self.allBoardsClear = 1
        self.sendUpdate('signalDone', [success])
        self.switchFire()
        taskMgr.remove(self.taskName('GolfGreenGameTimeout'))
        if success:
            for avId in self.joinedToons:
                self.addGag(avId)
                toon = simbase.air.doId2do.get(avId)
                timeleft = int(self.getTimeLeft())
                if toon and timeleft > 0:
                    toon.toonUp(timeleft)

        else:
            roomId = self.getLevelDoId()
            room = simbase.air.doId2do.get(roomId)
            if room:
                playerIds = self.everJoinedToons
                for avId in playerIds:
                    av = simbase.air.doId2do.get(avId)
                    if av:
                        av.takeDamage(self.DamageOnFailure, quietly=0)
                        room.sendUpdate('forceOuch', [self.DamageOnFailure])

        if not self.challengeDefeated:
            self.challengeDefeated = True
            roomId = self.getLevelDoId()
            room = simbase.air.doId2do.get(roomId)
            if room:
                self.challengeDefeated = True
                room.challengeDefeated()
                eventName = self.getOutputEventName()
                messenger.send(eventName, [1])

    def switchFire(self):
        if self.switchId != 0:
            switch = self.level.getEntity(self.switchId)
            if switch:
                switch.setIsOn(1)

    def generate(self):
        BattleBlockerAI.BattleBlockerAI.generate(self)
        if self.switchId != 0:
            self.accept(self.getOutputEventName(self.switchId), self.reactToSwitch)
        self.detectName = 'golfGreenGame %s' % self.doId
        taskMgr.doMethodLater(1.0, self.__detect, self.detectName)
        self.setPos(self.pos)
        self.setHpr(self.hpr)

    def registerBlocker(self):
        BattleBlockerAI.BattleBlockerAI.registerBlocker(self)
        if hasattr(self, 'hideSuits'):
            self.hideSuits()

    def delete(self):
        taskMgr.remove(self.detectName)
        self.ignoreAll()
        BattleBlockerAI.BattleBlockerAI.delete(self)

    def destroy(self):
        self.notify.info('destroy entity(laserField) %s' % self.entId)
        BattleBlockerAI.BattleBlockerAI.destroy(self)

    def __detect(self, task):
        isThereAnyToons = False
        if hasattr(self, 'level'):
            toonInRange = 0
            for avId in self.level.presentAvIds:
                if avId in self.air.doId2do:
                    av = self.air.doId2do[avId]
                    isThereAnyToons = True
                    distance = self.getDistance(av)

            if isThereAnyToons:
                taskMgr.doMethodLater(1.0, self.__detect, self.detectName)
                self.__run()
        return Task.done

    def __run(self):
        pass

    def reactToSwitch(self, on):
        pass

    def setBattleFinished(self):
        BattleBlockerAI.BattleBlockerAI.setBattleFinished(self)
        messenger.send(self.getOutputEventName(), [1])
        self.switchFire()

    def sendScoreData(self):
        total = len(self.boardList)
        closed = 0
        scoreDict = {}
        for board in self.boardList:
            if board[0] == 'closed':
                closed += 1
                if board[3] not in scoreDict:
                    scoreDict[board[3]] = 1
                else:
                    scoreDict[board[3]] += 1

        outList = []
        for key in scoreDict:
            score = scoreDict[key]
            outList.append([key, score])

        self.sendUpdate('scoreData', [total, closed, outList])