class Test_games_manager_game_details(unittest.TestCase):
    def setUp(self):
        init_DB(status="", folder=db_path)
        self.assertTrue(os.path.exists(db_path))

        self.db_games_manager = GamesController(db_path)

        load_env_vars()

    def tearDown(self):
        shutil.rmtree(db_path)
        self.assertFalse(os.path.exists(db_path))

    def test_get_game_details(self):
        game_name = "Mario Party"
        game = self.db_games_manager.get_game_details(game_name)

        self.assertNotEqual(False, game)
        self.assertNotEqual([], game)

    def test_get_unexisting_game_details(self):
        game_name = "Mario Party1111111"
        game = self.db_games_manager.get_game_details(game_name)

        self.assertEqual(None, game)
class Test_games_manager_game_exist(unittest.TestCase):
    def setUp(self):
        init_DB(status="", folder=db_path)
        self.assertTrue(os.path.exists(db_path))

        self.db_games_manager = GamesController(db_path)

        load_env_vars()

    def tearDown(self):
        shutil.rmtree(db_path)
        self.assertFalse(os.path.exists(db_path))

    def test_game_exist(self):
        game_name = "Mario Party Fushigi no Challenge World"
        game = self.db_games_manager.does_game_exists(game_name)

        self.assertNotEqual(False, game)
        self.assertEqual(1, len(game))
        self.assertEqual(game_name, game[0]["name"])

    def test_game_d_exist(self):
        game_name = "Mario Party11111"
        game = self.db_games_manager.does_game_exists(game_name)

        self.assertFalse(game)
    def setUp(self):
        init_DB(status="", folder=db_path)
        self.assertTrue(os.path.exists(db_path))

        self.db_games_manager = GamesController(db_path)

        load_env_vars()
    def __init__(self, folder="db"):
        '''
            Constructor
        '''

        if not os.path.exists(folder):
            os.mkdir(folder)

        init_DB_session(self, folder)

        self.db_users_manager = UsersController(folder)
        self.db_games_manager = GamesController(folder)
class Test_games_manager_get_list_of_games(unittest.TestCase):
    def setUp(self):
        init_DB(status="", folder=db_path)
        self.assertTrue(os.path.exists(db_path))

        self.db_games_manager = GamesController(db_path)

        load_env_vars()

    def tearDown(self):
        shutil.rmtree(db_path)
        self.assertFalse(os.path.exists(db_path))

    def test_get_list_of_games(self):
        list_games = self.db_games_manager.get_list_of_games("Mario")

        self.assertTrue(type(list_games) is list)
        self.assertNotEqual([], list_games)

    def test_get_list_of_games_empty(self):
        list_games = self.db_games_manager.get_list_of_games("Mario1235124123")

        self.assertTrue(type(list_games) is list)
        self.assertEqual([], list_games)
class ChallengesController(object):
    '''
        Databases to handle challenges
    '''

    def __init__(self, folder="db"):
        '''
            Constructor
        '''

        if not os.path.exists(folder):
            os.mkdir(folder)

        init_DB_session(self, folder)

        self.db_users_manager = UsersController(folder)
        self.db_games_manager = GamesController(folder)

    @db_session_setup
    def get_challenge_details(self, challenge_name):
        '''
            Return a challenge details given its name
        '''
        challenge = self.session.query(Challenge).filter(
                Challenge.title == challenge_name).first()

        if challenge is not None:
            data = challenge
        else:
            data = None
        return data

    @db_session_setup
    def get_last_n_challenges(self, n):
        '''
            Retrieve the last n challenges
        '''
        challenges = []

        for challenge in self.session.query(Challenge).all()[:n]:
            game_data = self.db_games_manager.get_game_details(challenge.game)

            # Possible that the connection to the game API cannot be done
            # In that case
            data = (challenge, game_data)

            challenges.append(data)

        return challenges

    @db_session_setup
    def get_your_challenges(self, username):
        '''
            Retrieve a user challenges given its username
        '''
        challenges_q = self.session.query(Challenge).filter(
                or_(Challenge.user1 == username, Challenge.user2 == username))
        challenges = challenges_q.all()
        challenges_with_games = []

        for challenge in challenges:
            game_data = self.db_games_manager.get_game_details(challenge.game)
            challenges_with_games.append((challenge, game_data))

        return challenges_with_games

    @db_session_setup
    def get_ranking(self):
        '''
            Retrieve a user challenges given its username
            TODO: improve the ranking
        '''

        users = self.db_users_manager.get_users()

        # Index by the number of wins
        ranking = {}
        for user in users:
            query_user = self.session.query(Challenge).filter(
                    Challenge.user2 == user)
            query_user_status = query_user.filter(
                    Challenge.status == 'won')

            nb_wins = len(query_user_status.all())

            tmp = ranking.get(nb_wins, [])
            tmp.append(user)
            ranking[nb_wins] = tmp

        # Sort by number of wins
        for nb_wins in ranking:
            ranking[nb_wins].sort()

        overall_ranking = []

        for rank in ranking:
            overall_ranking.append(ranking[rank])

        return overall_ranking

    @db_session_setup
    def get_all_challenges(self):
        '''
            Retrieve all challenges
        '''
        challenges = self.session.query(Challenge).all()
        challenges_with_games = []

        for challenge in challenges:
            game_data = self.db_games_manager.get_game_details(challenge.game)

            challenges_with_games.append((challenge, game_data))

        return challenges_with_games

    @db_session_setup
    def get_number_unseen_challenges(self, username):
        '''
            Return the number of new challenges
        '''
        challenges_q = self.session.query(Challenge)
        challenges_received = challenges_q.filter(Challenge.user2 == username)
        challenges_accept_or_new = challenges_received.filter(
                or_(Challenge.status == 'new', Challenge.status == 'accepted'))
        nb_unseen = len(challenges_accept_or_new.all())

        return nb_unseen

    @db_session_setup
    def new_challenge(self,
                      title,
                      challenger,
                      contestant,
                      game_name,
                      description,
                      time_limit):
        '''
            Add a new challenge
        '''
        challenge = Challenge(title=title,
                              content=description,
                              user1=challenger, user2=contestant,
                              game=game_name,
                              time_limit=time_limit)
        self.session.add(challenge)
        self.session.commit()

        return True

    def _get_challenge(self, title):
        challenge_unfiltered = self.session.query(Challenge)
        filtered = challenge_unfiltered.filter(Challenge.title == title)
        return filtered.first()

    @db_session_setup
    def accept_challenge(self, title, username):
        '''
            Update the status of a challenge to accepted
        '''
        try:
            challenge = self._get_challenge(title)
            if challenge.user2 == username:
                challenge.status = "accepted"
                self.session.commit()

                return (True, challenge.id)
            else:
                return (False, None)
        except:
            return (False, None)

    def get_challenge_in_progress_status(self, id):
        curr_time = self.challenges_curr_time.get(id, -1)

        if curr_time == -1:
            # TODO: raise a better exception
            raise Exception()

        return curr_time

    @db_session_setup
    def decline_challenge(self, title, username):
        '''
            Update the status of a challenge to declined
        '''
        try:
            challenge = self._get_challenge(title)

            if challenge.user2 == username:
                challenge.status = "declined"
                self.session.commit()
                return True
            else:
                return False
        except:
            return False

    @db_session_setup
    def succeed_challenge(self, title, username):
        '''
            Update the status of a challenge to won
        '''
        try:
            challenge = self._get_challenge(title)

            if challenge.user1 == username and challenge.status != "declined":
                challenge.status = "won"
                self.session.commit()
                return True
            else:
                return False

        except:
            return False

    @db_session_setup
    def fail_challenge(self, title, username):
        '''
            Update the status of a challenge to lost
        '''
        try:
            challenge = self._get_challenge(title)

            if challenge.user1 == username and challenge.status != "declined":
                challenge.status = "lost"
                self.session.commit()
                return True
            else:
                return False
        except:
            return False