private void cbFinished_CheckedChanged(object sender, System.EventArgs e)
        {
            if (!this._match.Started)
            {
                return;
            }

            if (MessageBox.Show("Finish?", "Finish", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                var data = new EUFAEntities();

                var evs = data.MatchEvents.Where(x => x.MatchId == this._match.Id).AsNoTracking().ToList();
                var r   = MatchResultCalc.FromEvents(this._match, evs);
                if (r.TeamACount == r.TeamBCount && this._match.StageCode != Stage.Group)
                {
                    MessageBox.Show("goals, bad, sad, add penalty shootout");
                    return;
                }

                this._match.Finished = this.cbFinished.Checked;

                var match = data.Matches.Find(this._match.Id);
                match.Finished = true;
                data.TrySave();

                _match.Finished = true;

                this.SetResultLabel();
            }
        }
        public static MatchResultCalc FromEvents(Match match, IEnumerable <MatchEvent> events)
        {
            var matchResult = new MatchResultCalc
            {
                Match = match
            };

            foreach (var ev in events.Where(x => x.EventType == MatchEventCode.Goal || x.EventType == MatchEventCode.Penalty))
            {
                if (ev.EventType == MatchEventCode.Goal)
                {
                    matchResult.TeamACount += ev.TeamA ? 1 : 0;
                    matchResult.TeamBCount += ev.TeamA ? 0 : 1;
                }
                else
                {
                    matchResult.TeamAPenalty += ev.TeamA ? 1 : 0;
                    matchResult.TeamBPenalty += ev.TeamA ? 0 : 1;
                }
            }

            matchResult.HasStarted   = match.Started;
            matchResult.IsInProgress = match.Started && !match.Finished;

            return(matchResult);
        }
        public static int Winner(Match match, IEnumerable <MatchEvent> results)
        {
            var res = MatchResultCalc.FromEvents(match, results);

            if (res.IsInProgress || res.TeamACount == res.TeamBCount)
            {
                return(-1);
            }

            return(res.TeamACount > res.TeamBCount ? match.TeamA : match.TeamB);
        }
        public void SetResultLabel()
        {
            this.lbResult.Text = MatchResultCalc.FromEvents(_match, _match.MatchEvents).ToString();

            if (_match.Started)
            {
                playerListTeamA.EditEnabled = false;
                playerListTeamB.EditEnabled = false;

                tabControl1.SelectedTab = eventTab;
            }
            else
            {
                tabControl1.TabPages.Remove(eventTab);
            }

            if (_match.Finished)
            {
                this.btAdd.Enabled       = false;
                this.btEditEvent.Enabled = false;
                this.btDelete.Enabled    = false;
            }
        }
        public static void Init(int tournamentId, string stage)
        {
            var data    = new EUFAEntities();
            var matches = new List <Match>();
            var random  = new Random();

            void add(int a, int b, string tag = null) => matches.Add(new Match
            {
                TeamA     = a,
                TeamB     = b,
                StageCode = stage,
                Tag       = tag
            });

            Func <string, int> getWinnerFn(string tagStart)
            {
                var m = data.Matches
                        .Include(x => x.MatchEvents)
                        .Where(x => x.Tag.Length == 3).ToList()
                        .Where(x => x.Tag.StartsWith(tagStart))
                        .ToList();

                int WinnerOf(string s)
                {
                    var cur = m.First(x => x.Tag == s);

                    return(MatchResultCalc.Winner(cur, cur.MatchEvents));
                }

                return(WinnerOf);
            }

            switch (stage)
            {
            case Stage.Group:
                var parts   = data.TournamentParticipations.Where(x => x.TournamentId == tournamentId).ToList();
                var byGroup = parts.GroupBy(x => x.GroupLetter);
                foreach (var group in byGroup)
                {
                    add(group.First(x => x.GroupNumber == 1).Id, group.First(x => x.GroupNumber == 2).Id);
                    add(group.First(x => x.GroupNumber == 1).Id, group.First(x => x.GroupNumber == 3).Id);
                    add(group.First(x => x.GroupNumber == 3).Id, group.First(x => x.GroupNumber == 4).Id);
                    add(group.First(x => x.GroupNumber == 4).Id, group.First(x => x.GroupNumber == 1).Id);
                    add(group.First(x => x.GroupNumber == 2).Id, group.First(x => x.GroupNumber == 4).Id);
                    add(group.First(x => x.GroupNumber == 2).Id, group.First(x => x.GroupNumber == 3).Id);
                }

                break;

            case Stage.RoundOf16:
                var groupMatches = data.Matches.Where(x => x.TournamentParticipation.TournamentId == tournamentId)
                                   .Where(x => x.StageCode == Stage.Group)
                                   .Include(x => x.MatchEvents)
                                   .Include(x => x.TournamentParticipation)
                                   .Include(x => x.TournamentParticipation1)
                                   .ToList()
                                   .Select(x => new
                {
                    TeamAId    = x.TeamA,
                    TeamBId    = x.TeamB,
                    Group      = x.TournamentParticipation.GroupLetter,
                    TeamAScore = MatchResultCalc.FromEvents(x, x.MatchEvents).TeamACount,
                    TeamBScore = MatchResultCalc.FromEvents(x, x.MatchEvents).TeamBCount
                }).ToList();
                var dict        = new Dictionary <string, IList <int> >();
                var thirdRanked = new List <Ranking>();
                foreach (var group in groupMatches.GroupBy(x => x.Group))
                {
                    int MatchesWon(int teamId)
                    {
                        var aWon = group.Where(x => x.TeamAId == teamId && x.TeamAScore > x.TeamBScore);
                        var bWon = group.Where(x => x.TeamBId == teamId && x.TeamBScore > x.TeamAScore);

                        return(aWon.Concat(bWon).Distinct().Count());
                    }

                    int GoalsScored(int teamId)
                    {
                        var aScored = group.Where(x => x.TeamAId == teamId).Sum(x => x.TeamAScore);
                        var bScored = group.Where(x => x.TeamBId == teamId).Sum(x => x.TeamBScore);

                        return(aScored + bScored);
                    }

                    int GoalsDifference(int teamId)
                    {
                        var aScored = group.Where(x => x.TeamAId == teamId).Sum(x => x.TeamAScore - x.TeamBScore);
                        var bScored = group.Where(x => x.TeamBId == teamId).Sum(x => x.TeamBScore - x.TeamAScore);

                        return(aScored + bScored);
                    }

                    var teamsInGroup = group.Select(x => x.TeamAId).Concat(group.Select(x => x.TeamBId)).Distinct().ToList();

                    var rankedTeams = teamsInGroup
                                      .Select(x => new Ranking
                    {
                        TeamId          = x,
                        MatchesWon      = MatchesWon(x),
                        GoalsDifference = GoalsDifference(x),
                        GoalsScored     = GoalsScored(x),
                        Random          = random.Next(),
                        Group           = group.Key
                    })
                                      .OrderByDescending(x => x.MatchesWon)
                                      .ThenByDescending(x => x.GoalsDifference)
                                      .ThenByDescending(x => x.GoalsScored)
                                      .ThenBy(x => x.Random)
                                      .ToList();

                    thirdRanked.Add(rankedTeams[2]);

                    dict.Add(group.Key, rankedTeams.Select(x => x.TeamId).ToList());
                }

                var third = new Dictionary <string, string[]>
                {
                    { "ABCD", new[] { "C", "D", "A", "B" } },
                    { "ABCE", new[] { "C", "A", "B", "E" } },
                    { "ABCF", new[] { "C", "A", "B", "F" } },
                    { "ABDE", new[] { "D", "A", "B", "E" } },
                    { "ABDF", new[] { "D", "A", "B", "F" } },
                    { "ABEF", new[] { "E", "A", "B", "F" } },
                    { "ACDE", new[] { "C", "D", "A", "E" } },
                    { "ACDF", new[] { "C", "D", "A", "F" } },
                    { "ACEF", new[] { "C", "A", "F", "E" } },
                    { "ADEF", new[] { "D", "A", "F", "E" } },
                    { "BCDE", new[] { "C", "D", "B", "E" } },
                    { "BCDF", new[] { "C", "D", "B", "F" } },
                    { "BCEF", new[] { "E", "C", "B", "F" } },
                    { "BDEF", new[] { "E", "D", "B", "F" } },
                    { "CDEF", new[] { "C", "D", "F", "E" } }
                };

                var thirdRankedInOrder = thirdRanked
                                         .OrderByDescending(x => x.MatchesWon)
                                         .ThenByDescending(x => x.GoalsDifference)
                                         .ThenByDescending(x => x.GoalsScored)
                                         .Take(4)
                                         .ToList();
                var key = string.Join(string.Empty, thirdRankedInOrder.Select(x => x.Group).ToList());

                string DetermineThirdGroup(int index)
                {
                    return(third[key][index]);
                }

                add(dict["A"][1], dict["C"][1], "AF1");
                add(dict["B"][0], dict[DetermineThirdGroup(1)][2], "AF2");
                add(dict["D"][0], dict[DetermineThirdGroup(3)][2], "AF3");
                add(dict["A"][0], dict[DetermineThirdGroup(0)][2], "AF4");
                add(dict["C"][0], dict[DetermineThirdGroup(2)][2], "AF5");
                add(dict["F"][0], dict["E"][1], "AF6");
                add(dict["E"][0], dict["D"][1], "AF7");
                add(dict["B"][1], dict["F"][1], "AF8");
                break;

            case Stage.QuarterFinal:
                var qfWin = getWinnerFn("AF");
                add(qfWin("AF1"), qfWin("AF3"), "QF1");
                add(qfWin("AF2"), qfWin("AF6"), "QF2");
                add(qfWin("AF5"), qfWin("AF7"), "QF3");
                add(qfWin("AF4"), qfWin("AF8"), "QF4");
                break;

            case Stage.SemiFinal:
                var smWin = getWinnerFn("QF");
                add(smWin("QF1"), smWin("QF2"), "SF1");
                add(smWin("QF2"), smWin("QF4"), "SF2");
                break;

            case Stage.Final:
                var fWin = getWinnerFn("SF");
                add(fWin("SF1"), fWin("SF2"), "TF1");
                break;

            default:
                throw new Exception();
            }

            data.Matches.AddRange(matches);
            data.TrySave();
        }