/// <summary>
        /// Calculates the return leg based on the previously calculated first leg
        /// by swapping home / guest team and assigning the referee.
        /// </summary>
        private void CalcCombinationsReturnLeg()
        {
            _combinationGroupReturnLeg.Clear();
            T referee = _combinationGroup[0].Referee;             // just to make the compiler happy

            foreach (var match in _combinationGroup)
            {
                // re-assign referee according to settings:
                switch (_refereeType)
                {
                case RefereeType.HomeTeam:
                    referee = match.GuestTeam; break;

                case RefereeType.GuestTeam:
                    referee = match.HomeTeam; break;

                case RefereeType.OtherTeamOfGroup:
                    referee = match.Referee; break;
                }
                _combinationGroupReturnLeg.Add(new TeamCombination <T>(match.GuestTeam, match.HomeTeam, referee));
            }
        }
        /// <summary>
        /// Groups the calculated team combinations for matches.  in a way, that most matches
        /// can be played in parallel.
        /// </summary>
        /// <param name="legType">First leg or return leg.</param>
        /// <param name="optiType">Optimization type for groups. Differences can be seen be with an uneven number of teams.</param>
        /// <returns>Return a collection containing collections of team combinations.</returns>
        internal Collection <TeamCombinationGroup <T> > GetBundledGroups(LegType legType, CombinationGroupOptimization optiType)
        {
            var combinationsQueue = new Queue <TeamCombination <T> >(_group.Count);
            TeamCombinationGroup <T> group;
            var bundledGroups = new Collection <TeamCombinationGroup <T> >();

            // create the FIFO queue
            foreach (var combination in _group)
            {
                combinationsQueue.Enqueue(combination);
            }

            switch (optiType)
            {
            case CombinationGroupOptimization.NoGrouping:
                // every group contains a collection with only 1 match
                while (combinationsQueue.Count > 0)
                {
                    group = new TeamCombinationGroup <T>();
                    group.Add(combinationsQueue.Dequeue());
                    bundledGroups.Add(group);
                }
                break;

            case CombinationGroupOptimization.GroupWithAlternatingHomeGuest:
                group = new TeamCombinationGroup <T>();
                while (combinationsQueue.Count > 0)
                {
                    TeamCombination <T> combination = combinationsQueue.Dequeue();
                    if (AnyTeamExistsInGroup(combination, group))
                    {
                        bundledGroups.Add(group);
                        group = new TeamCombinationGroup <T>();
                    }
                    group.Add(combination);
                }
                if (group.Count > 0)
                {
                    bundledGroups.Add(group);
                }
                break;

            case CombinationGroupOptimization.LeastGroupsPossible:
                while (combinationsQueue.Count > 0)
                {
                    var tmpGroup = new List <TeamCombination <T> >();
                    tmpGroup.AddRange(combinationsQueue);

                    group = new TeamCombinationGroup <T>();
                    foreach (var combination in tmpGroup)
                    {
                        if (!AnyTeamExistsInGroup(combination, group))
                        {
                            group.Add(combinationsQueue.Dequeue());
                        }
                    }
                    bundledGroups.Add(group);
                }
                break;
            }
            return(bundledGroups);
        }
        /// <summary>
        /// Doing the job of creating matches for all teams.
        /// </summary>
        private void CalcCombinations()
        {
            /*
             * Round robin match calculations are as follows.
             * Example with 5 teams (which total in 10 matches):
             +-   A -+    -+ -+
             |       |     |  |
             +- | +- B -+ -+  |  |
             |  | |        |  |  |
             +- |  | |  C -+ -+  | -+
             |  |  | |     |     |
             |  |  | +- D -+ -+ -+
             |  |  |          |
             +- +- +-   E    -+
             */
            if (_teams.Count < 2)
            {
                throw new Exception("Round Robin system requires at least 2 teams.");
            }

            if (_teams.Count < 3 && _refereeType == RefereeType.OtherTeamOfGroup)
            {
                throw new Exception("Round Robin system with separate referee requires at least 3 teams.");
            }

            _combinationGroup.Clear();
            _maxNumOfCombinations   = _teams.Count * (_teams.Count - 1) / 2;
            _teamCombinationsPerLeg = _teams.Count - 1;

            for (int count = 0; count < _maxNumOfCombinations; count++)
            {
                T homeTeam  = GetHomeTeam();
                T guestTeam = GetGuestTeam(homeTeam);
                T referee   = homeTeam;

                int homeTeamNumOfHomeCombs  = GetNumOfHomeCombinations(homeTeam);
                int guestTeamNumOfHomeCombs = GetNumOfHomeCombinations(guestTeam);

                // make sure that home matches are alternating
                if (homeTeamNumOfHomeCombs <= guestTeamNumOfHomeCombs)
                {
                    _combinationGroup.Add(new TeamCombination <T>(homeTeam, guestTeam, referee));
                }
                else
                {
                    _combinationGroup.Add(new TeamCombination <T>(guestTeam, homeTeam, referee));
                }

                // re-assign referee according to settings
                switch (_refereeType)
                {
                case RefereeType.HomeTeam:
                    _combinationGroup[count].Referee = _combinationGroup[count].HomeTeam; break;

                case RefereeType.GuestTeam:
                    _combinationGroup[count].Referee = _combinationGroup[count].GuestTeam; break;

                case RefereeType.OtherTeamOfGroup:
                    _combinationGroup[count].Referee = GetReferee(homeTeam, guestTeam); break;
                }
            }

            CalcCombinationsReturnLeg();
        }