from DistributedMinigameAI import *
from direct.distributed.ClockDelta import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
import RingGameGlobals
import random
import types

class DistributedRingGameAI(DistributedMinigameAI):

    def __init__(self, air, minigameId):
        try:
            self.DistributedRingGameAI_initialized
        except:
            self.DistributedRingGameAI_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedRingGameAI', [State.State('inactive', self.enterInactive, self.exitInactive, ['swimming']), State.State('swimming', self.enterSwimming, self.exitSwimming, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, ['inactive'])], 'inactive', 'inactive')
            self.addChildGameFSM(self.gameFSM)
            self.__timeBase = globalClockDelta.localToNetworkTime(globalClock.getRealTime())
            self.selectColorIndices()

    def delete(self):
        self.notify.debug('delete')
        del self.gameFSM
        DistributedMinigameAI.delete(self)

    def setGameReady(self):
        self.notify.debug('setGameReady')
        DistributedMinigameAI.setGameReady(self)

    def setGameStart(self, timestamp):
        self.notify.debug('setGameStart')
        DistributedMinigameAI.setGameStart(self, timestamp)
        self.gameFSM.request('swimming')

    def setGameAbort(self):
        self.notify.debug('setGameAbort')
        if self.gameFSM.getCurrentState():
            self.gameFSM.request('cleanup')
        DistributedMinigameAI.setGameAbort(self)

    def gameOver(self):
        self.notify.debug('gameOver')
        self.gameFSM.request('cleanup')
        DistributedMinigameAI.gameOver(self)

    def enterInactive(self):
        self.notify.debug('enterInactive')

    def exitInactive(self):
        pass

    def getTimeBase(self):
        return self.__timeBase

    def getColorIndices(self):
        return self.colorIndices

    def selectColorIndices(self):
        self.colorIndices = [None,
         None,
         None,
         None]
        chooseFrom = RingGameGlobals.ringColorSelection[:]
        for i in range(0, 4):
            c = random.choice(chooseFrom)
            chooseFrom.remove(c)
            if isinstance(c, types.TupleType):
                c = random.choice(c)
            self.colorIndices[i] = c

        return

    def enterSwimming(self):
        self.notify.debug('enterSwimming')
        self.__nextRingGroup = {}
        for avId in self.avIdList:
            self.__nextRingGroup[avId] = 0

        self.__numRingsPassed = [0] * RingGameGlobals.NUM_RING_GROUPS
        self.__ringResultBitfield = [0] * RingGameGlobals.NUM_RING_GROUPS
        self.perfectGames = {}
        for avId in self.avIdList:
            self.perfectGames[avId] = 1

        for avId in self.avIdList:
            self.scoreDict[avId] = 0

    def exitSwimming(self):
        pass

    def enterCleanup(self):
        self.notify.debug('enterCleanup')
        self.gameFSM.request('inactive')

    def exitCleanup(self):
        pass

    def setToonGotRing(self, success):
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.air.writeServerEvent('suspicious', avId, 'RingGameAI.setToonGotRing: invalid avId')
            return
        if self.gameFSM.getCurrentState() is None or self.gameFSM.getCurrentState().getName() != 'swimming':
            self.air.writeServerEvent('suspicious', avId, 'RingGameAI.setToonGotRing: game not in swimming state')
            return
        ringGroupIndex = self.__nextRingGroup[avId]
        if ringGroupIndex >= RingGameGlobals.NUM_RING_GROUPS:
            self.notify.warning('warning: got extra ToonGotRing msg from av %s' % avId)
            return
        self.__nextRingGroup[avId] += 1
        if not success:
            self.__ringResultBitfield[ringGroupIndex] |= 1 << self.avIdList.index(avId)
            self.perfectGames[avId] = 0
        else:
            self.scoreDict[avId] += 1
        self.__numRingsPassed[ringGroupIndex] += 1
        if self.__numRingsPassed[ringGroupIndex] >= self.numPlayers:
            if not self.isSinglePlayer():
                bitfield = self.__ringResultBitfield[ringGroupIndex]
                if bitfield == 0:
                    for id in self.avIdList:
                        self.scoreDict[id] += 0.5

                self.sendUpdate('setRingGroupResults', [bitfield])
            if ringGroupIndex >= RingGameGlobals.NUM_RING_GROUPS - 1:
                perfectBonuses = {1: 5,
                 2: 5,
                 3: 10,
                 4: 18}
                numPerfectToons = 0
                for avId in self.avIdList:
                    if self.perfectGames[avId]:
                        numPerfectToons += 1

                for avId in self.avIdList:
                    if self.perfectGames[avId]:
                        self.scoreDict[avId] += perfectBonuses[numPerfectToons]
                        self.logPerfectGame(avId)

                for avId in self.avIdList:
                    self.scoreDict[avId] = max(1, self.scoreDict[avId])

                if not RingGameGlobals.ENDLESS_GAME:
                    self.gameOver()
        return
