# File: D (Python 2.4)

from direct.distributed.DistributedNodeAI import DistributedNodeAI
from direct.distributed.ClockDelta import *
from direct.fsm import ClassicFSM, State
from direct.fsm import State
from direct.fsm import StateData
from direct.distributed.ClockDelta import *
from direct.interval.IntervalGlobal import *

class DistributedFindFourAI(DistributedNodeAI):

    def __init__(self, air, parent, name, x, y, z, h, p, r):
        DistributedNodeAI.__init__(self, air)
        self.name = name
        self.air = air
        self.setPos(x, y, z)
        self.setHpr(h, p, r)
        self.myPos = (x, y, z)
        self.myHpr = (h, p, r)
        self.board = [
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0]]
        self.parent = self.air.doId2do[parent]
        self.parentDo = parent
        self.wantStart = []
        self.playersPlaying = []
        self.playersSitting = 0
        self.playersTurn = 1
        self.movesMade = 0
        self.playerNum = 1
        self.winDirection = None
        self.playersGamePos = [
            None,
            None]
        self.wantTimer = True
        self.timerEnd = 0
        self.turnEnd = 0
        self.playersObserving = []
        self.winLaffPoints = 20
        self.movesRequiredToWin = 10
        self.zoneId = self.air.allocateZone()
        self.generateOtpObject(air.districtId, self.zoneId, optionalFields = [
            'setX',
            'setY',
            'setZ',
            'setH',
            'setP',
            'setR'])
        self.parent.setCheckersZoneId(self.zoneId)
        self.timerStart = None
        self.fsm = ClassicFSM.ClassicFSM('Checkers', [
            State.State('waitingToBegin', self.enterWaitingToBegin, self.exitWaitingToBegin, [
                'playing']),
            State.State('playing', self.enterPlaying, self.exitPlaying, [
                'gameOver']),
            State.State('gameOver', self.enterGameOver, self.exitGameOver, [
                'waitingToBegin'])], 'waitingToBegin', 'waitingToBegin')
        self.fsm.enterInitialState()


    def announceGenerate(self):
        self.parent.setGameDoId(self.doId)


    def getTableDoId(self):
        return self.parentDo


    def delete(self):
        self.fsm.requestFinalState()
        self.parent = None
        self.parentDo = None
        del self.board
        del self.fsm
        DistributedNodeAI.delete(self)


    def informGameOfPlayer(self):
        self.playersSitting += 1
        if self.playersSitting < 2:
            self.timerEnd = 0
        elif self.playersSitting == 2:
            self.timerEnd = globalClock.getRealTime() + 20
            self.parent.isAccepting = False
            self.parent.sendUpdate('setIsPlaying', [
                1])
        elif self.playersSitting > 2:
            pass

        self.sendUpdate('setTimer', [
            globalClockDelta.localToNetworkTime(self.timerEnd)])


    def informGameOfPlayerLeave(self):
        self.playersSitting -= 1
        if self.playersSitting < 2 and self.fsm.getCurrentState().getName() == 'waitingToBegin':
            self.timerEnd = 0
            self.parent.isAccepting = True
            self.parent.sendUpdate('setIsPlaying', [
                0])

        if self.playersSitting > 2 and self.fsm.getCurrentState().getName() == 'waitingToBegin':
            pass
        1
        self.timerEnd = 0
        if self.timerEnd != 0:
            self.sendUpdate('setTimer', [
                globalClockDelta.localToNetworkTime(self.timerEnd)])
        else:
            self.sendUpdate('setTimer', [
                0])


    def setGameCountdownTime(self):
        self.timerEnd = globalClock.getRealTime() + 10


    def setTurnCountdownTime(self):
        self.turnEnd = globalClock.getRealTime() + 25


    def getTimer(self):
        if self.timerEnd != 0:
            return 0
        else:
            return 0


    def getTurnTimer(self):
        return globalClockDelta.localToNetworkTime(self.turnEnd)


    def requestTimer(self):
        avId = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avId, 'setTimer', [
            globalClockDelta.localToNetworkTime(self.timerEnd)])


    def handlePlayerExit(self, avId):
        if avId in self.wantStart:
            self.wantStart.remove(avId)

        if self.fsm.getCurrentState().getName() == 'playing':
            gamePos = self.playersGamePos.index(avId)
            self.playersGamePos[gamePos] = None
            self.fsm.request('gameOver')



    def handleEmptyGame(self):
        self.movesMade = 0
        self.playersPlaying = []
        self.playersTurn = 1
        self.playerNum = 1
        self.fsm.request('waitingToBegin')
        self.parent.isAccepting = True


    def requestWin(self, pieceNum):
        avId = self.air.getAvatarIdFromSender()
        playerNum = self.playersGamePos.index(avId) + 1
        x = pieceNum[0]
        y = pieceNum[1]
        if self.checkWin(x, y, playerNum) == True:
            self.sendUpdate('announceWinnerPosition', [
                x,
                y,
                self.winDirection,
                playerNum])
            winnersSequence = Sequence(Wait(5.0), Func(self.fsm.request, 'gameOver'), Func(self.parent.announceWinner, 'Find Four', avId))
            winnersSequence.start()
        else:
            self.sendUpdateToAvatarId(avId, 'illegalMove', [])


    def distributeLaffPoints(self):
        for x in self.parent.seats:
            if x != None:
                av = self.air.doId2do.get(x)
                av.toonUp(self.winLaffPoints)
                continue



    def enterWaitingToBegin(self):
        self.setGameCountdownTime()
        self.parent.isAccepting = True


    def exitWaitingToBegin(self):
        self.turnEnd = 0


    def enterPlaying(self):
        self.parent.isAccepting = False
        for x in self.playersGamePos:
            if x != None:
                self.playersTurn = self.playersGamePos.index(x)
                self.d_sendTurn(self.playersTurn + 1)
                break
                continue

        self.setTurnCountdownTime()
        self.sendUpdate('setTurnTimer', [
            globalClockDelta.localToNetworkTime(self.turnEnd)])


    def exitPlaying(self):
        pass


    def enterGameOver(self):
        self.timerEnd = 0
        isAccepting = True
        self.parent.handleGameOver()
        self.playersObserving = []
        self.playersTurn = 1
        self.playerNum = 1
        self.playersPlaying = []
        self.movesMade = 0
        self.playersGamePos = [
            None,
            None]
        self.parent.isAccepting = True
        self.fsm.request('waitingToBegin')


    def exitGameOver(self):
        pass


    def requestBegin(self):
        avId = self.air.getAvatarIdFromSender()
        if avId not in self.wantStart:
            self.wantStart.append(avId)

        numPlayers = 0
        for x in self.parent.seats:
            if x != None:
                numPlayers = numPlayers + 1
                continue

        if len(self.wantStart) == numPlayers and numPlayers >= 2:
            self.d_gameStart(avId)
            self.parent.sendIsPlaying()



    def d_gameStart(self, avId):
        for x in self.playersObserving:
            self.sendUpdateToAvatarId(x, 'gameStart', [
                255])

        zz = 0
        numPlayers = 0
        for x in self.parent.seats:
            if x != None:
                numPlayers += 1
                self.playersPlaying.append(x)
                continue

        if numPlayers == 2:
            player1 = self.playersPlaying[0]
            self.sendUpdateToAvatarId(player1, 'gameStart', [
                1])
            self.playersGamePos[0] = player1
            player2 = self.playersPlaying[1]
            self.sendUpdateToAvatarId(player2, 'gameStart', [
                2])
            self.playersGamePos[1] = player2

        self.wantStart = []
        self.fsm.request('playing')
        self.parent.getTableState()


    def d_sendTurn(self, playersTurn):
        self.sendUpdate('sendTurn', [
            playersTurn])


    def advancePlayerTurn(self):
        if self.playersTurn == 0:
            self.playersTurn = 1
            self.playerNum = 2
        else:
            self.playerNum = 1
            self.playersTurn = 0


    def requestMove(self, moveColumn):
        avId = self.air.getAvatarIdFromSender()
        turn = self.playersTurn
        if avId in self.playersGamePos:
            if self.playersGamePos.index(avId) != self.playersTurn:
                pass


        if self.board[0][moveColumn] != 0:
            self.sendUpdateToAvatarId(avId, 'illegalMove', [])

        for x in xrange(6):
            if self.board[x][moveColumn] == 0:
                movePos = x
                continue

        self.board[movePos][moveColumn] = self.playersTurn + 1
        if self.checkForTie() == True:
            self.sendUpdate('setGameState', [
                self.board,
                moveColumn,
                movePos,
                turn])
            self.sendUpdate('tie', [])
            winnersSequence = Sequence(Wait(8.0), Func(self.fsm.request, 'gameOver'))
            winnersSequence.start()
            return None

        self.movesMade += 1
        self.advancePlayerTurn()
        self.setTurnCountdownTime()
        self.sendUpdate('setTurnTimer', [
            globalClockDelta.localToNetworkTime(self.turnEnd)])
        self.d_sendTurn(self.playersTurn + 1)
        self.sendUpdate('setGameState', [
            self.board,
            moveColumn,
            movePos,
            turn])


    def checkForTie(self):
        for x in xrange(7):
            if self.board[0][x] == 0:
                return False
                continue

        return True


    def getState(self):
        return self.fsm.getCurrentState().getName()


    def getName(self):
        return self.name


    def getGameState(self):
        return [
            self.board,
            0,
            0,
            0]


    def clearBoard(self):
        for x in self.board.squareList:
            x.setState(0)



    def getPosHpr(self):
        return self.posHpr


    def tempSetBoardState(self):
        self.board = [
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0],
            [
                1,
                2,
                1,
                2,
                2,
                2,
                1],
            [
                2,
                2,
                1,
                2,
                1,
                2,
                1],
            [
                2,
                1,
                1,
                2,
                2,
                1,
                2],
            [
                1,
                2,
                2,
                1,
                2,
                1,
                1],
            [
                1,
                2,
                1,
                2,
                1,
                2,
                1]]
        self.sendUpdate('setGameState', [
            self.board,
            0,
            0,
            1])


    def checkWin(self, rVal, cVal, playerNum):
        if self.checkHorizontal(rVal, cVal, playerNum) == True:
            self.winDirection = 0
            return True
        elif self.checkVertical(rVal, cVal, playerNum) == True:
            self.winDirection = 1
            return True
        elif self.checkDiagonal(rVal, cVal, playerNum) == True:
            self.winDirection = 2
            return True
        else:
            self.winDirection = None
            return False


    def checkHorizontal(self, rVal, cVal, playerNum):
        if cVal == 3:
            for x in xrange(1, 4):
                if self.board[rVal][cVal - x] != playerNum:
                    break

                if self.board[rVal][cVal - x] == playerNum and x == 3:
                    return True
                    continue

            for x in xrange(1, 4):
                if self.board[rVal][cVal + x] != playerNum:
                    break

                if self.board[rVal][cVal + x] == playerNum and x == 3:
                    return True
                    continue

            return False
        elif cVal == 2:
            for x in xrange(1, 4):
                if self.board[rVal][cVal + x] != playerNum:
                    break

                if self.board[rVal][cVal + x] == playerNum and x == 3:
                    return True
                    continue

            return False
        elif cVal == 4:
            for x in xrange(1, 4):
                if self.board[rVal][cVal - x] != playerNum:
                    break

                if self.board[rVal][cVal - x] == playerNum and x == 3:
                    return True
                    continue

            return False
        else:
            return False


    def checkVertical(self, rVal, cVal, playerNum):
        if rVal == 2:
            for x in xrange(1, 4):
                if self.board[rVal + x][cVal] != playerNum:
                    break

                if self.board[rVal + x][cVal] == playerNum and x == 3:
                    return True
                    continue

            return False
        elif rVal == 3:
            for x in xrange(1, 4):
                if self.board[rVal - x][cVal] != playerNum:
                    break

                if self.board[rVal - x][cVal] == playerNum and x == 3:
                    return True
                    continue

            return False
        else:
            return False


    def checkDiagonal(self, rVal, cVal, playerNum):
        if cVal <= 2:
            if rVal == 2:
                for x in xrange(1, 4):
                    if self.board[rVal + x][cVal + x] != playerNum:
                        break

                    if self.board[rVal + x][cVal + x] == playerNum and x == 3:
                        return True
                        continue

                return False
            elif rVal == 3:
                for x in xrange(1, 4):
                    if self.board[rVal - x][cVal + x] != playerNum:
                        break

                    if self.board[rVal - x][cVal + x] == playerNum and x == 3:
                        return True
                        continue

                return False

        elif cVal >= 4:
            if rVal == 2:
                for x in xrange(1, 4):
                    if self.board[rVal + x][cVal - x] != playerNum:
                        break

                    if self.board[rVal + x][cVal - x] == playerNum and x == 3:
                        return True
                        continue

                return False
            elif rVal == 3:
                for x in xrange(1, 4):
                    if self.board[rVal - x][cVal - x] != playerNum:
                        break

                    if self.board[rVal - x][cVal - x] == playerNum and x == 3:
                        return True
                        continue

                return False

        elif rVal == 3 and rVal == 4 or rVal == 5:
            for x in xrange(1, 4):
                if self.board[rVal - x][cVal - x] != playerNum:
                    break

                if self.board[rVal - x][cVal - x] == playerNum and x == 3:
                    return True
                    continue

            for x in xrange(1, 4):
                if self.board[rVal + x][cVal - x] != playerNum:
                    break

                if self.board[rVal + x][cVal - x] == playerNum and x == 3:
                    return True
                    continue

            return False
        elif rVal == 0 and rVal == 1 or rVal == 2:
            for x in xrange(1, 4):
                if self.board[rVal + x][cVal - x] != playerNum:
                    break

                if self.board[rVal + x][cVal - x] == playerNum and x == 3:
                    return True
                    continue

            for x in xrange(1, 4):
                if self.board[rVal + x][cVal + x] != playerNum:
                    break

                if self.board[rVal + x][cVal + x] == playerNum and x == 3:
                    return True
                    continue

            return False

        return False
