from direct.directnotify import DirectNotifyGlobal
import DistributedRaceAI
from toontown.toonbase import ToontownGlobals, TTLocalizer
from toontown.coghq import MintLayout
from toontown.ai import HolidayBaseAI
from direct.showbase import DirectObject
import RaceGlobals, random, os, cPickle

class RaceManagerAI(DirectObject.DirectObject):
    notify = DirectNotifyGlobal.directNotify.newCategory('RaceManagerAI')
    serverDataFolder = simbase.config.GetString('server-data-folder', '')

    def __init__(self, air):
        DirectObject.DirectObject.__init__(self)
        self.air = air
        self.races = []
        self.shard = str(air.districtId)
        self.filename = self.getFilename()
        self.trackRecords = self.loadRecords()

    def getDoId(self):
        return 0

    def createRace(self, trackId, raceType, laps, players, circuitLoop, circuitPoints, circuitTimes, qualTimes=[], circuitTimeList={}, circuitTotalBonusTickets={}):
        raceZone = self.air.allocateZone()
        race = DistributedRaceAI.DistributedRaceAI(self.air, trackId, raceZone, players, laps, raceType, self.exitedRace, self.raceOver, circuitLoop, circuitPoints, circuitTimes, qualTimes, circuitTimeList, circuitTotalBonusTickets)
        race.generateWithRequired(raceZone)
        race.playersFinished = []
        race.lastTotalTime = 0
        self.races.append(race)
        return raceZone

    def exitedRace(self, race, playerInfo):
        self.notify.debug('exited race: %s' % playerInfo.avId)
        totalTime = playerInfo.totalTime
        entryFee = 0
        bonus = 0
        placeMultiplier = 0
        qualify = 0
        winnings = 0
        trophies = []
        points = []
        newHistory = None
        race.playersFinished.append(playerInfo.avId)
        place = len(race.playersFinished)
        self.notify.debug('place: %s of %s' % (place, race.toonCount))
        self.notify.debug('pre-tie totalTime: %s' % totalTime)
        if totalTime <= race.lastTotalTime:
            totalTime = race.lastTotalTime + 0.01
        race.lastTotalTime = totalTime
        self.notify.debug('totalTime: %s, qualify: %s' % (totalTime, RaceGlobals.getQualifyingTime(race.trackId)))
        circuitTime = totalTime + race.circuitTimes.get(playerInfo.avId, 0)
        race.circuitTimes[playerInfo.avId] = circuitTime
        if not race.circuitTimeList.get(playerInfo.avId):
            race.circuitTimeList[playerInfo.avId] = []
        race.circuitTimeList[playerInfo.avId].append([totalTime, 0])
        self.notify.debug('CircuitTimeList %s' % race.circuitTimeList)
        if race.raceType == RaceGlobals.Circuit:
            points = race.circuitPoints.get(playerInfo.avId, [])
            points.append(RaceGlobals.CircuitPoints[place - 1])
            race.circuitPoints[playerInfo.avId] = points
        currentTimeIndex = len(race.circuitTimeList[playerInfo.avId]) - 1
        if totalTime <= RaceGlobals.getQualifyingTime(race.trackId):
            race.circuitTimeList[playerInfo.avId][currentTimeIndex][1] = 1
            self.notify.debug('Racer Qualified time: %s required: %s' % (totalTime, RaceGlobals.getQualifyingTime(race.trackId)))
            qualify = 1
            self.checkPersonalBest(race.trackId, totalTime, race.raceType, race.toonCount, playerInfo.avId)
            if race.raceType == RaceGlobals.Practice:
                winnings = RaceGlobals.PracticeWinnings
                self.notify.debug('GrandTouring: Checking from branch: practice %s' % playerInfo.avId)
                trophies = self.checkForNonRaceTrophies(playerInfo.avId)
                if trophies:
                    self.updateTrophiesFromList(playerInfo.avId, trophies)
            else:
                self.air.writeServerEvent('kartingPlaced', playerInfo.avId, '%s|%s' % (place, race.toonCount))
                if race.raceType != RaceGlobals.Circuit:
                    entryFee = RaceGlobals.getEntryFee(race.trackId, race.raceType)
                    placeMultiplier = RaceGlobals.Winnings[place - 1 + (RaceGlobals.MaxRacers - race.toonCount)]
                    winnings = int(entryFee * placeMultiplier)
                    newHistory = self.getNewSingleRaceHistory(race, playerInfo.avId, place)
                    av = self.air.doId2do.get(playerInfo.avId)
                    if newHistory:
                        self.notify.debug('history %s' % newHistory)
                        av.b_setKartingHistory(newHistory)
                        trophies = self.checkForRaceTrophies(race, playerInfo.avId)
                    else:
                        trophies = self.checkForNonRaceTrophies(playerInfo.avId)
                    if trophies:
                        self.updateTrophiesFromList(playerInfo.avId, trophies)
                bonus = self.checkTimeRecord(race.trackId, totalTime, race.raceType, race.toonCount, playerInfo.avId)
                if race.circuitTotalBonusTickets.has_key(playerInfo.avId):
                    race.circuitTotalBonusTickets[playerInfo.avId] += bonus
                else:
                    race.circuitTotalBonusTickets[playerInfo.avId] = bonus
            av = self.air.doId2do.get(playerInfo.avId)
            if av:
                oldTickets = av.getTickets()
                self.notify.debug('old tickets: %s' % oldTickets)
                newTickets = oldTickets + winnings + entryFee + bonus
                self.air.writeServerEvent('kartingTicketsWon', playerInfo.avId, '%s' % (newTickets - oldTickets))
                self.notify.debug('entry fee: %s' % entryFee)
                self.notify.debug('place mult: %s' % placeMultiplier)
                self.notify.debug('winnings: %s' % winnings)
                self.notify.debug('bonus: %s' % bonus)
                self.notify.debug('new tickets: %s' % newTickets)
                self.notify.debug('circuit points: %s' % points)
                self.notify.debug('circuit time: %s' % circuitTime)
                self.notify.debug('circuitTotalBonusTickets: %s' % race.circuitTotalBonusTickets)
                av.b_setTickets(newTickets)
        else:
            race.circuitTimeList[playerInfo.avId][currentTimeIndex][1] = -1
            self.notify.debug('GrandTouring: Checking from branch: Not Qualified %s' % playerInfo.avId)
            trophies = self.checkForNonRaceTrophies(playerInfo.avId)
            if trophies:
                self.updateTrophiesFromList(playerInfo.avId, trophies)
        if race in self.races:
            race.d_setPlace(playerInfo.avId, totalTime, place, entryFee, qualify, winnings, bonus, trophies, points, circuitTime)
            if race.isCircuit():
                self.notify.debug('isCircuit')
                if race.everyoneDone():
                    self.notify.debug('everyoneDone')
                    if race.isLastRace():
                        taskMgr.doMethodLater(10, self.endCircuitRace, 'DelayEndCircuitRace=%d' % race.doId, (race, bonus))
                    else:
                        self.endCircuitRace(race, bonus)
            else:
                self.notify.debug('not isCircuit')
        return

    def endCircuitRace(self, race, bonus=0):
        self.notify.debug('endCircuitRace')
        pointTotals = []
        for avId in race.circuitPoints:
            pointTotals.append([avId, sum(race.circuitPoints[avId])])

        numVals = len(pointTotals)
        finalStandings = []

        def swap(x, y):
            t = pointTotals[x]
            pointTotals[x] = pointTotals[y]
            pointTotals[y] = t

        for i in range(numVals - 1, 0, -1):
            for j in range(i):
                if pointTotals[j][1] < pointTotals[j + 1][1]:
                    swap(j, j + 1)
                elif pointTotals[j][1] == pointTotals[j + 1][1]:
                    avId1 = pointTotals[j][0]
                    avId2 = pointTotals[j + 1][0]
                    if race.circuitTimes[avId1] > race.circuitTimes[avId2]:
                        swap(j, j + 1)

        for i in range(numVals):
            finalStandings.append(pointTotals[i][0])

        self.notify.debug('Final standings %s' % finalStandings)
        for avId in finalStandings:
            self.notify.debug('avId %s' % avId)
            place = finalStandings.index(avId) + 1
            places = len(finalStandings)
            winnings = 0
            trophies = []
            if race.isLastRace():
                self.notify.debug('isLastRace')
                av = self.air.doId2do.get(avId)
                if av and avId in race.playersFinished:
                    self.air.writeServerEvent('kartingCircuitFinished', avId, '%s|%s' % (place, places))
                    print 'kartingCircuitFinished', avId, '%s|%s' % (place, places)
                    entryFee = RaceGlobals.getEntryFee(race.trackId, race.raceType)
                    placeMultiplier = RaceGlobals.Winnings[place - 1 + (RaceGlobals.MaxRacers - places)]
                    winnings = int(entryFee * placeMultiplier)
                    newHistory = self.getNewCircuitHistory(race, avId, place)
                    if newHistory:
                        self.notify.debug('history %s' % newHistory)
                        trophies = self.checkForCircuitTrophies(race, avId, newHistory)
                        av.b_setKartingHistory(newHistory)
                        if trophies:
                            self.updateTrophiesFromList(avId, trophies)
                    else:
                        self.notify.debug('no new history')
                        trophies = self.checkForNonRaceTrophies(avId)
                    oldTickets = av.getTickets()
                    self.notify.debug('endCircuitRace: old tickets: %s' % oldTickets)
                    newTickets = oldTickets + winnings + entryFee
                    self.air.writeServerEvent('kartingTicketsWonCircuit', avId, '%s' % (newTickets - oldTickets))
                    self.notify.debug('entry fee: %s' % entryFee)
                    self.notify.debug('place mult: %s' % placeMultiplier)
                    self.notify.debug('winnings: %s' % winnings)
                    self.notify.debug('new tickets: %s' % newTickets)
                    self.notify.debug('trophies: %s' % trophies)
                    self.notify.debug('bonus: %s' % bonus)
                    av.b_setTickets(newTickets)
                    finalBonus = 0
                    if race.circuitTotalBonusTickets.has_key(avId):
                        finalBonus = race.circuitTotalBonusTickets[avId]
                    race.d_setCircuitPlace(avId, place, entryFee, winnings, finalBonus, trophies)

        race.playersFinished = finalStandings
        race.d_endCircuitRace()

    def updateTrophiesFromList(self, avId, trophies):
        self.air.writeServerEvent('Writing Trophies: Updating trophies from list', avId, '%s' % trophies)
        av = self.air.doId2do.get(avId)
        if not av:
            return
        if not trophies:
            return
        trophyField = av.getKartingTrophies()
        for trophy in trophies:
            trophyField[trophy] = 1

        av.b_setKartingTrophies(trophyField)

    def checkForCircuitTrophies(self, race, avId, inHistory=None):
        av = self.air.doId2do.get(avId)
        if not av:
            return []
        trophies = av.getKartingTrophies()
        if inHistory:
            history = inHistory
        else:
            history = av.getKartingHistory()
        winIndex = RaceGlobals.CircuitWins
        winReqList = RaceGlobals.WonCircuitRaces
        winIndices = RaceGlobals.CircuitWinsList
        sweepIndex = RaceGlobals.CircuitSweeps
        sweepReqList = RaceGlobals.SweptCircuitRaces
        sweepIndices = RaceGlobals.CircuitSweepsList
        qualIndex = RaceGlobals.CircuitQuals
        qualReqList = RaceGlobals.QualifiedCircuitRaces
        qualIndices = RaceGlobals.CircuitQualList
        trophies = av.getKartingTrophies()
        newTrophies = []
        newTrophies.extend(self.checkHistoryForTrophy(trophies, history, winIndex, winReqList, winIndices))
        newTrophies.extend(self.checkHistoryForTrophy(trophies, history, sweepIndex, sweepReqList, sweepIndices))
        newTrophies.extend(self.checkHistoryForTrophy(trophies, history, qualIndex, qualReqList, qualIndices))
        self.notify.debug('GrandTouring: Checking from branch: Circuit %s' % avId)
        newTrophies.extend(self.checkForNonRaceTrophies(avId, history))
        newTrophies.sort()
        return newTrophies

    def checkForRaceTrophies(self, race, avId, inHistory=None):
        av = self.air.doId2do.get(avId)
        if not av:
            return []
        trophies = av.getKartingTrophies()
        if inHistory:
            history = inHistory
        else:
            history = av.getKartingHistory()
        newTrophies = []
        numTrackGenres = len(RaceGlobals.WinsList)
        for genre in range(numTrackGenres):
            singleGenreNewTrophies = self.checkHistoryForTrophy(trophies, history, RaceGlobals.WinsList[genre], RaceGlobals.WonRaces, RaceGlobals.AllWinsList[genre])
            newTrophies.extend(singleGenreNewTrophies)

        numTrackGenres = len(RaceGlobals.QualsList)
        for genre in range(numTrackGenres):
            singleGenreNewTrophies = self.checkHistoryForTrophy(trophies, history, RaceGlobals.QualsList[genre], RaceGlobals.QualifiedRaces, RaceGlobals.AllQualsList[genre])
            newTrophies.extend(singleGenreNewTrophies)

        totalWins = 0
        for genre in range(numTrackGenres):
            totalWins += history[RaceGlobals.WinsList[genre]]

        singleGenreNewTrophies = self.checkHistoryForTrophyByValue(trophies, history, totalWins, [
         RaceGlobals.TotalWonRaces], [
         RaceGlobals.TotalWins])
        newTrophies.extend(singleGenreNewTrophies)
        totalQuals = 0
        for genre in range(numTrackGenres):
            totalQuals += history[RaceGlobals.QualsList[genre]]

        singleGenreNewTrophies = self.checkHistoryForTrophyByValue(trophies, history, totalQuals, [
         RaceGlobals.TotalQualifiedRaces], [
         RaceGlobals.TotalQuals])
        newTrophies.extend(singleGenreNewTrophies)
        self.notify.debug('GrandTouring: Checking from branch: Race %s ' % avId)
        newTrophies.extend(self.checkForNonRaceTrophies(avId, history))
        newTrophies.sort()
        return newTrophies

    def checkForNonRaceTrophies(self, avId, inHistory=None):
        self.notify.debug('CHECKING FOR NONRACE TROPHIES')
        self.notify.debug('GrandTouring: Checking for non-race trophies %s' % avId)
        av = self.air.doId2do.get(avId)
        if not av:
            self.notify.debug('NO AV %s' % avId)
            self.notify.debug("GrandTouring: can't convert avId to Av %s" % avId)
            return []
        trophies = av.getKartingTrophies()
        if inHistory:
            history = inHistory
        else:
            history = av.getKartingHistory()
        newTrophies = []
        self.notify.debug('GrandTouring: history-- %s' % history)
        self.notify.debug('GrandTouring: trophies- %s' % trophies)
        addTrophyCount = 0
        if not trophies[RaceGlobals.GrandTouring]:
            self.notify.debug('checking for grand touring')
            self.notify.debug('GrandTouring: checking for grand touring %s' % trophies[RaceGlobals.GrandTouring])
            best = av.getKartingPersonalBestAll()
            self.notify.debug('personal best %s' % best)
            self.notify.debug('GrandTouring: checking personal best %s' % best)
            counter = 0
            for time in best:
                if not time == 0:
                    counter += 1

            self.notify.debug('counter %s tracks %s' % (counter, len(RaceGlobals.TrackDict)))
            self.notify.debug('GrandTouring: bests comparison counter: %s tracks: %s' % (counter, len(RaceGlobals.TrackDict)))
            if counter >= len(RaceGlobals.TrackDict):
                newTrophies.append(RaceGlobals.GrandTouring)
                addTrophyCount += 1
                self.air.writeServerEvent('kartingTrophy', avId, '%s' % RaceGlobals.GrandTouring)
                self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[RaceGlobals.GrandTouring])
                self.notify.debug('GrandTouring: awarding grand touring new trophies %s' % newTrophies)
        else:
            self.notify.debug('already has grandtouring')
            self.notify.debug('trophies %s' % trophies)
            self.notify.debug('GrandTouring: already has grand touring %s' % trophies[RaceGlobals.GrandTouring])
        for i in range(1, RaceGlobals.NumTrophies / RaceGlobals.TrophiesPerCup + 1):
            cupNum = (trophies[:RaceGlobals.NumTrophies].count(1) + addTrophyCount) / (i * RaceGlobals.TrophiesPerCup)
            self.notify.debug('cupNum: %s' % cupNum)
            trophyIndex = RaceGlobals.TrophyCups[i - 1]
            if cupNum and not trophies[trophyIndex]:
                newTrophies.append(trophyIndex)
                oldMaxHp = av.getMaxHp()
                newMaxHp = min(ToontownGlobals.MaxHpLimit, oldMaxHp + 1)
                self.notify.debug('cup awarded! new max laff : %s' % newMaxHp)
                av.b_setMaxHp(newMaxHp)
                av.toonUp(newMaxHp)
                self.air.writeServerEvent('kartingTrophy', avId, '%s' % trophyIndex)
                self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[trophyIndex])

        self.notify.debug('NONRACE TROPHIES %s' % newTrophies)
        return newTrophies

    def checkHistoryForTrophyByValue(self, trophies, history, historyIndexValue, trophyReqList, trophyIndices):
        newTrophies = []
        self.notify.debug('Checking History for Trophy')
        self.notify.debug('Index %s Num %s ReqList %s Indices %s' % (0, historyIndexValue, trophyReqList, trophyIndices))
        for index in range(len(trophyIndices)):
            if not trophies[trophyIndices[index]]:
                if historyIndexValue >= trophyReqList[index]:
                    trophies[trophyIndices[index]] = 1
                    newTrophies.append(trophyIndices[index])

        return newTrophies

    def checkHistoryForTrophy(self, trophies, history, historyIndex, trophyReqList, trophyIndices):
        newTrophies = []
        self.notify.debug('Checking History for Trophy')
        self.notify.debug('Index %s Num %s ReqList %s Indices %s' % (historyIndex, history[historyIndex], trophyReqList, trophyIndices))
        for index in range(len(trophyIndices)):
            if not trophies[trophyIndices[index]]:
                if history[historyIndex] >= trophyReqList[index]:
                    trophies[trophyIndices[index]] = 1
                    newTrophies.append(trophyIndices[index])

        return newTrophies

    def mergeHistories(self, historyA, historyB):
        newHistorySize = len(historyA)
        if len(historyB) > len(historyA):
            newHistorySize = historyB
        mergedHistory = []
        for index in range(newHistorySize):
            mergedHistory[index] = 0
            if len(historyA) > index:
                if historyA[index] > mergedHistory[index]:
                    historyA[index] = mergedHistory[index]
            if len(historyB) > index:
                if historyB[index] > mergedHistory[index]:
                    historyB[index] = mergedHistory[index]

        return mergedHistory

    def getNewSingleRaceHistory(self, race, avId, positionFinished):
        newHistory = 0
        av = self.air.doId2do.get(avId)
        if not av:
            return []
        history = av.getKartingHistory()
        trackGenre = RaceGlobals.getTrackGenre(race.trackId)
        winIndex = RaceGlobals.WinsList[trackGenre]
        winReqList = RaceGlobals.WonRaces
        qualIndex = RaceGlobals.QualsList[trackGenre]
        qualReqList = RaceGlobals.QualifiedRaces
        if history[winIndex] < winReqList[-1] and positionFinished == 1:
            history[winIndex] += 1
            self.notify.debug('New History Won!')
            newHistory = 1
        if history[qualIndex] < qualReqList[-1]:
            history[qualIndex] += 1
            self.notify.debug('New History Qualified!')
            newHistory = 1
        if newHistory:
            return history

    def getNewCircuitHistory(self, race, avId, positionFinished):
        newHistory = 0
        av = self.air.doId2do.get(avId)
        if not av:
            return []
        history = av.getKartingHistory()
        trackGenre = RaceGlobals.getTrackGenre(race.trackId)
        historyIndex = RaceGlobals.CircuitWins
        trophyReqList = RaceGlobals.WonCircuitRaces
        sweepIndices = RaceGlobals.CircuitSweepsList
        sweepReqList = RaceGlobals.SweptCircuitRaces
        self.notify.debug('getNewCircuitHistory: avId=%d positionFinished=%d history =%s' % (avId, positionFinished, history))
        if history[historyIndex] < trophyReqList[-1] and positionFinished == 1:
            history[historyIndex] += 1
            self.notify.debug('New History Won!')
            newHistory = 1
        swept = 0
        totalPoints = sum(race.circuitPoints[avId])
        if totalPoints == len(race.circuitPoints[avId]) * RaceGlobals.CircuitPoints[0]:
            swept = 1
        if swept:
            if history[RaceGlobals.CircuitSweeps] < sweepReqList[-1]:
                if not history[RaceGlobals.CircuitSweeps]:
                    history[RaceGlobals.CircuitSweeps] = 0
                history[RaceGlobals.CircuitSweeps] += 1
                self.notify.debug('New History Swept!')
                newHistory = 1
        qualified = 0
        self.notify.debug('qual times %s' % race.qualTimes)
        self.notify.debug('avatar times %s' % race.circuitTimeList[avId])
        qualified = 1
        self.notify.debug('End Race Circuit Time List %s' % race.circuitTimeList)
        self.notify.debug('check for qualify')
        for qual in race.circuitTimeList[avId]:
            self.notify.debug('qual %s' % qual)
            if qual[1] == -1:
                qualified = 0
                self.notify.debug('not qualified')

        if qualified:
            self.notify.debug('qualified has %s needs %s' % (history[RaceGlobals.CircuitQuals], RaceGlobals.QualifiedCircuitRaces[-1]))
            if history[RaceGlobals.CircuitQuals] < RaceGlobals.QualifiedCircuitRaces[-1]:
                history[RaceGlobals.CircuitQuals] += 1
                self.notify.debug('New History qualified!')
                newHistory = 1
        if newHistory:
            return history

    def raceOver(self, race, normalExit=True):
        if race in self.races:
            if normalExit and race.isCircuit() and not race.isLastRace():
                nextTrackId = race.circuitLoop[0]
                continuingAvs = []
                for avId in race.avIds:
                    if avId not in race.kickedAvIds:
                        continuingAvs.append(avId)

                lastRace = False
                if len(continuingAvs) > 0:
                    raceZone = self.createRace(nextTrackId, race.raceType, race.lapCount, continuingAvs, race.circuitLoop[1:], race.circuitPoints, race.circuitTimes, race.qualTimes, race.circuitTimeList, race.circuitTotalBonusTickets)
                    race.sendToonsToNextCircuitRace(raceZone, nextTrackId)
                else:
                    lastRace = True
                self.races.remove(race)
                race.requestDelete(lastRace)
            else:
                self.races.remove(race)
                race.requestDelete()

    def checkForTrophies(self, place, trackId, raceType, numRacers, avId):
        av = self.air.doId2do.get(avId)
        outHistory = av.getKartingHistory()
        trophies = av.getKartingTrophies()
        trophiesWon = []
        trackGenre = RaceGlobals.getTrackGenre(trackId)
        if place == 1:
            historyIndex = RaceGlobals.WinsList[trackGenre]
            trophyIndices = RaceGlobals.AllWinsList[trackGenre]
            trophyReqList = RaceGlobals.WonRaces
            historyTotalList = RaceGlobals.WinsList
            totalTrophyIndex = RaceGlobals.TotalWins
            totalReq = RaceGlobals.TotalWonRaces
            trophiesWon += self.checkForTrophy(place, trackId, raceType, numRacers, avId, historyIndex, trophyIndices, trophyReqList, historyTotalList, totalTrophyIndex, totalReq)
        historyIndex = RaceGlobals.QualsList[trackGenre]
        trophyIndices = RaceGlobals.AllQualsList[trackGenre]
        trophyReqList = RaceGlobals.QualifiedRaces
        historyTotalList = RaceGlobals.QualsList
        totalTrophyIndex = RaceGlobals.TotalQuals
        totalReq = RaceGlobals.TotalQualifiedRaces
        trophiesWon += self.checkForTrophy(place, trackId, raceType, numRacers, avId, historyIndex, trophyIndices, trophyReqList, historyTotalList, totalTrophyIndex, totalReq)
        if not trophies[RaceGlobals.GrandTouring]:
            self.notify.debug('checking for grand touring')
            best = av.getKartingPersonalBestAll()
            self.notify.debug('personal best %s' % best)
            counter = 0
            for time in best:
                if not time == 0:
                    counter += 1

            self.notify.debug('counter %s tracks %s' % (counter, len(RaceGlobals.TrackDict)))
            if counter >= len(RaceGlobals.TrackDict):
                trophiesWon.append(RaceGlobals.GrandTouring)
        if outHistory:
            av.b_setKartingHistory(outHistory)
        if len(trophiesWon):
            for trophy in trophiesWon:
                trophies[trophy] = 1

            av.b_setKartingTrophies(trophies)
        trophiesWon.sort()
        return trophiesWon

    def checkForTrophy(self, place, trackId, raceType, numRacers, avId, historyIndex, trophyIndices, trophyReqList, historyTotalList, totalTrophyIndex, totalReq):
        av = self.air.doId2do.get(avId)
        if not av:
            return []
        history = av.getKartingHistory()
        newHistory = 0
        trophies = av.getKartingTrophies()
        newTrophies = []
        if history[historyIndex] < trophyReqList[-1]:
            history[historyIndex] += 1
            newHistory = 1
        for i in range(0, len(trophyReqList)):
            if not trophies[trophyIndices[i]]:
                if history[historyIndex] == trophyReqList[i]:
                    trophies[trophyIndices[i]] = 1
                    newTrophies.append(trophyIndices[i])
                    self.air.writeServerEvent('kartingTrophy', avId, '%s' % trophyIndices[i])
                    self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[trophyIndices[i]])
                    break

        if not raceType == RaceGlobals.Circuit:
            if not trophies[totalTrophyIndex]:
                total = 0
                for i in historyTotalList:
                    total += history[i]

                self.notify.debug('checking for total trophy: %s >= %s' % (total, totalReq))
                if total >= totalReq:
                    trophies[totalTrophyIndex] = 1
                    newTrophies.append(totalTrophyIndex)
                    self.air.writeServerEvent('kartingTrophy', avId, '%s' % totalTrophyIndex)
                    self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[totalTrophyIndex])
        for i in range(1, RaceGlobals.NumTrophies / RaceGlobals.TrophiesPerCup + 1):
            cupNum = trophies[:RaceGlobals.NumTrophies].count(1) / (i * RaceGlobals.TrophiesPerCup)
            self.notify.debug('cupNum: %s' % cupNum)
            trophyIndex = RaceGlobals.TrophyCups[i - 1]
            if cupNum and not trophies[trophyIndex]:
                trophies[trophyIndex] = 1
                newTrophies.append(trophyIndex)
                oldMaxHp = av.getMaxHp()
                newMaxHp = min(ToontownGlobals.MaxHpLimit, oldMaxHp + 1)
                self.notify.debug('cup awarded! new max laff : %s' % newMaxHp)
                av.b_setMaxHp(newMaxHp)
                av.toonUp(newMaxHp)
                self.air.writeServerEvent('kartingTrophy', avId, '%s' % trophyIndex)
                self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[trophyIndex])

        self.notify.debug('newTrophies: %s' % newTrophies)
        self.notify.debug('trophies: %s' % trophies)
        self.notify.debug('kartingHistory: %s' % history)
        if newHistory:
            av.b_setKartingHistory(history)
        return newTrophies

    def checkPersonalBest(self, trackId, time, raceType, numRacers, avId):
        av = simbase.air.doId2do.get(avId)
        if av:
            bestTimes = av.getKartingPersonalBestAll()
            trackIndex = RaceGlobals.TrackIds.index(trackId)
            bestTime = bestTimes[trackIndex]
            self.notify.debug('thisTime: %s, bestTime: %s' % (time, bestTime))
            if bestTime == 0.0 or time < bestTime:
                bestTimes[trackIndex] = time
                self.notify.debug('new personal best!')
                av.b_setKartingPersonalBest(bestTimes)
                self.notify.debug('personal best: %s' % bestTimes)

    def checkTimeRecord(self, trackId, time, raceType, numRacers, avId):
        bonus = 0
        newRecord = 0
        for period in RaceGlobals.PeriodIds:
            for record in range(0, RaceGlobals.NumRecordsPerPeriod):
                recordTime = self.trackRecords[trackId][period][record][0]
                if time < recordTime:
                    newRecord = 1
                    self.notify.debug('new %s record!' % TTLocalizer.RecordPeriodStrings[period])
                    av = simbase.air.doId2do.get(avId)
                    if av:
                        name = av.name
                        self.trackRecords[trackId][period].insert(record, (time, raceType, numRacers, name))
                        self.trackRecords[trackId][period] = self.trackRecords[trackId][period][:RaceGlobals.NumRecordsPerPeriod]
                        self.updateLeaderboards(trackId, period)
                        bonus = RaceGlobals.PeriodDict[period]
                        self.air.writeServerEvent('kartingRecord', avId, '%s|%s|%s' % (period, trackId, time))
                    else:
                        self.notify.warning('warning: av not logged in!')
                    break

        if newRecord:
            self.updateRecordFile()
        return bonus

    def updateRecordFile(self):
        try:
            backup = self.filename + '.bu'
            if os.path.exists(self.filename):
                os.rename(self.filename, backup)
            file = open(self.filename, 'w')
            file.seek(0)
            cPickle.dump(self.trackRecords, file)
            file.close()
            if os.path.exists(backup):
                os.remove(backup)
        except EnvironmentError:
            self.notify.warning(str(sys.exc_info()[1]))

    def getFilename(self):
        return '%s%s.trackRecords' % (self.serverDataFolder, self.shard)

    def loadRecords(self):
        try:
            file = open(self.filename + '.bu', 'r')
            if os.path.exists(self.filename):
                os.remove(self.filename)
        except IOError:
            try:
                file = open(self.filename, 'r')
            except IOError:
                return self.getRecordTimes()

        file.seek(0)
        records = self.loadFrom(file)
        file.close()
        for trackId in RaceGlobals.TrackIds:
            if not records.has_key(trackId):
                records[trackId] = {}
                for i in RaceGlobals.PeriodIds:
                    records[trackId][i] = []
                    for j in range(0, RaceGlobals.NumRecordsPerPeriod):
                        records[trackId][i].append(RaceGlobals.getDefaultRecord(trackId))

        self.resetLeaderboards()
        return records

    def loadFrom(self, file):
        records = {}
        try:
            while 1:
                records = cPickle.load(file)

        except EOFError:
            pass

        return records

    def getRecordTimes(self):
        records = {}
        for trackId in RaceGlobals.TrackIds:
            records[trackId] = {}
            for i in RaceGlobals.PeriodIds:
                records[trackId][i] = []
                for j in range(0, RaceGlobals.NumRecordsPerPeriod):
                    records[trackId][i].append(RaceGlobals.getDefaultRecord(trackId))

        return records

    def resetRecordPeriod(self, period):
        for trackId in RaceGlobals.TrackIds:
            for i in range(0, RaceGlobals.NumRecordsPerPeriod):
                self.trackRecords[trackId][period][i] = RaceGlobals.getDefaultRecord(trackId)

            self.updateLeaderboards(trackId, period)

        self.updateRecordFile()

    def getRecords(self, trackId, period):
        return self.trackRecords[trackId][period]

    def updateLeaderboards(self, trackId, period):
        messenger.send('UpdateRaceRecord', [(trackId, period)])

    def resetLeaderboards(self):
        for track in RaceGlobals.TrackIds:
            for period in RaceGlobals.PeriodIds:
                self.updateLeaderboards(track, period)


class KartRecordDailyResetter(HolidayBaseAI.HolidayBaseAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('ResistanceEventMgrAI')
    PostName = 'kertRecordDailyReset'

    def __init__(self, air, holidayId):
        HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)

    def start(self):
        bboard.post(KartRecordDailyResetter.PostName)
        simbase.air.raceMgr.resetRecordPeriod(RaceGlobals.Daily)

    def stop(self):
        bboard.remove(KartRecordDailyResetter.PostName)


class KartRecordWeeklyResetter(HolidayBaseAI.HolidayBaseAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('ResistanceEventMgrAI')
    PostName = 'kartRecordWeeklyReset'

    def __init__(self, air, holidayId):
        HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)

    def start(self):
        bboard.post(KartRecordWeeklyResetter.PostName)
        simbase.air.raceMgr.resetRecordPeriod(RaceGlobals.Weekly)

    def stop(self):
        bboard.remove(KartRecordWeeklyResetter.PostName)


class CircuitRaceHolidayMgr(HolidayBaseAI.HolidayBaseAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('CircuitRaceHolidayMgr')
    PostName = 'CircuitRaceHoliday'
    StartStopMsg = 'CircuitRaceHolidayStartStop'

    def __init__(self, air, holidayId):
        HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)

    def start(self):
        bboard.post(CircuitRaceHolidayMgr.PostName, True)
        simbase.air.newsManager.circuitRaceStart()
        messenger.send(CircuitRaceHolidayMgr.StartStopMsg)

    def stop(self):
        bboard.remove(CircuitRaceHolidayMgr.PostName)
        simbase.air.newsManager.circuitRaceEnd()
        messenger.send(CircuitRaceHolidayMgr.StartStopMsg)
