/// <summary>
        /// This creates a best-out-of-three match for the Finale and a solo match for the Bronze Finale.
        /// </summary>
        public static void CreateFinaleStructure()
        {
            // Finale
            for (int p = 0; p < 3; p++)
            {
                var match = new Match {Phase = Phase.Finale, Priority = p};
                Mongo.Matches.Save(match);
            }

            // Losers' finale
            var losers = new Match {Phase = Phase.LoserFinale};
            Mongo.Matches.Save(losers);

            // Bronze finale
            var bronze = new Match { Phase = Phase.BronzeFinale };
            Mongo.Matches.Save(bronze);
        }
        /// <summary>
        /// This method creates the pool structure and adds it to the database.
        /// Teams are divided into groups of 4, based on their MMR.
        /// 
        /// Only works when there are 2^N with N >= 4 teams.
        /// </summary>
        public static void CreatePoolStructure()
        {
            // Get competing teams
            var validTeams = Mongo.Teams.FindAll()
                .OrderByDescending(x => x.AmountOfRuStudents)
                .ThenBy(x => x.Participants.Sum(y => y.RegisterTime.Ticks))
                .Take(32)
                .OrderByDescending(x => x.MMR).ToList();

            // For each pool
            for (int i = 0; i < validTeams.Count() / 4; i++)
            {
                Team[] teams = {validTeams[i], validTeams[validTeams.Count()/2 - i - 1], validTeams[validTeams.Count()/2 + i], validTeams[(int)(validTeams.Count()*0.75) + i]};
                List<int>[] availabilityLists = { new List<int> { 0, 1, 2 }, new List<int> { 0, 1, 2 }, new List<int> { 0, 1, 2 }, new List<int> { 0, 1, 2 } };

                // For each team
                for (int j = 0; j < 4; j++)
                {
                    // Set pool in team objects
                    teams[j].Pool = i;
                    Mongo.Teams.Save(teams[j]);

                    // For each team below team j
                    for (int k = j + 1; k < 4; k++)
                    {
                        // Determine priority
                        var intersect = availabilityLists[j].Intersect(availabilityLists[k]);
                        var p = intersect.Min();

                        // Remove chosen priority from team availability lists
                        availabilityLists[j].Remove(p);
                        availabilityLists[k].Remove(p);

                        // Determine sides (lowest MMR = blue)
                        var blue = teams[j].MMR < teams[k].MMR ? teams[j].Id : teams[k].Id;
                        var purple = teams[j].MMR >= teams[k].MMR ? teams[j].Id : teams[k].Id;

                        // Create match and add to database
                        var match = new Match { BlueTeamId = blue, PurpleTeamId = purple, Phase = Phase.Pool, Priority = p };
                        Mongo.Matches.Save(match);
                    }
                }

            }
        }
        /// <summary>
        /// Checks whether the match that was just played has consequences for the structure of the rest of the tournament. If so, push these consequences into the database.
        /// </summary>
        /// <param name="finishedMatch">The match that was just finished.</param>
        private static void NewMatch(Match finishedMatch)
        {
            var finishedMatchWinner = finishedMatch.Winner;

            if (finishedMatch.Phase == Phase.Pool)
            {
                var pool = finishedMatch.BlueTeam.Pool;

                // Check whether the pool is finished
                if (PoolFinished(pool, Mongo.Matches))
                {
                    // Pool is finished
                    // To create brackets, one of the other pools also needs to be finished.
                    // Pools are coupled as follows: 1,2 | 3,4 | etc.

                    int otherPool;

                    // If this is an even pool
                    if (pool%2 == 0)
                        otherPool = pool + 1;
                    else
                        otherPool = pool - 1;

                    // If coupled pool is also finished
                    if (PoolFinished(otherPool, Mongo.Matches))
                    {
                        // Get ranking for pools
                        var poolARanking = GetPoolRanking(pool, Mongo.Teams);
                        var poolBRanking = GetPoolRanking(otherPool, Mongo.Teams);

                        // We can now create the brackets for these pools
                        // Winner bracket
                        var match = new Match {BlueTeamId = poolARanking[0].Id, PurpleTeamId = poolBRanking[1].Id, Phase = Phase.WinnerBracket, Priority = Math.Min(pool, otherPool)};
                        var match2 = new Match { BlueTeamId = poolBRanking[0].Id, PurpleTeamId = poolARanking[1].Id, Phase = Phase.WinnerBracket, Priority = Math.Max(pool, otherPool)};
                        Mongo.Matches.Save(match);
                        Mongo.Matches.Save(match2);

                        // Loser bracket
                        var match3 = new Match { BlueTeamId = poolARanking[2].Id, PurpleTeamId = poolBRanking[3].Id, Phase = Phase.LoserBracket, Priority = Math.Min(pool, otherPool) };
                        var match4 = new Match { BlueTeamId = poolBRanking[2].Id, PurpleTeamId = poolARanking[3].Id, Phase = Phase.LoserBracket, Priority = Math.Max(pool, otherPool) };
                        Mongo.Matches.Save(match3);
                        Mongo.Matches.Save(match4);

                        // Set the teams to the correct phase
                        poolARanking[0].Phase = Phase.WinnerBracket;
                        poolARanking[0].OnHold = false;
                        poolARanking[1].Phase = Phase.WinnerBracket;
                        poolARanking[1].OnHold = false;
                        poolARanking[2].Phase = Phase.LoserBracket;
                        poolARanking[2].OnHold = false;
                        poolARanking[3].Phase = Phase.LoserBracket;
                        poolARanking[3].OnHold = false;

                        poolBRanking[0].Phase = Phase.WinnerBracket;
                        poolBRanking[0].OnHold = false;
                        poolBRanking[1].Phase = Phase.WinnerBracket;
                        poolBRanking[1].OnHold = false;
                        poolBRanking[2].Phase = Phase.LoserBracket;
                        poolBRanking[2].OnHold = false;
                        poolBRanking[3].Phase = Phase.LoserBracket;
                        poolBRanking[3].OnHold = false;

                        // Save all to database
                        Mongo.Teams.Save(poolARanking[0]);
                        Mongo.Teams.Save(poolARanking[1]);
                        Mongo.Teams.Save(poolARanking[2]);
                        Mongo.Teams.Save(poolARanking[3]);

                        Mongo.Teams.Save(poolBRanking[0]);
                        Mongo.Teams.Save(poolBRanking[1]);
                        Mongo.Teams.Save(poolBRanking[2]);
                        Mongo.Teams.Save(poolBRanking[3]);
                    }
                    else
                    {
                        // Set all teams in pool to Hold
                        var teams = Mongo.Teams.Find(Query<Team>.Where(x => x.Pool == pool));
                        foreach (var t in teams)
                        {
                            t.OnHold = true;
                            Mongo.Teams.Save(t);
                        }
                    }
                }
                // If this was the final match in the pool for this team
                else if (finishedMatch.Priority == 2)
                {
                    // Set match teams on hold since they don't have any matches left
                    Team[] teams = {finishedMatch.BlueTeam, finishedMatch.PurpleTeam};
                    foreach (var t in teams)
                    {
                        t.OnHold = true;
                        Mongo.Teams.Save(t);
                    }
                }
            }
            else if (finishedMatch.Phase == Phase.WinnerBracket || finishedMatch.Phase == Phase.LoserBracket)
            {
                // First phase
                if (finishedMatch.Priority <= 7)
                {
                    int[] couples =
                    {
                        4,
                        5,
                        6,
                        7,
                        0,
                        1,
                        2,
                        3
                    };

                    // Check if other match is also finished
                    var otherPrio = couples[finishedMatch.Priority];
                    var matchFinished =
                        Mongo.Matches.Find(
                            Query<Match>.Where(
                                x => x.Finished && x.Phase == finishedMatch.Phase && x.Priority == otherPrio));

                    // It's finished, add new bracket match
                    if (matchFinished.Count() == 1)
                    {
                        var otherTeam = matchFinished.First().Winner;

                        var match = new Match
                        {
                            BlueTeamId = finishedMatch.WinnerId,
                            PurpleTeamId = otherTeam.Id,
                            Phase = finishedMatch.Phase,
                            Priority = Math.Min(finishedMatch.Priority, otherPrio) + 8
                        };

                        Mongo.Matches.Save(match);

                        // Set OnHold = false for teams
                        finishedMatchWinner.OnHold = false;
                        otherTeam.OnHold = false;

                        Mongo.Teams.Save(finishedMatch.Winner);
                        Mongo.Teams.Save(otherTeam);
                    }
                    else
                    {
                        // Not finished, put team on hold
                        finishedMatchWinner.OnHold = true;
                        Mongo.Teams.Save(finishedMatchWinner);
                    }
                }
                // Second phase
                else if (finishedMatch.Priority >= 8 && finishedMatch.Priority <= 11)
                {
                    var couples = new Dictionary<int, int>
                    {
                        {8, 10},
                        {10, 8},
                        {9, 11},
                        {11, 9}
                    };

                    // Check if other match is also finished
                    var otherPrio = couples[finishedMatch.Priority];
                    var matchFinished =
                        Mongo.Matches.Find(
                            Query<Match>.Where(
                                x => x.Finished && x.Phase == finishedMatch.Phase && x.Priority == otherPrio));

                    // It's finished, add new bracket match
                    if (matchFinished.Count() == 1)
                    {
                        var otherTeam = matchFinished.First().Winner;

                        var match = new Match
                        {
                            BlueTeamId = finishedMatch.WinnerId,
                            PurpleTeamId = matchFinished.First().WinnerId,
                            Phase = finishedMatch.Phase,
                            Priority = Math.Min(finishedMatch.Priority, otherPrio) + 4
                        };

                        Mongo.Matches.Save(match);

                        // Set OnHold = false for teams
                        finishedMatchWinner.OnHold = false;
                        otherTeam.OnHold = false;

                        Mongo.Teams.Save(finishedMatch.Winner);
                        Mongo.Teams.Save(otherTeam);
                    }
                    else
                    {
                        // Not finished, put team on hold
                        finishedMatchWinner.OnHold = true;
                        Mongo.Teams.Save(finishedMatchWinner);
                    }
                }
                // Third phase, don't do this for loser bracket
                else if ((finishedMatch.Priority == 12 || finishedMatch.Priority == 13) && finishedMatch.Phase == Phase.WinnerBracket)
                {
                    // Check if other match is also finished
                    var otherPrio = finishedMatch.Priority == 12 ? 13 : 12;
                    var matchFinished =
                        Mongo.Matches.Find(
                            Query<Match>.Where(
                                x => x.Finished && x.Phase == Phase.WinnerBracket && x.Priority == otherPrio));

                    // It's finished, set finale match
                    if (matchFinished.Count() == 1)
                    {
                        var match = Mongo.Matches.Find(Query<Match>.Where(x => x.Phase == Phase.Finale && x.Priority == 0)).First();
                        match.BlueTeamId = finishedMatch.WinnerId;
                        match.PurpleTeamId = matchFinished.First().WinnerId;
                        Mongo.Matches.Save(match);

                        // Switch sides
                        match = Mongo.Matches.Find(Query<Match>.Where(x => x.Phase == Phase.Finale && x.Priority == 1)).First();
                        match.BlueTeamId = matchFinished.First().WinnerId;
                        match.PurpleTeamId = finishedMatch.WinnerId;
                        Mongo.Matches.Save(match);

                        // Switch sides again
                        match = Mongo.Matches.Find(Query<Match>.Where(x => x.Phase == Phase.Finale && x.Priority == 2)).First();
                        match.BlueTeamId = finishedMatch.WinnerId;
                        match.PurpleTeamId = matchFinished.First().WinnerId;
                        Mongo.Matches.Save(match);

                        // Set team phases
                        var blueTeam = match.BlueTeam;
                        var purpleTeam = match.PurpleTeam;

                        blueTeam.Phase = Phase.Finale;
                        blueTeam.OnHold = false;
                        purpleTeam.Phase = Phase.Finale;
                        purpleTeam.OnHold = false;

                        // Save all to database
                        Mongo.Teams.Save(blueTeam);
                        Mongo.Teams.Save(purpleTeam);

                        // Also set bronze finale match
                        match = Mongo.Matches.Find(Query<Match>.Where(x => x.Phase == Phase.BronzeFinale)).First();
                        match.BlueTeamId = finishedMatch.BlueTeamId == finishedMatch.WinnerId ? finishedMatch.PurpleTeamId : finishedMatch.BlueTeamId;
                        match.PurpleTeamId = matchFinished.First().BlueTeamId == matchFinished.First().WinnerId ? matchFinished.First().PurpleTeamId : matchFinished.First().BlueTeamId;
                        Mongo.Matches.Save(match);

                        // And set their teams to the correct phase
                        blueTeam = match.BlueTeam;
                        purpleTeam = match.PurpleTeam;

                        blueTeam.Phase = Phase.BronzeFinale;
                        blueTeam.OnHold = false;
                        purpleTeam.Phase = Phase.BronzeFinale;
                        purpleTeam.OnHold = false;

                        // Save all to database
                        Mongo.Teams.Save(blueTeam);
                        Mongo.Teams.Save(purpleTeam);
                    }
                    else
                    {
                        // Not finished, put team on hold
                        finishedMatchWinner.OnHold = true;
                        var loser = finishedMatchWinner.Id == finishedMatch.BlueTeamId
                            ? finishedMatch.PurpleTeam
                            : finishedMatch.BlueTeam;
                        loser.OnHold = true;
                        Mongo.Teams.Save(finishedMatchWinner);
                        Mongo.Teams.Save(loser);
                    }
                }
                // Set up loser finale
                else if ((finishedMatch.Priority == 12 || finishedMatch.Priority == 13) && finishedMatch.Phase == Phase.LoserBracket)
                {
                    // Check if other match is also finished
                    var otherPrio = finishedMatch.Priority == 12 ? 13 : 12;
                    var matchFinished =
                        Mongo.Matches.Find(
                            Query<Match>.Where(
                                x => x.Finished && x.Phase == Phase.LoserBracket && x.Priority == otherPrio));

                    // It's finished, set loser finale match
                    if (matchFinished.Count() == 1)
                    {
                        var match = Mongo.Matches.Find(Query<Match>.Where(x => x.Phase == Phase.LoserFinale && x.Priority == 0)).First();
                        match.BlueTeamId = finishedMatch.WinnerId;
                        match.PurpleTeamId = matchFinished.First().WinnerId;
                        Mongo.Matches.Save(match);

                        // Set team phases
                        var blueTeam = match.BlueTeam;
                        var purpleTeam = match.PurpleTeam;

                        blueTeam.Phase = Phase.LoserFinale;
                        blueTeam.OnHold = false;
                        purpleTeam.Phase = Phase.LoserFinale;
                        purpleTeam.OnHold = false;

                        // Save all to database
                        Mongo.Teams.Save(blueTeam);
                        Mongo.Teams.Save(purpleTeam);
                    }
                    else
                    {
                        // Not finished, put team on hold
                        finishedMatchWinner.OnHold = true;
                        var loser = finishedMatchWinner.Id == finishedMatch.BlueTeamId
                            ? finishedMatch.PurpleTeam
                            : finishedMatch.BlueTeam;
                        loser.OnHold = true;
                        Mongo.Teams.Save(finishedMatchWinner);
                        Mongo.Teams.Save(loser);
                    }
                }
            }
            else if (finishedMatch.Phase == Phase.BronzeFinale)
            {
                // Add third and fourth place to database
                var winner = finishedMatch.Winner;
                var loser = finishedMatch.BlueTeamId == winner.Id ? finishedMatch.PurpleTeam : finishedMatch.BlueTeam;
                winner.FinalRanking = 3;
                loser.FinalRanking = 4;

                Mongo.Teams.Save(winner);
                Mongo.Teams.Save(loser);
            }
            else if (finishedMatch.Phase == Phase.Finale)
            {
                if (finishedMatch.Priority == 2)
                {
                    // We have played all three matches, add final rankings to database
                    var winsBlueTeam = Mongo.Matches.Count(Query<Match>.Where(x => x.Phase == Phase.Finale && x.WinnerId == finishedMatch.BlueTeamId));
                    var winner = winsBlueTeam >= 2 ? finishedMatch.BlueTeam : finishedMatch.PurpleTeam;
                    var loser = winner.Id == finishedMatch.BlueTeamId ? finishedMatch.PurpleTeam : finishedMatch.BlueTeam;

                    winner.FinalRanking = 1;
                    loser.FinalRanking = 2;

                    Mongo.Teams.Save(winner);
                    Mongo.Teams.Save(loser);
                }
                else if (finishedMatch.Priority == 1)
                {
                    // We have played two matches so far
                    var winsBlueTeam = Mongo.Matches.Count(Query<Match>.Where(x => x.Phase == Phase.Finale && x.WinnerId == finishedMatch.BlueTeamId));
                    if (winsBlueTeam == 0 || winsBlueTeam == 2)
                    {
                        // It's already decided, scratch third match
                        Mongo.Matches.Remove(Query<Match>.Where(x => x.Phase == Phase.Finale && x.Priority == 2));

                        var winner = finishedMatch.Winner; // winner is always also the winner of the previous match
                        var loser = winner.Id == finishedMatch.BlueTeamId ? finishedMatch.PurpleTeam : finishedMatch.BlueTeam;

                        winner.FinalRanking = 1;
                        loser.FinalRanking = 2;

                        Mongo.Teams.Save(winner);
                        Mongo.Teams.Save(loser);
                    }
                }
                else if (finishedMatch.Priority == 0)
                {
                    // This was the first match, do nothing
                }
            }
        }