class OptimizeRoster(object):

    positions = ['P','C','1B','2B','3B','SS','OF']

    def __init__(self, dataDirectory, eligiblePlayers):
        
        self.dataDirectory = dataDirectory
        self.eligiblePlayers = eligiblePlayers
        self.statsColumn = 'points'
        self.statsRoster = {}
        self.positionPlayers = {}
        self.preCalcPos = {}
        self.rRank = None

    def makePlayerKey(self, name, team):
        return name + '_' + team

    def getPlayerStats(self):
        
        filename = self.dataDirectory + '/fd.players.json'
        f = open(filename)
        data = json.load(f)
        f.close()

        mlb = MLB(self.dataDirectory)
        self.statsRoster = {}

        for key in data:
                    
            #print "key=", key
            fields = data[key]
            #print "item=", fields

            # [u'2B', u'Ed Lucas', u'83325', u'606', u'1000', u'2500', 1.3, 26, False, 0, u'']
            player = {}
            player['key'] = key
            player['position'] = fields[0]
            player['name'] = fields[1]
            player['game_id'] = fields[2]
            player['team_id'] = fields[3]
            player['id3'] = fields[4]
            player['salary'] = float(fields[5])
            player['points'] = fields[6]
            player[self.statsColumn] = fields[6]
            player['num_games'] = fields[7]
            player['some_boolean'] = fields[8]
            player['player_status'] = fields[9]
            player['injury'] = fields[10]

            player['team'] = mlb.getTeamFromFanduelTeamId(player['team_id'])
            print player

            self.statsRoster[self.makePlayerKey(player['name'], player['team'])] = player

    def buildPositionPlayers(self):

        for pos in self.positions:
            self.positionPlayers[pos] = []

        # go through the players that are eligible for this set of games
        # see if we have stats for them, if so, we add them to positionPlayers[]
        for p in self.eligiblePlayers:
            if self.makePlayerKey(p['name'], p['team']) in self.statsRoster:
                player = self.statsRoster[self.makePlayerKey(p['name'], p['team'])]
                self.positionPlayers[p['position']].append(player)
            else:
                # default value
                p[self.statsColumn] = 0.0
                self.positionPlayers[p['position']].append(p)
            

    def optimizePositionPlayers(self):
        # remove duplicate players with same salary and varying points
        # sort descending and then take the first one in the groupby
        # decreases search space by a few orders of magnitude
        for pos in self.positions:
            self.positionPlayers[pos] = sorted(self.positionPlayers[pos], key=itemgetter('salary',self.statsColumn,'secondary_sort'), reverse=True )
            print "pos:", pos, len(self.positionPlayers[pos])
            newList = []
            for k,g in groupby(self.positionPlayers[pos], itemgetter('salary')):
                print "k=",k, "g=",g
                if pos == 'OF':
                    count = 1
                    # Add this salary, we could have 3 OF's with a decent score. Instead of just one 
                    for val in g:
                        #print "adding val=", val
                        newList.append(val)
                        if count > 3:
                            break
                        count += 1
                else:
                    val = g.next()
                    #print "val=", val
                    newList.append(val)
                    #for i in g:
                    #    print "\trest=", i
            self.positionPlayers[pos] = newList


    def preCalcPositions(self):
        tempRoster = {}
        for ss in self.positionPlayers['SS']:
            for players in combinations(self.positionPlayers['OF'], 3):
                # Add to tuple
                players += (ss,)
                #print "players=", players
                #(totalCost, totalPoints) = self.getRosterTotals(players)
                roster = Roster(self.statsColumn, list(players))
                if roster.totalCost in tempRoster and  roster.totalPoints < tempRoster[roster.totalCost].totalPoints:
                        tempRoster[roster.totalCost].numSkipped += 1
                        #print "SKIPPING totalCost ", totalCost, " < ", totalPoints, " ? ",tempRoster[totalCost]
                        continue
                if roster.totalCost not in tempRoster:
                    tempRoster[roster.totalCost] = roster
                    #print "NEW ADDED roster=", roster
                elif roster.totalPoints > tempRoster[roster.totalCost].totalPoints:
                    roster.numSkipped = tempRoster[roster.totalCost].numSkipped + 1
                    tempRoster[roster.totalCost] = roster
                    #print "MORE POINTS ADDED roster=", roster
                else:
                    tempRoster[roster.totalCost].numSkipped += 1
                    #print "SKIPPED NOT ENOUGH POINTS"
        print "len tempRoster=", len(tempRoster)
        #print "tempRoster=", tempRoster
        self.preCalcPos = tempRoster

    def bruteForce(self):
        print "# of players:"
        grandTotalCombinations = 1
        for pos in self.positions:
            self.positionPlayers[pos] = sorted(self.positionPlayers[pos], key=lambda k: k[self.statsColumn], reverse=True)
            print "pos:", pos, len(self.positionPlayers[pos])
            if pos != 'OF':
                grandTotalCombinations *= len(self.positionPlayers[pos])

        print "OF combinations:", len(list(combinations(self.positionPlayers['OF'], 3)))
        grandTotalCombinations *= len(list(combinations(self.positionPlayers['OF'], 3)))
        print "Total Combinations: {:,}".format(grandTotalCombinations)


        self.rRank = RosterRank(self.__class__.__name__, grandTotalCombinations)
        startTime=datetime.now()
        print "start=", startTime
        #preCalcPos = preCalcPositions(positionPlayers)
        numPitcher=0
        numCatcher=0
        numFirstBase=0
        numSecondBase=0
        numThirdBase=0
        numShortstop=0
        totalCombinations=0
        numSkipped=0
        illegalLineup=0
        rosters = []
        zrosters = []
        salaryCap = 35000
        rosterScoreHist = defaultdict(int)
        zrosterScoreHist = defaultdict(int)
        #positions = ['P','C','1B','2B','3B','SS','OF'];
        for pitcher in self.positionPlayers['P']:
            numPitcher += 1
            roster = [ pitcher ]
            for catcher in self.positionPlayers['C']:
                numCatcher += 1
                roster.append(catcher)
                for firstbase in self.positionPlayers['1B']:
                    numFirstBase += 1
                    roster.append(firstbase)
                    for secondbase in self.positionPlayers['2B']:
                        numSecondBase += 1
                        roster.append(secondbase)
                        for thirdbase in self.positionPlayers['3B']:
                            numThirdBase += 1
                            roster.append(thirdbase)
                            #for players in combinations(positionPlayers['OF'], 3):
                            numPreCalc = 0
                            for key, rosterDict in self.preCalcPos.items():
                                rosterObj = rosterDict.copy()
                                rosterObj.extend(roster)
                                self.rRank.addRoster(rosterObj)
                                totalCombinations += 1

                                if (totalCombinations % 2000000) == 0:
                                    #zrosters= sorted(zrosters, key=lambda k: k['zscore'], reverse=True)[:1000]
                                    print "numPitcher=", numPitcher, "numCatcher=", numCatcher
                            roster.pop()
                        roster.pop()
                    roster.pop()
                roster.pop()
            roster.pop()

        self.rRank.printStats()
        self.rRank.saveStats(self.dataDirectory)

    def run(self):
        self.getPlayerStats()
        self.buildPositionPlayers()
        self.optimizePositionPlayers()
        self.preCalcPositions()
        self.bruteForce()
    def bruteForce(self):
        print "# of players:"
        grandTotalCombinations = 1
        for pos in self.positions:
            self.positionPlayers[pos] = sorted(self.positionPlayers[pos], key=lambda k: k[self.statsColumn], reverse=True)
            print "pos:", pos, len(self.positionPlayers[pos])
            if pos != 'OF':
                grandTotalCombinations *= len(self.positionPlayers[pos])

        print "OF combinations:", len(list(combinations(self.positionPlayers['OF'], 3)))
        grandTotalCombinations *= len(list(combinations(self.positionPlayers['OF'], 3)))
        print "Total Combinations: {:,}".format(grandTotalCombinations)


        self.rRank = RosterRank(self.__class__.__name__, grandTotalCombinations)
        startTime=datetime.now()
        print "start=", startTime
        #preCalcPos = preCalcPositions(positionPlayers)
        numPitcher=0
        numCatcher=0
        numFirstBase=0
        numSecondBase=0
        numThirdBase=0
        numShortstop=0
        totalCombinations=0
        numSkipped=0
        illegalLineup=0
        rosters = []
        zrosters = []
        salaryCap = 35000
        rosterScoreHist = defaultdict(int)
        zrosterScoreHist = defaultdict(int)
        #positions = ['P','C','1B','2B','3B','SS','OF'];
        for pitcher in self.positionPlayers['P']:
            numPitcher += 1
            roster = [ pitcher ]
            for catcher in self.positionPlayers['C']:
                numCatcher += 1
                roster.append(catcher)
                for firstbase in self.positionPlayers['1B']:
                    numFirstBase += 1
                    roster.append(firstbase)
                    for secondbase in self.positionPlayers['2B']:
                        numSecondBase += 1
                        roster.append(secondbase)
                        for thirdbase in self.positionPlayers['3B']:
                            numThirdBase += 1
                            roster.append(thirdbase)
                            #for players in combinations(positionPlayers['OF'], 3):
                            numPreCalc = 0
                            for key, rosterDict in self.preCalcPos.items():
                                rosterObj = rosterDict.copy()
                                rosterObj.extend(roster)
                                self.rRank.addRoster(rosterObj)
                                totalCombinations += 1

                                if (totalCombinations % 2000000) == 0:
                                    #zrosters= sorted(zrosters, key=lambda k: k['zscore'], reverse=True)[:1000]
                                    print "numPitcher=", numPitcher, "numCatcher=", numCatcher
                            roster.pop()
                        roster.pop()
                    roster.pop()
                roster.pop()
            roster.pop()

        self.rRank.printStats()
        self.rRank.saveStats(self.dataDirectory)