class SelectionsTest(unittest.TestCase):

    def setUp(self):
        self.__selections = Selections()
        self.__selections.addSelections("default", [1, 2, 3])

    def testAddAndGetSelections_byPosition(self):
        '''Tests adding and retrieval of selection. Note that the returned order must be the
        same as the order as in which they were added!'''
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3))

    def testAddAndGetSelections_all(self):
        assert_that(self.__selections.getSelections(), is_(equal_to({
            "default": [1, 2, 3]
        })))

    def testAddSelections_alreadyAtPosition(self):
        self.__selections.addSelections("default", 1)
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3))


    def testAddSelections_positionAlreadyExists(self):
        self.__selections.addSelections("default", 4)
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3, 4))
    
    def testAddSelections_useList(self):
        self.__selections.addSelections("default", [4, 5])
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3, 4, 5))
    
    def testAddSelections_useListWithOverlap(self):
        self.__selections.addSelections("default", [3, 4, 5])
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3, 4, 5))

    def testAddSelections_otherPositions(self):
        self.__selections.addSelections("with list", [4, 5, 6])
        self.__selections.addSelections("use single", 7)

        assert_that(self.__selections.getSelections(), has_entries({
            "default": [1, 2, 3],
            "with list": [4, 5, 6],
            "use single": [7]
        }))

    def testGetSelections_byPosition_noEntriesAddedForPosition(self):
        assert_that(self.__selections.getSelections("not added"), is_(equal_to([])))

    def testGetSelections_byPosition_afterAllRemoved(self):
        self.__selections.removeSelection("default", 1)
        self.__selections.removeSelection("default", 2)
        self.__selections.removeSelection("default", 3)
        assert_that(self.__selections.getSelections("default"), is_(equal_to([])))

    def testGetSelections_all_beforeAnyAdded(self):
        assert_that(Selections().getSelections(), is_(equal_to({})))

    def testGetSelectedPositions(self):
        assert_that(self.__selections.getSelectedPositions(1), contains_inanyorder("default"))

    def testGetSelectedPositions_all(self):
        assert_that(self.__selections.getSelectedPositions(), is_(equal_to({
            1: set(["default"]),
            2: set(["default"]),
            3: set(["default"])
        })))

    def testGetSelectedPositions_multiplePositions(self):
        self.__selections.addSelections("other", [1])
        assert_that(self.__selections.getSelectedPositions(1), 
            contains_inanyorder("default", "other"))

    def testGetSelectionPositions_all_multiplePositions(self):
        self.__selections.addSelections("other", [1])
        assert_that(self.__selections.getSelectedPositions(), is_(equal_to({
            1: set(["default", "other"]),
            2: set(["default"]),
            3: set(["default"])
        })))

    def testGetSelectedPositions_afterRemove(self):
        self.__selections.removeSelection("default", 1)
        assert_that(len(self.__selections.getSelectedPositions(1)), is_(equal_to(0)))

    def testGetSelectedPositions_all_afterRemove(self):
        self.__selections.removeSelection("default", 1)
        assert_that(self.__selections.getSelectedPositions(), is_(equal_to({
            2: set(["default"]),
            3: set(["default"])
        })))

    def testGetSelectedPositions_all_afterAllRemoved(self):
        self.__selections.removeSelection("default", 1)
        self.__selections.removeSelection("default", 2)
        self.__selections.removeSelection("default", 3)
        assert_that(self.__selections.getSelectedPositions(), is_(equal_to({}))) 

    def testRemoveSelection_removeExisting(self):
        self.__selections.removeSelection("default", 1)
        assert_that(self.__selections.getSelections("default"), contains(2, 3))

    def testRemoveSelection_nonExistingPlayerId(self):
        self.__selections.removeSelection("default", 5)
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3))

    def testRemoveSelection_nonExistingPosition(self):
        self.__selections.removeSelection("other", 1)
        assert_that(self.__selections.getSelections("default"), contains(1, 2, 3))

    def testRemoveSelection_playerHasMultiplePositions(self):
        self.__selections.addSelections("other", 1)
        self.__selections.removeSelection("default", 1)
        assert_that(self.__selections.getSelections(), has_entries({
            "default": [2, 3],
            "other": [1]
        }))

    def testRemoveSelection_allRemoved(self):
        self.__selections.removeSelection("default", 1)
        self.__selections.removeSelection("default", 2)
        self.__selections.removeSelection("default", 3)
        assert_that(self.__selections.getSelections(), is_(equal_to({})))
    for player in selected:
        selections.addSelections(p, player["id"])
        byIds[player["id"]] = player

# Next, try to fix the duplicates. Since duplicates would normally have at
# least two positions. The one that the player stays in depends on distance
# from the price mean of the positions.            
print ("Selection duplicates:")
leftOver = 0
for (playerId, positions) in selections.getSelectedPositions().iteritems():
    if len(positions) > 1:
        player = byIds[playerId]
        nominated = __nominatePosition__(player["price"], positions, priceAvg)
        for p in set(positions):
            if p != nominated:
                selections.removeSelection(p, playerId)
                print "  %s (remove from %s)" % (player["name"], p)
                
                # Choose replacement for player. To bring cost down, restrict price to the first
                # quartile.
   
                replacement = dao.findReplacement(p, 
                    selections.getSelectedPositions().iterkeys(),
                    minGames = minGames,        
                    priceLimit = quartiles[p].getQuartileBounds()[0])
                
                print "  Replace with: %s (%s)" % (replacement["name"], replacement["price"])
                byIds[replacement["id"]] = replacement
                selections.addSelections(p, replacement["id"])
                
totalPrice = dao.getTotalPrice(selections.getSelectedPositions().iterkeys())