from DistributedMinigameAI import *
from direct.distributed.ClockDelta import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
from direct.task import Task
import CannonGameGlobals

class DistributedCannonGameAI(DistributedMinigameAI):

    def __init__(self, air, minigameId):
        DistributedMinigameAI.__init__(self, air, minigameId)
        self.gameFSM = ClassicFSM.ClassicFSM('DistributedCannonGameAI', [State.State('inactive', self.enterInactive, self.exitInactive, ['play']), State.State('play', self.enterPlay, self.exitPlay, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, ['inactive'])], 'inactive', 'inactive')
        self.addChildGameFSM(self.gameFSM)

    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('play')

    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 enterPlay(self):
        self.notify.debug('enterPlay')
        if not config.GetBool('endless-cannon-game', 0):
            taskMgr.doMethodLater(CannonGameGlobals.GameTime, self.timerExpired, self.taskName('gameTimer'))

    def timerExpired(self, task):
        self.notify.debug('timer expired')
        self.gameOver()
        return Task.done

    def __playing(self):
        if not hasattr(self, 'gameFSM'):
            return False
        if self.gameFSM.getCurrentState() == None:
            return False
        return self.gameFSM.getCurrentState().getName() == 'play'

    def _checkCannonRange(self, zRot, angle, avId):
        outOfRange = 0
        if zRot < CannonGameGlobals.CANNON_ROTATION_MIN or zRot > CannonGameGlobals.CANNON_ROTATION_MAX:
            self.air.writeServerEvent('suspicious', avId, 'Cannon game z-rotation out of range: %s' % zRot)
            self.notify.warning('av %s cannon z-rotation out of range: %s' % (avId, zRot))
            outOfRange = 1
        if angle < CannonGameGlobals.CANNON_ANGLE_MIN or angle > CannonGameGlobals.CANNON_ANGLE_MAX:
            self.air.writeServerEvent('suspicious', avId, 'Cannon game vertical angle out of range: %s' % angle)
            self.notify.warning('av %s cannon vertical angle out of range: %s' % (avId, angle))
            outOfRange = 1
        return outOfRange

    def setCannonPosition(self, zRot, angle):
        if not self.__playing():
            self.notify.debug('ignoring setCannonPosition message')
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('setCannonPosition: ' + str(avId) + ': zRot=' + str(zRot) + ', angle=' + str(angle))
        if self._checkCannonRange(zRot, angle, avId):
            return
        self.sendUpdate('updateCannonPosition', [avId, zRot, angle])

    def setCannonLit(self, zRot, angle):
        if not self.__playing():
            self.notify.debug('ignoring setCannonLit message')
            return
        avId = self.air.getAvatarIdFromSender()
        self.notify.debug('setCannonLit: ' + str(avId) + ': zRot=' + str(zRot) + ', angle=' + str(angle))
        if self._checkCannonRange(zRot, angle, avId):
            return
        fireTime = self.getCurrentGameTime() + CannonGameGlobals.FUSE_TIME
        self.sendUpdate('setCannonWillFire', [avId,
         fireTime,
         zRot,
         angle])

    def setToonWillLandInWater(self, landTime):
        if not self.__playing():
            self.notify.debug('ignoring setToonWillLandInWater message')
            return
        senderAvId = self.air.getAvatarIdFromSender()
        score = CannonGameGlobals.calcScore(landTime)
        for avId in self.avIdList:
            self.scoreDict[avId] = score

        self.notify.debug('setToonWillLandInWater: time=%s, score=%s' % (landTime, score))
        taskMgr.remove(self.taskName('gameTimer'))
        delay = max(0, landTime - self.getCurrentGameTime())
        taskMgr.doMethodLater(delay, self.toonLandedInWater, self.taskName('game-over'))
        self.sendUpdate('announceToonWillLandInWater', [senderAvId, landTime])

    def toonLandedInWater(self, task):
        self.notify.debug('toonLandedInWater')
        if self.__playing():
            self.gameOver()
        return Task.done

    def exitPlay(self):
        taskMgr.remove(self.taskName('gameTimer'))
        taskMgr.remove(self.taskName('game-over'))

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

    def exitCleanup(self):
        pass