from PlasmaServer import *

heekPlayerList = []
curtime = 0
lastupdate = 0
countdownStarted = 0
winners = []
pot = 0

agePlayers = [] # a list of all people in the age, tuple where 0 is ID and 1 is Key
queueCleanup = 0 # do we need to send a cleanup message to the first person to link in?

kNone = 0
kRock = 1
kPaper = 2
kScissors = 3

class heekPlayer:
    def __init__(self):
        self.ID = -1
        self.key = None
        self.pos = -1
        self.choice = kNone
        self.rocksWon = 0
        self.papersWon = 0
        self.scissorsWon = 0
        self.roundsWon = 0
        self.curRoundScore = 0
        self.points = -1
        self.isPlaying = 0
        self.name = ""
        self.scoreDict = { (kRock, kRock): 0,
                            (kRock, kPaper): -1,
                            (kRock, kScissors): 1,
                            (kRock, kNone): 0,
                            
                            (kPaper, kRock): 1,
                            (kPaper, kPaper): 0,
                            (kPaper, kScissors): -1,
                            (kPaper, kNone): 0,
                            
                            (kScissors, kRock): -1,
                            (kScissors, kPaper): 1,
                            (kScissors, kScissors): 0,
                            (kScissors, kNone): 0,
                            
                            (kNone, kNone): 0,
                            (kNone, kRock): 0,
                            (kNone, kPaper): 0,
                            (kNone, kScissors): 0
                            }
    
    def ScoreAgainst(self,other):
        return self.scoreDict[(self.choice,other.choice)]
    
    def ResetGame(self):
        self.choice = kNone
        self.rocksWon = 0
        self.papersWon = 0
        self.scissorsWon = 0
        self.curRoundScore = 0
        self.isPlaying = 0

    def ResetRound(self):
        self.curRoundScore = 0
        self.choice = kNone
    
    def SendMessage(self,contents):
        msg = ptPythonMsg()
        msg.setKey(self.key)
        msg.setContents(str(contents))
        msg.send(self.ID)

def SendToAll(message):
    global heekPlayerList
    for player in heekPlayerList:
        player.SendMessage(message)


def CalculateRank(points):
    if points == 0:
        return 0
    gamesWinToRank = 100 # number of 1v1 games against same rank to level
    rank = 1
    curPoints = gamesWinToRank
    while 1:
        curPoints += rank*gamesWinToRank
        if points <= curPoints:
            return rank
        rank += 1

def CalculateAnte(points):
    return CalculateRank(points)
    
def SendWelcomeMsg(name,points):
    global heekPlayerList
    SendToAll("PlrWelcome "+str(points)+' '+str(CalculateAnte(points))+' '+name)   

def SendStatusMsg(player):
    player.SendMessage("Points "+str(player.points)+' '+str(CalculateAnte(player.points)))

def RewardRoundWinners():
    global winners
    global heekPlayerList
    for winner in winners:
        winner.roundsWon += 1
        lightNum = 0
        if winner.choice == kRock:
            winner.rocksWon += 1
            lightNum = winner.rocksWon
        elif winner.choice == kPaper:
            winner.papersWon += 1
            lightNum = winner.papersWon
        elif winner.choice == kScissors:
            winner.scissorsWon += 1
            lightNum = winner.scissorsWon
        if lightNum == 0: # shouldn't happen, but just in case
            print "lightNum is 0 for some reason...len(winners)="+str(len(winners))+", winner.choice="+str(winner.choice)
            print "len(heekPlayerList)="+str(len(heekPlayerList))+", winner.ID="+str(winner.ID)+", winner.pos="+str(winner.pos)
            return
        winner.SendMessage("Win "+str(winner.choice))
        if lightNum < 3:
            light = (winner.choice-1)*2+(lightNum-1)
            winner.SendMessage("LightOn "+str(light))
        elif lightNum == 3:
            light1 = (winner.choice-1)*2
            light2 = light1+1
            winner.SendMessage("Flash "+str(light1))
            winner.SendMessage("Flash "+str(light2))
    losers = [player for player in heekPlayerList if not player in winners]
    for loser in losers:
        loser.SendMessage("Lose "+str(loser.choice))

def CompareRoundScores(player1, player2):
    if player1.curRoundScore < player2.curRoundScore:
        return -1
    if player1.curRoundScore > player2.curRoundScore:
        return 1
    return 0
    
def ComputeRoundScores():
    global heekPlayerList
    cnt = len(heekPlayerList)
    
    #if cnt == 1: # for single-player only
        #heekPlayerList[0].curRoundScore = 1
    
    for i in range(cnt-1):
        player1 = heekPlayerList[i]
        for j in range(i+1,cnt):
            player2 = heekPlayerList[j]
            player1.curRoundScore += player1.ScoreAgainst(player2)
            player2.curRoundScore += player2.ScoreAgainst(player1)

def PickRoundWinners():
    global heekPlayerList
    global winners
    rwCopy = heekPlayerList
    rwCopy.sort(CompareRoundScores)
    big=rwCopy[len(rwCopy)-1].curRoundScore
    if big>0:
        winners = [winner for winner in rwCopy if winner.curRoundScore == big]

def CompareRoundsWon(player1, player2):
    if player1.roundsWon < player2.roundsWon:
        return -1
    if player1.roundsWon > player2.roundsWon:
        return 1
    return 0

def PickGameWinners():
    global winners
    gameWinners = [winner for winner in winners if winner.rocksWon == 3 or winner.papersWon == 3 or winner.scissorsWon == 3]
    if (len(gameWinners) <= 1):
        return gameWinners
    gwCopy = gameWinners
    gwCopy.sort(CompareRoundsWon)
    big=gwCopy[len(gwCopy)-1].roundsWon
    if big>0:
        gameWinners = [winner for winner in gwCopy if winner.roundsWon==big]
    return gameWinners

def HandlePlayerReady():
    global countdownStarted
    global heekPlayerList
    if not countdownStarted:
        print "Starting countdown"
        SendToAll("StartCountdown")
        countdownStarted = 1
        return
    
    playersReady = [player for player in heekPlayerList if player.choice != kNone]
    allReady = (len(playersReady) == len(heekPlayerList))
    
    if allReady and len(playersReady)>1:
        SendToAll("StopCountdown")

def ResetGame():
    global heekPlayerList
    global winners
    winners = []
    for player in heekPlayerList:
        player.ResetGame()

def ResetRound():
    global heekPlayerList
    global winners
    winners = []
    for player in heekPlayerList:
        player.ResetRound()

def PlayGame():
    global countdownStarted
    global heekPlayerList
    global pot
    if not countdownStarted:
        print "Extra countdown end message received, ignoring"
        return # extra countdown end message, ignore
    countdownStarted = 0
    playersReady = [player for player in heekPlayerList if player.choice != kNone]
    if len(playersReady) <= 1:
        print "Only one player was ready, aborting game"
        ResetRound()
        SendToAll("ShowIdleAnimation")
        return
    print "Disabling player's interfaces"
    SendToAll("Disable")
    ComputeRoundScores()
    PickRoundWinners()
    RewardRoundWinners()

def HandleGameWinner():
    global heekPlayerList
    global pot
    gameWinners = PickGameWinners()
    if len(gameWinners) > 0:
        print "A player has won, letting admin know about it"
        x = "init"
        if (gameWinners[0].choice == kRock): # it might be possible for multiple types to win, will need to check
            x = "rock"
        elif (gameWinners[0].choice == kPaper):
            x = "paper"
        elif (gameWinners[0].choice == kScissors):
            x = "scissors"
        SendToAll("GameWin "+x)
        pointsToGive = int(pot/len(gameWinners))
        pot -= pointsToGive*len(gameWinners)
        for winner in gameWinners:
            if winner.points != -1:
                winner.SendMessage("SetPoints "+str(winner.points+pointsToGive))
                for player in heekPlayerList:
                    if player.ID == winner.ID and player.key == winner.key:
                        player.points += pointsToGive
                        break
        ResetGame()
        for player in heekPlayerList:
            SendStatusMsg(player)
        return 1
    return 0

def SendTableState(ID,key):
    global heekPlayerList
    for player in heekPlayerList:
        setupMsg = ptPythonMsg()
        setupMsg.setKey(key)
        setupStr = "SetupP"+str(player.pos)
        setupMsg.setContents(setupStr+"B") # enable buttons
        setupMsg.send(ID)
        if player.rocksWon >= 1:
            setupMsg.setContents(setupStr+"L0")
            setupMsg.send(ID)
        if player.rocksWon >= 2:
            setupMsg.setContents(setupStr+"L1")
            setupMsg.send(ID)
        if player.papersWon >= 1:
            setupMsg.setContents(setupStr+"L2")
            setupMsg.send(ID)
        if player.papersWon >= 2:
            setupMsg.setContents(setupStr+"L3")
            setupMsg.send(ID)
        if player.scissorsWon >= 1:
            setupMsg.setContents(setupStr+"L4")
            setupMsg.send(ID)
        if player.scissorsWon >= 2:
            setupMsg.setContents(setupStr+"L5")
            setupMsg.send(ID)

def onInit():
    global heekPlayerList
    global lastupdate
    global countdownStarted
    global winners
    global queueCleanup
    global pot
    print "Neighborhood.py is initializing"
    heekPlayerList = []
    winners = []
    lastupdate = 0
    countdownStarted = 0
    queueCleanup = []
    pot = 0

def onShutdown():
    print "Neighborhood.py is shutting down"

#def onUpdate(secs):
    #global curtime
    #global lastupdate
    #global heekPlayerList
    #if lastupdate == 0:
        #lastupdate = secs
    #curtime = secs
    #if curtime - lastupdate >= 1:
        # put any code here that wants to be run every second (nothing currently)
        #lastupdate += 1

def onClientLeft(ID):
    global heekPlayerList
    global agePlayers
    global queueCleanup
    position = -1
    for player in heekPlayerList[:]:
        if player.ID == ID:
            position = player.pos
            heekPlayerList.remove(player)
    for player in agePlayers[:]:
        if player[0] == ID:
            agePlayers.remove(player)
    if position == -1: # client wasn't playing
        return
    print "Client ID# "+str(ID)+" has left, cleaning up after him"
    if len(heekPlayerList) == 0: # no players left to cleanup the position
        if len(agePlayers) == 0: # no players in age left to cleanup the table
            queueCleanup.append(position)
        else:
            cleanup = ptPythonMsg()
            cleanup.setContents("Cleanup "+str(position))
            cleanup.setKey(agePlayers[0][1])
            cleanup.send(agePlayers[0][0])
            cleanup.setContents("ShowIdleAnimation")
            cleanup.send(agePlayers[0][0])
    for num in range(len(heekPlayerList)): # let everyone know of their new player numbers
        numberMsg = ptPythonMsg()
        numberMsg.setKey(heekPlayerList[num].key)
        numberMsg.setContents("Number "+str(num+1))
        numberMsg.send(heekPlayerList[num].ID)
    if position != -1:
        SendToAll("Drop "+str(position))

def onMsgReceived(msg):
    global heekPlayerList
    global countdownStarted
    global agePlayers
    global queueCleanup
    global pot
    msgContents = msg.getContents()
    senderID = msg.getSenderID()
    key = msg.getKey()
    print "Message received from client. ID#: "+str(msg.getSenderID())+" Contents: "+msg.getContents()
    if len(msgContents) > 3 and msgContents[:3] == "Add": # they want to be added to our player list
        pos = msgContents[4:]
        for player in heekPlayerList:
            if player.pos == pos:
                print "Ignoring client ID# "+str(senderID)+" request to play since someone is already sitting in their requested position: "+str(pos)
                return
        print "Adding client ID# "+str(senderID)+" to player list. They are playing position "+str(pos)
        player = heekPlayer()
        player.ID = senderID
        player.key = key
        player.pos = pos
        heekPlayerList.append(player)
        reply = ptPythonMsg()
        reply.setContents("Player "+str(len(heekPlayerList)))
        reply.setKey(key)
        reply.send(senderID)
        reply.setContents("GetPoints")
        reply.send(senderID)
        reply.setContents("GetName")
        reply.send(senderID)
    elif msgContents == "Remove": # they want to be removed from our player list
        print "Removing client ID# "+str(senderID)+" from player list."
        for player in heekPlayerList:
            if player.ID == senderID and player.key == key:
                heekPlayerList.remove(player)
                if len(heekPlayerList) == 0: # last player left
                    print "Last player is requesting a leave, telling him to clean up"
                    if countdownStarted:
                        player.SendMessage("StopCountdown")
                        countdownStarted = 0
                    player.SendMessage("ShowIdleAnimation")
                    if player.points != -1:
                        print "Giving last player the remaining points in the pot: "+str(pot)
                        player.SendMessage("SetPoints "+str(player.points+pot))
                        pot = 0
                player.SendMessage("Goodbye")
                #ResetGame()
                break
        for num in range(len(heekPlayerList)): # let everyone know of their new player numbers
            numberMsg = ptPythonMsg()
            numberMsg.setKey(heekPlayerList[num].key)
            numberMsg.setContents("Number "+str(num+1))
            numberMsg.send(heekPlayerList[num].ID)
    elif msgContents == "Rock":
        print "Player #"+str(senderID)+" has chosen rock"
        for player in heekPlayerList:
            if player.ID == senderID and player.key == key:
                if player.points != -1 and not player.isPlaying:
                    ante = CalculateAnte(player.points)
                    player.points -= ante
                    pot += ante
                    player.isPlaying = 1
                    player.SendMessage("SetPoints "+str(player.points))
                player.choice = kRock
                HandlePlayerReady()
                return
    elif msgContents == "Paper":
        print "Player #"+str(senderID)+" has chosen paper"
        for player in heekPlayerList:
            if player.ID == senderID and player.key == key:
                if player.points != -1 and not player.isPlaying:
                    ante = CalculateAnte(player.points)
                    player.points -= ante
                    pot += ante
                    player.isPlaying = 1
                    player.SendMessage("SetPoints "+str(player.points))
                player.choice = kPaper
                HandlePlayerReady()
                return
    elif msgContents == "Scissors":
        print "Player #"+str(senderID)+" has chosen scissors"
        for player in heekPlayerList:
            if player.ID == senderID and player.key == key:
                if player.points != -1 and not player.isPlaying:
                    ante = CalculateAnte(player.points)
                    player.points -= ante
                    pot += ante
                    player.isPlaying = 1
                    player.SendMessage("SetPoints "+str(player.points))
                player.choice = kScissors
                HandlePlayerReady()
                return
    elif msgContents == "CountdownFinished":
        print "Countdown has finished"
        PlayGame()
    elif msgContents == "ChoiceAnimFinished":
        print "Choice animation has finished"
        if not HandleGameWinner():
            ResetRound()
            SendToAll("ShowIdleAnimation")
            SendToAll("Enable")
    elif msgContents == "GameWinAnimFinished":
        SendToAll("ShowIdleAnimation")
        SendToAll("Enable")
    elif msgContents == "LinkIn": # client telling us it's in the age
        agePlayers.append((senderID,key))
        if len(queueCleanup) != 0:
            for item in queueCleanup:
                cleanup = ptPythonMsg()
                cleanup.setContents("Cleanup "+str(item))
                cleanup.setKey(agePlayers[0][1])
                cleanup.send(agePlayers[0][0])
            queueCleanup = []
            idle = ptPythonMsg()
            idle.setContents("ShowIdleAnimation")
            idle.setKey(agePlayers[0][1])
            idle.send(agePlayers[0][0])
        SendTableState(senderID,key)
    elif len(msgContents) > 6 and msgContents[:6] == "Points":
        points = int(msgContents[7:])
        print "Player ID# "+str(senderID)+" has "+str(points)+" points"
        for player in heekPlayerList:
            if player.ID == senderID and player.key == key:
                player.points = points
                if player.name != "":
                    SendWelcomeMsg(player.name,player.points)
                return
    elif len(msgContents) > 4 and msgContents[:4] == "Name":
        name = msgContents[5:]
        for player in heekPlayerList:
            if player.ID == senderID and player.key == key:
                player.name = name
                if player.points != -1:
                    SendWelcomeMsg(player.name,player.points)
                return
    else:
        print "Unknown message, not handling"