public ProcessRequestResponse Get(FetchProcessRequest request)
        {
            var processingRequest = new ProcessingRequest();

            foreach (Season season in ResolveService<SeasonService>().GetAll(new FetchSeasons { NotFinal = true }))
            {
                var seasonRequest = new SeasonProcessRequest
                {
                    SeasonId = season.Id,
                    CrawlVersion = season.CrawlVersion
                };

                foreach (var round in season.RoundInformation.RoundsToProcess.Values)
                {
                    var roundRequest = new RoundProcessRequest {Round = round};

                    // Crawlers that have already played a game
                    var finishedCrawlers =
                        Db.SqlColumn<int>(
                            Db.From<Game>()
                                .Select(g => g.CrawlerId)
                                .Where(g => g.CompletedDate >= round.Start)
                                .And(g => g.CompletedDate <= round.End)
                                .And(g => g.SeasonId == season.Id));

                    // Crawlers that need a game (select crawlers excluding the completed crawlers)
                    var gamesNeeded = Db.Select<TestMe>(new JoinSqlBuilder<Participant, Participant>()
                        .Join<Crawler, Participant>(c => c.Id, p => p.CrawlerId)
                        .Join<Participant, Season>(p => p.SeasonId, s => s.Id)
                        .Join<Server, Crawler>(s => s.Id, c => c.ServerId)
                        .Select<Participant>(p => new {ParticipantId = p.Id, p.CrawlerId})
                        .Select<Server>(s => new {s.MorgueUrl, s.UtcOffset})
                        .Select<Crawler>(c => new {c.UserName})
                        .Select<Season>(s => new {s.CrawlVersion, SeasonStart = s.Start})
                        .Where<Participant>(p => p.SeasonId == season.Id) // Specific season
                        .And<Participant>(p => !Sql.In(p.CrawlerId, finishedCrawlers)) // Not played a game
                        .And<Crawler>(c => !c.Banned).ToSql());

                    // Create lookup requests
                    gamesNeeded.ForEach(r => roundRequest.GameFetchRequests.Add(new GameFetchRequest
                    {
                        CrawlerId = r.CrawlerId,
                        ParticipantId = r.ParticipantId,
                        MorgueUrl = new Server {MorgueUrl = r.MorgueUrl}.PlayerMorgueUrl(r.CrawlVersion, r.UserName),
                        MorguesSince = r.LastProcessed == DateTime.MinValue ? r.SeasonStart : r.LastProcessed,
                        UtcOffset = r.UtcOffset,
                    }));

                    seasonRequest.RoundProcessRequests.Add(roundRequest);
                }

                processingRequest.SeasonProcessRequests.Add(seasonRequest);
            }

            return new ProcessRequestResponse {ProcessRequest = processingRequest};
        }
        public IList<MorgueFile> GetValidMorgues(RoundProcessRequest roundRequest, IMorgueValidator validator)
        {
            IDictionary<GameFetchRequest, ScraperResponse> moregueIndexes =
                GetMorgueIndexes(roundRequest.GameFetchRequests);

            List<MorgueFile> morgueFiles =
                GetMorgueFiles(moregueIndexes, roundRequest.Round);

            var validMorgueFiles = new List<MorgueFile>();

            foreach (GameFetchRequest gameRequest in roundRequest.GameFetchRequests)
            {
                var morgue =
                    GetFirstValidMorgueFile(morgueFiles.Where(m => m.ParticipantId == gameRequest.ParticipantId), validator);

                if (morgue != null)
                    validMorgueFiles.Add(morgue);
            }

            return validMorgueFiles;
        }