private static void RenderScores(HtmlTextWriter htmlWriter, MatchHeaderInfo match, int player)
        {
            htmlWriter.AddAttribute(HtmlTextWriterAttribute.Class, "scores");
            htmlWriter.RenderBeginTag(HtmlTextWriterTag.Div);
            if (match.SetScores.IsNullOrEmpty() && (int)match.Status < (int)MatchStatus.Completed)
            {
                if (player == 0)
                {

                    htmlWriter.Write(match.Date);
                }
                else if (match.StartTime.HasValue)
                {
                    htmlWriter.Write(match.StartTime.Value.ToString("HH:mm"));
                }
            }
            else
            {
                foreach (var setScore in match.SetScores)
                {
                    
                    htmlWriter.RenderBeginTag(HtmlTextWriterTag.Span);
                    var points = (player == 0 ? setScore.Player1Points : setScore.Player2Points);
                    htmlWriter.Write(points == 0 ? " " : points.ToString());
                    htmlWriter.RenderEndTag();
                }
            }
            htmlWriter.RenderEndTag();
        }
        private IEnumerable<MatchHeaderInfo> CreateConselationMatches(int finalPlayersCount)
        {
            var section = CompetitionSection.Consolation;

            var playersCount = finalPlayersCount;
            var matches = new List<MatchHeaderInfo>();
            var round = 0;
            var position = 0;
            var roundRelativePosition = 0;
            var match = default(MatchHeaderInfo);
            for (var i = (playersCount / 4); i >= 4; i /= 2)
            {
                for (var x = 0; x < 2; x++)
                {
                    for (var j = 0; j < i; j++)
                    {
                        match = new MatchHeaderInfo();
                        match.Section = section;
                        match.Position = position++;
                        match.RoundRelativePosition = roundRelativePosition++;
                        match.Round = round;
                        match.Status = MatchStatus.Created;
                        matches.Add(match);
                    }
                    round++;
                    roundRelativePosition = 0;
                }


            }

            match = new MatchHeaderInfo();
            match.Section = section;
            match.Position = position++;
            match.Round = round;
            match.IsSemiFinal = true;
            match.Status = MatchStatus.Created;
            matches.Add(match);            
            match = new MatchHeaderInfo();
            match.Section = section;
            match.Position = position++;
            match.Round = round;
            match.IsSemiFinal = true;
            match.Status = MatchStatus.Created;
            matches.Add(match);
            round++;

            match = new MatchHeaderInfo();
            match.Section = section;
            match.Position = position++;
            match.Round = round;
            match.IsFinal = true;
            match.Status = MatchStatus.Created;
            matches.Add(match);            

            return matches;

        }
        public static MatchHeaderInfo MapFromData(this Match match)
        {
            var result = new MatchHeaderInfo()
            {
                Id = match.Id,
                StartTime = match.StartTime.HasValue ? DateTime.SpecifyKind(match.StartTime.Value, DateTimeKind.Utc).ToLocalTime() : default(DateTime?),
                Status = (MatchStatus)match.Status,
                Section = (CompetitionSection)match.SectionId,
                CompetitionId = match.CompetitionId,
                StartTimeType = (StartTimeType)match.StartTimeType,
                Round = match.Round,
                RoundRelativePosition = match.RoundRelativePosition,
                Position = match.Position,
                IsFinal = match.IsFinal,
                IsSemiFinal = match.IsSemiFinal,
                SlotPosition = match.SlotPosition,
                Player1Code = match.Player1Code,
                Player2Code = match.Player2Code,
            };
            if (match.SlotType.HasValue)
            {
                result.SlotType = (SlotType) match.SlotType.Value;
            }
            if (match.Winner.HasValue)
            {
                result.Winner = (MatchWinner)match.Winner.Value;
            }
            if (match.Result.HasValue)
            {
                result.Result = (MatchResult)match.Result.Value;
            }

            result.Player1 = CreateMatchPlayerFromData(match.Player);
            result.Player2 = CreateMatchPlayerFromData(match.Player5);
            result.Player3 = CreateMatchPlayerFromData(match.Player6);
            result.Player4 = CreateMatchPlayerFromData(match.Player7);
            result.SetScores =
                match.MatchScores.Select(ms => new SetScore()
                {
                    Number = ms.SetNumber,
                    Player1Points = ms.Player1Points,
                    Player2Points = ms.Player2Points,
                    BreakPoints = ms.BreakPoints
                }).ToArray();

            return result;        
        }
        private void RenderContainer(HtmlTextWriter htmlWriter, int round, int minRound, Dictionary<int, Queue<MatchHeaderInfo>> map, MatchHeaderInfo match, int player)
        {
            var side = player == 0 ? "top" : "bottom";
            htmlWriter.AddAttribute(HtmlTextWriterAttribute.Class, "round" + round + "-" + side + "wrap");
            htmlWriter.RenderBeginTag(HtmlTextWriterTag.Div);
            if (match.IsNotNull())
            {
                htmlWriter.AddAttribute(HtmlTextWriterAttribute.Class, "round" + round + "-" + side);
                htmlWriter.RenderBeginTag(HtmlTextWriterTag.Div);
                RenderPlayer(htmlWriter, match, side == "top" ? match.Player1 : match.Player2);
                RenderScores(htmlWriter, match, player);
                htmlWriter.RenderEndTag();
            }

            WriteRound(htmlWriter, round - 1, minRound, map);

            htmlWriter.RenderEndTag();
        }
    private static IEnumerable<UpdatePlayerPositionInfo> GetUpdatePlayerPositionInfos(CompetitionPosition[] qualifyingPlayersPositions, MatchHeaderInfo[] orderedMatches)
    {
        var matchIndex = 0;
        var positionIndex = 0;
        var results =  qualifyingPlayersPositions.Select(position => {
            var result = default(UpdatePlayerPositionInfo);
            if (position.PlayerId.HasValue)
            {
                result = new UpdatePlayerPositionInfo {
                    PlayerId = position.PlayerId.Value,
                    MatchId = orderedMatches[matchIndex].Id,
                    Position = positionIndex % 2
                };
            }
            positionIndex++;
            if ((positionIndex % 2) == 0)
            {
                matchIndex++;
            }
            return result;
        });

        return results;
    }
        private IEnumerable<MatchHeaderInfo> CreateSectionMatches(int playersCount, CompetitionSection section, int? qualifyingToNextSection = default(int?))
        {
            var actualPlayersCount = playersCount - qualifyingToNextSection.GetValueOrDefault();
            var rounds = (int)Math.Log((playersCount), 2);
            var actualRounds = rounds - (qualifyingToNextSection.GetValueOrDefault() > 0 ? (int)Math.Log(qualifyingToNextSection.GetValueOrDefault(), 2) : 0);
            var matches = new List<MatchHeaderInfo>(playersCount);

            for (int i = 0; i < actualPlayersCount; i++)
            {
                var match = new MatchHeaderInfo();
                match.Section = section;
                match.Position = i;
                match.Round = rounds - Math.Max(0, (int)Math.Log((playersCount - (i + 1)), 2));
                match.IsFinal = (match.Round == actualRounds);// && ((actualRounds == 1) || (i < playersCount - 1));
                if (section == CompetitionSection.Final && match.Round == rounds - 1)
                {
                    match.IsSemiFinal = true;
                }
                match.Status = MatchStatus.Created;
                matches.Add(match);
            }
            var matchesByRound = matches.GroupBy(m => m.Round).ToArray();
            foreach (var roundMatches in matchesByRound)
            {
                var index = 0;
                foreach (var match in roundMatches)
                {
                    match.RoundRelativePosition = index++;
                }
            }
            return matches;
        }
        private void SaveSchedule(MatchHeaderInfo[] matches, CompetitionPlayer[] players, string schedulePath)
        {
            var playersMap = new Dictionary<int, int>();
            var index = 1;
            foreach (var player in players)
            {
                playersMap[player.Id] = index++;
            }

            var items = new List<MatchScheduleInfo>();
            index = 1;
            foreach (var match in matches)
            {
                var matchSchedule = new MatchScheduleInfo();
                matchSchedule.Id = "M" + index++;
                if (match.Player1 != null)
                {
                    matchSchedule.Player1 = playersMap[match.Player1.Id];
                }
                else if (match.Player1 == null || match.Player1Code == "BYE")
                {
                    matchSchedule.Player1 = players.Length+1;
                }
                if (match.Player2 != null)
                {
                    matchSchedule.Player2 = playersMap[match.Player2.Id];
                }
                else if (match.Player2 == null || match.Player2Code == "BYE")
                {
                    matchSchedule.Player2 = players.Length+1;
                }

                if (match.Winner != MatchWinner.None)
                {
                    matchSchedule.Winner = (int) match.Winner;
                }

                matchSchedule.Player1Points = 0;
                matchSchedule.Player2Points = 0;
                matchSchedule.SetScores = match.SetScores;
                //matchSchedule.SetScores = new[]
                //                              {
                //                                  new SetScore()
                //                                      {
                //                                          Player1Points = 7,
                //                                          Player2Points = 5,
                //                                      }, 
                //                                  new SetScore()
                //                                      {
                //                                          Player1Points = 2,
                //                                          Player2Points = 6,
                //                                      }, 
                //                                  new SetScore()
                //                                      {
                //                                          Player1Points = 0,
                //                                          Player2Points = 6,
                //                                      }, 
                //                              };
                items.Add(matchSchedule);
            }

            MatchScheduleInfo.Write(items.ToArray(), schedulePath);
        }
 private static void RenderPlayer(HtmlTextWriter htmlWriter, MatchHeaderInfo match, MatchPlayer player)
 {
     htmlWriter.AddAttribute(HtmlTextWriterAttribute.Class, "player");
     htmlWriter.RenderBeginTag(HtmlTextWriterTag.Div);
     if (player != null)
     {
         htmlWriter.Write(player.LocalFirstName);
         if (player.LocalLastName.NotNullOrEmpty())
         {
             htmlWriter.Write(" , ");
             htmlWriter.Write(player.LocalLastName);
         }
     }
     else
     {
         htmlWriter.Write(match.Status == MatchStatus.Completed ? "BYE" : "&nbsp;");
     }
     htmlWriter.RenderEndTag();
 }