from DistributedMinigameAI import *
from direct.distributed.ClockDelta import *
from direct.interval.IntervalGlobal import *
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.actor import Actor
import DivingGameGlobals
import random
import random
import types

class DistributedDivingGameAI(DistributedMinigameAI):
    fishProportions = []
    for i in xrange(6):
        fishProportions.append([])

    n = 100
    fishProportions[0]
    fishProportions[0].append(([0, 0.8],
     [0.8, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[0].append(([0, 0.8],
     [0.8, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[0].append(([0, 0.7],
     [0.7, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[0].append(([0, 0.7],
     [0.7, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[0].append(([0, 0.5],
     [0.5, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[0].append(([n, 0.5],
     [0.5, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[1]
    fishProportions[1].append(([0, 0.8],
     [0.8, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[1].append(([0, 0.8],
     [0.8, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[1].append(([0, 0.7],
     [0.7, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[1].append(([0, 0.7],
     [0.7, 0.9],
     [n, n],
     [n, n],
     [n, n],
     [0.9, 1]))
    fishProportions[1].append(([0, 0.4],
     [0.4, 0.8],
     [n, n],
     [n, n],
     [n, n],
     [0.8, 1]))
    fishProportions[1].append(([n, 0.3],
     [0.3, 0.6],
     [n, n],
     [n, n],
     [n, n],
     [0.6, 1]))
    fishProportions[2]
    fishProportions[2].append(([0, 0.7],
     [0.7, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[2].append(([0, 0.6],
     [0.6, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[2].append(([0, 0.6],
     [0.6, 0.8],
     [n, n],
     [0.8, 1],
     [n, n],
     [n, n]))
    fishProportions[2].append(([0, 0.5],
     [0.5, 0.7],
     [n, n],
     [0.7, 0.9],
     [n, n],
     [0.9, 1]))
    fishProportions[2].append(([0, 0.2],
     [0.2, 0.4],
     [n, n],
     [0.4, 0.75],
     [n, n],
     [0.75, 1]))
    fishProportions[2].append(([n, 0.2],
     [0.2, 0.6],
     [n, n],
     [0.6, 0.8],
     [n, n],
     [0.8, 1]))
    fishProportions[3]
    fishProportions[3].append(([0, 0.7],
     [0.7, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[3].append(([0, 0.6],
     [0.6, 1],
     [n, n],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[3].append(([0, 0.6],
     [0.6, 0.8],
     [n, n],
     [0.95, 1],
     [n, n],
     [n, n]))
    fishProportions[3].append(([0, 0.5],
     [0.5, 0.7],
     [n, n],
     [0.7, 0.85],
     [0.9, 0.95],
     [0.95, 1]))
    fishProportions[3].append(([0, 0.2],
     [0.2, 0.4],
     [n, n],
     [0.4, 0.75],
     [0.75, 0.85],
     [0.85, 1]))
    fishProportions[3].append(([n, 0.2],
     [0.2, 0.6],
     [n, n],
     [0.6, 0.8],
     [n, n],
     [0.8, 1]))
    fishProportions[4]
    fishProportions[4].append(([0, 0.7],
     [0.7, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[4].append(([0, 0.45],
     [0.45, 0.9],
     [n, n],
     [0.9, 1],
     [n, n],
     [n, n]))
    fishProportions[4].append(([0, 0.2],
     [0.2, 0.5],
     [n, n],
     [0.5, 0.95],
     [0.95, 1],
     [n, n]))
    fishProportions[4].append(([0, 0.1],
     [0.1, 0.3],
     [n, n],
     [0.3, 0.75],
     [0.75, 0.8],
     [0.8, 1]))
    fishProportions[4].append(([n, n],
     [0, 0.15],
     [n, n],
     [0.15, 0.4],
     [n, n],
     [0.4, 1]))
    fishProportions[4].append(([n, n],
     [n, n],
     [n, n],
     [0, 0.4],
     [n, n],
     [0.6, 1]))
    fishProportions[5]
    fishProportions[5].append(([0, 0.7],
     [0.7, 0.9],
     [0.9, 1],
     [n, n],
     [n, n],
     [n, n]))
    fishProportions[5].append(([0, 0.45],
     [0.45, 0.9],
     [n, n],
     [0.9, 1],
     [n, n],
     [n, n]))
    fishProportions[5].append(([0, 0.2],
     [0.2, 0.5],
     [n, n],
     [0.5, 0.95],
     [0.95, 1],
     [n, n]))
    fishProportions[5].append(([0, 0.1],
     [0.1, 0.3],
     [n, n],
     [0.3, 0.75],
     [0.75, 0.8],
     [0.8, 1]))
    fishProportions[5].append(([n, n],
     [0, 0.15],
     [n, n],
     [0.15, 0.4],
     [n, n],
     [0.4, 1]))
    fishProportions[5].append(([n, n],
     [n, n],
     [n, n],
     [0, 0.4],
     [n, n],
     [0.6, 1]))
    difficultyPatternsAI = {ToontownGlobals.ToontownCentral: [3.5, fishProportions[0], 1.5],
     ToontownGlobals.DonaldsDock: [3.0, fishProportions[1], 1.8],
     ToontownGlobals.DaisyGardens: [2.5, fishProportions[2], 2.1],
     ToontownGlobals.MinniesMelodyland: [2.0, fishProportions[3], 2.4],
     ToontownGlobals.TheBrrrgh: [2.0, fishProportions[4], 2.7],
     ToontownGlobals.DonaldsDreamland: [1.5, fishProportions[5], 3.0]}

    def __init__(self, air, minigameId):
        try:
            self.DistributedDivingGameAI_initialized
        except:
            self.DistributedDivingGameAI_initialized = 1
            DistributedMinigameAI.__init__(self, air, minigameId)
            self.gameFSM = ClassicFSM.ClassicFSM('DistributedDivingGameAI', [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())

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

    def setGameReady(self):
        self.notify.debug('setGameReady')
        self.sendUpdate('setTrolleyZone', [self.trolleyZone])
        for avId in self.scoreDict.keys():
            self.scoreDict[avId] = 0

        self.treasureHolders = [0] * self.numPlayers
        self.SPAWNTIME = self.difficultyPatternsAI[self.getSafezoneId()][0]
        self.proportion = self.difficultyPatternsAI[self.getSafezoneId()][1]
        self.REWARDMOD = self.difficultyPatternsAI[self.getSafezoneId()][2]
        DistributedMinigameAI.setGameReady(self)
        self.spawnings = []
        for i in xrange(DivingGameGlobals.NUM_SPAWNERS):
            self.spawnings.append(Sequence(Func(self.spawnFish, i), Wait(self.SPAWNTIME + random.random()), Func(self.spawnFish, i), Wait(self.SPAWNTIME - 0.5 + random.random())))
            self.spawnings[i].loop()

    def setGameStart(self, timestamp):
        self.notify.debug('setGameStart')
        DistributedMinigameAI.setGameStart(self, timestamp)
        self.gameFSM.request('swimming')
        self.scoreTracking = {}
        for avId in self.scoreDict.keys():
            self.scoreTracking[avId] = [0,
             0,
             0,
             0,
             0]

    def getCrabMoving(self, crabId, crabX, dir):
        timestamp = globalClockDelta.getFrameNetworkTime()
        rand1 = int(random.random() * 10)
        rand2 = int(random.random() * 10)
        self.sendUpdate('setCrabMoving', [crabId,
         timestamp,
         rand1,
         rand2,
         crabX,
         dir])

    def treasureRecovered(self):
        if not hasattr(self, 'scoreTracking'):
            return
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.treasureRecovered: invalid avId')
            return

        if avId not in self.treasureHolders:
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.treasureRecovered: tried to recover without holding treasure')
            return

        self.treasureHolders[self.treasureHolders.index(avId)] = 0

        timestamp = globalClockDelta.getFrameNetworkTime()
        newSpot = int(random.random() * 30)
        self.scoreTracking[avId][4] += 1
        for someAvId in self.scoreDict.keys():
            if someAvId == avId:
                self.scoreDict[avId] += 10 * (self.REWARDMOD * 0.25)
            self.scoreDict[someAvId] += 10 * (self.REWARDMOD * 0.75 / float(len(self.scoreDict.keys())))

        self.sendUpdate('incrementScore', [avId, newSpot, timestamp])

    def hasScoreMult(self):
        return 0

    def setGameAbort(self):
        self.notify.debug('setGameAbort')
        taskMgr.remove(self.taskName('gameTimer'))
        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)
        trackingString = 'MiniGame Stats : Diving Game'
        trackingString += '\nDistrict:%s' % self.getSafezoneId()
        for avId in self.scoreTracking.keys():
            trackingString = trackingString + '\navId:%s fishHits:%s crabHits:%s treasureCatches:%s treasureDrops:%s treasureRecoveries:%s Score: %s' % (avId,
             self.scoreTracking[avId][0],
             self.scoreTracking[avId][1],
             self.scoreTracking[avId][2],
             self.scoreTracking[avId][3],
             self.scoreTracking[avId][4],
             self.scoreDict[avId])

        self.air.writeServerEvent('MiniGame Stats', None, trackingString)
        return

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

    def exitInactive(self):
        pass

    def getTimeBase(self):
        return self.__timeBase

    def enterSwimming(self):
        self.notify.debug('enterSwimming')
        duration = 65.0
        taskMgr.doMethodLater(duration, self.timerExpired, self.taskName('gameTimer'))

    def timerExpired(self, task):
        self.notify.debug('timer expired')
        for avId in self.scoreDict.keys():
            if self.scoreDict[avId] < 5:
                self.scoreDict[avId] = 5

        self.gameOver()
        return Task.done

    def exitSwimming(self):
        for i in xrange(DivingGameGlobals.NUM_SPAWNERS):
            self.spawnings[i].pause()

    def enterCleanup(self):
        self.notify.debug('enterCleanup')
        for i in xrange(DivingGameGlobals.NUM_SPAWNERS):
            self.spawnings[i].finish()

        del self.spawnings
        self.gameFSM.request('inactive')

    def exitCleanup(self):
        pass

    def pickupTreasure(self, chestId):
        if not hasattr(self, 'scoreTracking'):
            return
        timestamp = globalClockDelta.getFrameNetworkTime()
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.avIdList:
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.pickupTreasure: invalid avId')
            return
        if avId in self.treasureHolders:
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.pickupTreasure: already holding treasure')
            return
        if not (0 <= chestId < len(self.treasureHolders)):
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.pickupTreasure: invalid chest requested (#%d)' % chestId)
            return
        if self.treasureHolders[chestId]:
            # This chest is already held by someone else. Because this can happen
            # during normal play (race conditions if two Toons swim into the treasure
            # simultaneously) we do not log a suspicious event and silently ignore it.
            return
        self.scoreTracking[avId][2] += 1
        self.treasureHolders[chestId] = avId
        self.sendUpdate('setTreasureGrabbed', [avId, chestId])

    def spawnFish(self, spawnerId):
        timestamp = globalClockDelta.getFrameNetworkTime()
        props = self.proportion[spawnerId]
        num = random.random()
        for i in xrange(len(props)):
            prop = props[i]
            low = prop[0]
            high = prop[1]
            if num > low and num <= high:
                offset = int(10 * random.random())
                self.sendUpdate('fishSpawn', [timestamp,
                 i,
                 spawnerId,
                 offset])
                return

    def handleCrabCollision(self, avId, status):
        if avId not in self.avIdList:
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.handleCrabCollision: invalid avId')
            return
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate('setTreasureDropped', [avId, timestamp])
        self.scoreTracking[avId][1] += 1
        if status == 'normal' or status == 'treasure':
            timestamp = globalClockDelta.getFrameNetworkTime()
            self.sendUpdate('performCrabCollision', [avId, timestamp])
            if status == 'treasure':
                if avId in self.treasureHolders:
                    self.treasureHolders[self.treasureHolders.index(avId)] = 0
                    self.scoreTracking[avId][3] += 1
                else:
                    self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.handleCrabCollision: reported "treasure drop" without holding treasure')

    def handleFishCollision(self, avId, spawnId, spawnerId, status):
        if avId not in self.avIdList:
            self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.handleFishCollision: invalid avId')
            return
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate('setTreasureDropped', [avId, timestamp])
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.scoreTracking[avId][0] += 1
        if status == 'treasure':
            if avId in self.treasureHolders:
                self.treasureHolders[self.treasureHolders.index(avId)] = 0
                self.scoreTracking[avId][3] += 1
            else:
                self.air.writeServerEvent('suspicious', avId, 'DivingGameAI.handleFishCollision: reported "treasure drop" without holding treasure')
        self.sendUpdate('performFishCollision', [avId,
         spawnId,
         spawnerId,
         timestamp])
