public SoccerSimulationResult Simulate(SoccerSimulationData data)
        {
            var result = new SoccerSimulationResult();
            var context = new SimulationContext(data, Settings);
            foreach (var league in data.Leagues)
            {
                foreach (var gameweek in league.Gameweeks)
                {
                    foreach (var fixture in gameweek.Fixtures)
                    {
                        if (Settings.CalculateOddsWhenSimulating)
                            fixture.Odds = CalculateOdds(fixture);
                    }

                    if (gameweek.Ended)
                    {
                        context.LastPlayedGameweek = gameweek;
                    }

                    var temp = new List<SoccerSimulationPlayerResult>();
                    var players = gameweek.GetPlayers();
                    foreach (var player in players)
                    {
                        if (Settings.FilterUnavailablePlayers)
                        {
                            if (player.Fantasy.Unavailable)
                                continue;
                        }

                        var res = AnalysePlayerResult(player, gameweek, context);
                        temp.Add(res);
                    }

                    var top = new List<SoccerSimulationPlayerResult>();
                    var recommended = temp.Where(x => x.RecommendationPoints > 0)
                                  .OrderBy(x => (int) x.Player.Fantasy.Position)
                                  .ThenByDescending(x => x.RecommendationPoints)
                                  .ThenByDescending(x => x.EstimatedPoints)
                                  .ToList();
                    var groups = recommended.GroupBy(x => x.Player.Fantasy.Position);
                    foreach (var group in groups)
                    {
                        var topForPosition = group.ToList();
                        if (Settings.TopRecommendationsPerPosition > 0)
                            topForPosition = topForPosition.Take(Settings.TopRecommendationsPerPosition).ToList();
                        top.AddRange(topForPosition);

                        // todo: if many with same recommendation points, then set a "uncertainty level" on player?
                    }
                    result.PlayerResults.Add(gameweek, top);

                    // todo: if players are recommended for several gameweeks (in a row), then recommend them even more
                }
            }
            return result;
        }
        public async Task<SoccerSimulationData> GenerateApplyTo(SoccerSimulationData data)
        {
            var api = new FantasyPremierLeagueApi.Api.FantasyPremierLeagueApi(Username, Password, Logger);
            var mySquad = api.GetMySquad();
            var clubSeasonPerformances = api.GetClubSeasonPerformances();
            var remainingBudget = api.GetRemainingBudget();
            var players = api.GetAllPlayers().ToList();

            // todo: Convert classes, and append to data
            throw new NotImplementedException();

            return data;
        }
 internal SimulationContext(SoccerSimulationData data, ISoccerSimulatorSettings settings)
 {
     Settings = settings;
     _data = data;
 }
        public async Task<SoccerSimulationData> GenerateApplyTo(SoccerSimulationData data)
        {
            try
            {
                var openFootball = new OpenFootballDB();
                _ukClubs = new List<Team>();
                try
                {
                    var eng = await openFootball.GetEnglishClubs();
                    var eng2 = await openFootball.GetEnglishClubs2();
                    var wal = await openFootball.GetWelshClubs();

                    _ukClubs.AddRange(eng.Where(x => _ukClubs.All(y => !y.MatchName(x.Name))));
                    _ukClubs.AddRange(eng2.Where(x => _ukClubs.All(y => !y.MatchName(x.Name))));
                    _ukClubs.AddRange(wal.Where(x => _ukClubs.All(y => !y.MatchName(x.Name))));
                }
                catch (Exception ex)
                {
                    
                }



                var macros = new Dictionary<string, Func<string, string, object>>();
                macros["now"]       = (macro, format) => DateTime.UtcNow.ToString(format);
                macros["now-utc"]   = (macro, format) => DateTime.UtcNow.ToString(format);
                macros["now-local"] = (macro, format) => DateTime.Now.ToString(format);
                

                var bootstrapFilename               = _macroResolver.Resolve(BootstrapFilename, macros);
                var bootstrapStaticFilename         = _macroResolver.Resolve(BootstrapStaticFilename, macros);
                var elementsFilename                = _macroResolver.Resolve(ElementsFilename, macros);
                var elementTypesFilename            = _macroResolver.Resolve(ElementTypesFilename, macros);
                var regionsFilename                 = _macroResolver.Resolve(RegionsFilename, macros);
                var teamsFilename                   = _macroResolver.Resolve(TeamsFilename, macros);
                var eventsFilename                  = _macroResolver.Resolve(EventsFilename, macros);
                var fixturesFilename                = _macroResolver.Resolve(FixturesFilename, macros);
                var openFootballFixturesFilename    = _macroResolver.Resolve(OpenFootballFixturesFilename, macros);
                
                JToken bootstrapJson,
                       bootstrapStaticJson,
                       elementsJson,
                       elementTypesJson,
                       regionsJson,
                       teamsJson,
                       eventsJson,
                       fixturesJson,
                       openFootballFixturesJson;
                if (FetchNewData)
                {
                    bootstrapJson               = await GetJTokenFromAPI(GetBootstrapJsonUri);
                    bootstrapStaticJson         = await GetJTokenFromAPI(GetBootstrapStaticJsonUri);
                    elementsJson                = await GetJTokenFromAPI(GetElementsJsonUri);
                    elementTypesJson            = await GetJTokenFromAPI(GetElementTypesJsonUri);
                    regionsJson                 = await GetJTokenFromAPI(GetRegionsJsonUri);
                    teamsJson                   = await GetJTokenFromAPI(GetTeamsJsonUri);
                    eventsJson                  = await GetJTokenFromAPI(GetEventsJsonUri);
                    fixturesJson                = await GetJTokenFromAPI(GetFixturesJsonUri);
                    openFootballFixturesJson    = await GetOpenFootballFixturesFromWebsite();

                    var s1 = await SaveJTokenToTextFile(bootstrapJson,              bootstrapFilename);
                    var s2 = await SaveJTokenToTextFile(bootstrapStaticJson,        bootstrapStaticFilename);
                    var s3 = await SaveJTokenToTextFile(elementsJson,               elementsFilename);
                    var s4 = await SaveJTokenToTextFile(elementTypesJson,           elementTypesFilename);
                    var s5 = await SaveJTokenToTextFile(regionsJson,                regionsFilename);
                    var s6 = await SaveJTokenToTextFile(teamsJson,                  teamsFilename);
                    var s7 = await SaveJTokenToTextFile(eventsJson,                 eventsFilename);
                    var s8 = await SaveJTokenToTextFile(fixturesJson,               fixturesFilename);
                    var s9 = await SaveJTokenToTextFile(openFootballFixturesJson,   openFootballFixturesFilename);
                    var success = s1 && s2 && s3 && s4 && s5 && s6 && s7 && s8 && s9;
                }
                else
                {
                    bootstrapJson               = await LoadJTokenFromTextFile(bootstrapFilename);
                    bootstrapStaticJson         = await LoadJTokenFromTextFile(bootstrapStaticFilename);
                    elementsJson                = await LoadJTokenFromTextFile(elementsFilename);
                    elementTypesJson            = await LoadJTokenFromTextFile(elementTypesFilename);
                    regionsJson                 = await LoadJTokenFromTextFile(regionsFilename);
                    teamsJson                   = await LoadJTokenFromTextFile(teamsFilename);
                    eventsJson                  = await LoadJTokenFromTextFile(eventsFilename);
                    fixturesJson                = await LoadJTokenFromTextFile(fixturesFilename);
                    openFootballFixturesJson    = await LoadJTokenFromTextFile(openFootballFixturesFilename);
                }



                var leagueDataJson = (JObject) bootstrapStaticJson;
                var fixturesDataJson = (JObject) openFootballFixturesJson;

                var teams = new List<Team>();
                var premierLeague = GenerateLeague(leagueDataJson, fixturesDataJson, ref teams);


                // todo: FA Cup
                //var faCup = GenerateLeague(teamsAndPlayerJson, fixturesJson, ref teams);
                //faCup.ID = "FACUP";
                //faCup.Name = "FA Cup 16/17";


                // todo: Champions League


                // todo: include in simulation: players playing in multiple leagues => tired, playtime, etc.


                data.Teams = (data.Teams ?? new Team[0]).Concat(teams).ToArray();
                data.Leagues = data.Leagues.Append(premierLeague);
                //data.Leagues = data.Leagues.Append(faCup);
                return data;
            }
            catch (Exception ex)
            {
                throw;
            }
        }
 public async Task<SoccerSimulationData> Generate()
 {
     var data = new SoccerSimulationData();
     data = await GenerateApplyTo(data);
     return data;
 }
        public async Task<SoccerSimulationData> Generate()
        {
            var league = new League
            {
                Name = "Sample League",
                Year = DateTime.Now.Year,
            };

            #region Players

            var teams = new List<Team>
            {
                new Team
                {
                    ID = "MCI",
                    Name = "Manchester City",
                    Rating = (Rating) 9,
                    Players = new List<Player>
                    {
                        new Player
                        {
                            ID = "SILVA",
                            DisplayName = "David Silva",
                            Rating = (Rating) 8,
                            CurrentPrice = 9.0,
                            Position = PlayerPosition.Midfielder,
                        },

                        new Player
                        {
                            ID = "KOMPANY",
                            DisplayName = "Vincent Kompany",
                            Rating = (Rating) 7,
                            CurrentPrice = 7.0,
                            Position = PlayerPosition.Defender,
                        },
                    }.ToArray(),
                },


                new Team
                {
                    ID = "CHE",
                    Name = "Chelsea",
                    Rating = (Rating) 9,
                    Players = new List<Player>
                    {
                        new Player
                        {
                            ID = "HAZARD",
                            DisplayName = "Eden Hazard",
                            Rating = (Rating) 9,
                            OriginalPrice = 11.0,
                            CurrentPrice = 11.0,
                            Position = PlayerPosition.Midfielder,
                        },

                    }.ToArray(),
                },


                new Team
                {
                    ID = "LIV",
                    Name = "Liverpool",
                    Rating = (Rating) 8,
                    Players = new List<Player>
                    {
                        new Player
                        {
                            ID = "MIGNOLET",
                            DisplayName = "Simon Mignolet",
                            Rating = (Rating) 7,
                            OriginalPrice = 5.0,
                            CurrentPrice = 5.0,
                            Position = PlayerPosition.Goalkeeper,
                        },

                        new Player
                        {
                            ID = "HENDERSON",
                            DisplayName = "Jordan Henderson",
                            Rating = (Rating) 7,
                            OriginalPrice = 7.0,
                            CurrentPrice = 7.0,
                            Position = PlayerPosition.Midfielder,
                        },

                        new Player
                        {
                            ID = "COUTINHO",
                            DisplayName = "Philipe Couthinho",
                            Rating = (Rating) 8,
                            OriginalPrice = 8.5,
                            CurrentPrice = 8.5,
                            Position = PlayerPosition.Midfielder,
                        },

                    }.ToArray(),
                },


                new Team
                {
                    ID = "BOU",
                    Name = "AFC Bournemouth",
                    Rating = (Rating) 4,
                    Players = new List<Player>
                    {
                        new Player
                        {
                            ID = "RICHE",
                            DisplayName = "Matt Richie",
                            Rating = (Rating) 7,
                            OriginalPrice = 5.0,
                            CurrentPrice = 5.0,
                            Position = PlayerPosition.Midfielder,
                        },

                        new Player
                        {
                            ID = "WILSON",
                            DisplayName = "Calum Wilson",
                            Rating = (Rating) 6,
                            OriginalPrice = 5.5,
                            CurrentPrice = 5.5,
                            Position = PlayerPosition.Forward,
                        },

                    }.ToArray(),
                },

            }.ToArray();


            foreach (var team in teams)
            {
                foreach (var player in team.Players)
                {
                    player.Team = team;
                }
            }

            var leagueTeams = teams.Select(x => new LeagueTeam(league, x)).ToList();

            #endregion
            

            #region Gameweeks

            var gameweeks = new List<Gameweek>
            {
                new Gameweek(league)
                {
                    Number = 1,
                    Fixtures = new List<Fixture>
                    {
                        new Fixture
                        {
                            HomeTeam = leagueTeams.Single(x => x.Team.ID == "MCI"),
                            AwayTeam = leagueTeams.Single(x => x.Team.ID == "CHE"),
                            Statistics = new FixtureStatistics
                            {
                                GameFinished = true,
                                PlayedMinutes = 90,
                                Score = new FixtureScore
                                {
                                    GoalsForHomeTeam = 2,
                                    GoalsForAwayTeam = 2,
                                },
                            },
                        },

                        new Fixture
                        {
                            HomeTeam = leagueTeams.Single(x => x.Team.ID == "LIV"),
                            AwayTeam = leagueTeams.Single(x => x.Team.ID == "BOU"),
                            Statistics = new FixtureStatistics
                            {
                                GameFinished = false,
                                PlayedMinutes = 74,
                                Score = new FixtureScore
                                {
                                    GoalsForHomeTeam = 3,
                                    GoalsForAwayTeam = 0,
                                },
                            },
                        },

                    }.ToArray(),
                },

                new Gameweek(league)
                {
                    Number = 2,
                    Fixtures = new List<Fixture>
                    {
                        new Fixture
                        {
                            HomeTeam = leagueTeams.Single(x => x.Team.ID == "BOU"),
                            AwayTeam = leagueTeams.Single(x => x.Team.ID == "MCI"),
                        },

                        new Fixture
                        {
                            HomeTeam = leagueTeams.Single(x => x.Team.ID == "CHE"),
                            AwayTeam = leagueTeams.Single(x => x.Team.ID == "LIV"),
                        },
                    }.ToArray(),
                },

                new Gameweek(league)
                {
                    Number = 3,
                    Fixtures = new List<Fixture>
                    {
                        new Fixture
                        {
                            HomeTeam = leagueTeams.Single(x => x.Team.ID == "LIV"),
                            AwayTeam = leagueTeams.Single(x => x.Team.ID == "MCI"),
                        },

                        new Fixture
                        {
                            HomeTeam = leagueTeams.Single(x => x.Team.ID == "BOU"),
                            AwayTeam = leagueTeams.Single(x => x.Team.ID == "CHE"),
                        },
                    }.ToArray(),
                },

            }.ToArray();


            foreach (var week in gameweeks)
            {
                foreach (var fixture in week.Fixtures)
                {
                    fixture.Gameweek = week;
                }
            }

            #endregion


            league.Teams = leagueTeams.ToArray();
            league.Gameweeks = gameweeks;

            var simulationData = new SoccerSimulationData();
            simulationData.Leagues = simulationData.Leagues.Append(league);
            //simulationData.Teams = teams;
            //simulationData.Gameweeks = gameweeks;
            return simulationData;
        }