package com.jdbernard.teammaker

public class OddsCalculator {

    Map odds = [:]

    public void recalculate(List players, int spotsOpen, PlayerChooser chooser) {

        // reset computed player odds
        odds = [:]

        /* this list will contain each possible selection path with
         * the odds at each node. It is a list of lists of lists::
         *
         *  oddsList: [
         *      path: [
         *          node: [player, odds]
         *          node: [player, odds]
         *      ]
         *      path: [
         *          node: [player, odds]
         *          node: [player, odds]
         *      ]
         *  ]
         */
        
        def oddsList = buildOdds([], players, spotsOpen)

        /* The oddsMap is a condensed version of the oddsList, calculating
         * the overall probability of each path::
         *
         *  oddsMap: [
         *      [player, player]: pathOdds,
         *      [player, player]: pathOdds
         *  ]
         */
        def oddsMap = [:]

        // calculate the overall odds for each path
        oddsList.each { path ->
            def pathPlayers = []
            float pathOdds = 1f

            // the overall odds of the path is the product of the  odds for
            // each node in the path
            path.each { node ->
                pathPlayers << node[0]  // player
                pathOdds *= node[1] // node odds
            }

            oddsMap[(pathPlayers)] = pathOdds
        }

        // now we calculate the overall odds for each player. The odds for a
        // player is the sum of the odds of each path that contains that player
        // (since that means he was picked for one of the nodes, ie., open
        // spots)
        players.each { player ->
            float playerOdds = 0f

            // check each path in the map
            oddsMap.each { pathPlayers, pathOdds ->
                // if we are in this path, add that probability to our own
                if (pathPlayers.contains(player))
                    playerOdds += pathOdds
            }

            odds[(player)] = playerOdds
        }
    }

    protected List buildOdds(List chosenPath, List players, int spotsOpen) {
        def oddsList = []

        if (spotsOpen == 0) return [chosenPath]

        players.each { player ->
            def odds = chooser.getOdds(players, player)
            def newPath = chosenPath.clone()
            newPath << [player, odds]
            oddsList.addAll(buildOdds(newPath, players - [player], spotsOpen - 1))
        }

        return oddsList
    }
}
