public static Tuple <ReplayParseResult, Replay> ParseReplay(string fileName, bool deleteFile, ParseOptions parseOptions)
        {
            var replay = new Replay();

            try
            {
                // File in the version numbers for later use.
                MpqHeader.ParseHeader(replay, fileName);

                if (!parseOptions.IgnoreErrors && replay.ReplayBuild < 32455)
                {
                    return(new Tuple <ReplayParseResult, Replay>(ReplayParseResult.PreAlphaWipe, null));
                }

                using (var archive = new MpqArchive(fileName))
                    ParseReplayArchive(replay, archive, parseOptions);

                if (deleteFile)
                {
                    File.Delete(fileName);
                }

                return(ParseReplayResults(replay, parseOptions.IgnoreErrors, parseOptions.AllowPTR));
            }
            catch
            {
                return(new Tuple <ReplayParseResult, Replay>(ReplayParseResult.ParserException, new Replay {
                    ReplayBuild = replay.ReplayBuild
                }));
            }
        }
        private static void ParseReplayArchive(Replay replay, MpqArchive archive, ParseOptions parseOptions)
        {
            archive.AddListfileFilenames();

            // Replay Details
            ReplayDetails.Parse(replay, GetMpqFile(archive, ReplayDetails.FileName), parseOptions.IgnoreErrors);

            if (!parseOptions.IgnoreErrors)
            {
                if (replay.Players.Length != 10 || replay.Players.Count(i => i.IsWinner) != 5)
                {
                    // Filter out 'Try Me' games, any games without 10 players, and incomplete games
                    return;
                }
                else if (replay.Timestamp == DateTime.MinValue)
                {
                    // Uncommon issue when parsing replay.details
                    return;
                }
                else if (replay.Timestamp < new DateTime(2014, 10, 6, 0, 0, 0, DateTimeKind.Utc))
                {
                    // Technical Alpha replays
                    return;
                }
            }

            // Replay Init Data
            ReplayInitData.Parse(replay, GetMpqFile(archive, ReplayInitData.FileName));

            ReplayAttributeEvents.Parse(replay, GetMpqFile(archive, ReplayAttributeEvents.FileName));

            if (parseOptions.ShouldParseEvents)
            {
                replay.TrackerEvents = ReplayTrackerEvents.Parse(GetMpqFile(archive, ReplayTrackerEvents.FileName));
                try
                {
                    replay.GameEvents = ReplayGameEvents.Parse(GetMpqFile(archive, ReplayGameEvents.FileName), replay.ClientListByUserID, replay.ReplayBuild, replay.ReplayVersionMajor, parseOptions.ShouldParseMouseEvents);
                    replay.IsGameEventsParsedSuccessfully = true;
                }
                catch
                {
                    replay.GameEvents = new List <GameEvent>();
                }

                {
                    // Gather talent selections
                    var talentGameEventsDictionary = replay.GameEvents
                                                     .Where(i => i.eventType == GameEventType.CHeroTalentSelectedEvent)
                                                     .GroupBy(i => i.player)
                                                     .ToDictionary(
                        i => i.Key,
                        i => i.Select(j => new Talent {
                        TalentID = (int)j.data.unsignedInt.Value, TimeSpanSelected = j.TimeSpan
                    }).OrderBy(j => j.TimeSpanSelected).ToArray());

                    foreach (var player in talentGameEventsDictionary.Keys)
                    {
                        player.Talents = talentGameEventsDictionary[player];
                    }
                }
                // Replay Server Battlelobby
                if (archive.Any(i => i.Filename == ReplayServerBattlelobby.FileName))
                {
                    if (parseOptions.ShouldParseDetailedBattleLobby)
                    {
                        ReplayServerBattlelobby.Parse(replay, GetMpqFile(archive, ReplayServerBattlelobby.FileName));
                    }
                    else
                    {
                        ReplayServerBattlelobby.GetBattleTags(replay, GetMpqFile(archive, ReplayServerBattlelobby.FileName));
                    }
                }

                // Parse Unit Data using Tracker events
                if (parseOptions.ShouldParseUnits)
                {
                    Unit.ParseUnitData(replay);
                }

                // Parse Statistics
                if (parseOptions.ShouldParseStatistics)
                {
                    if (replay.ReplayBuild >= 40431)
                    {
                        try
                        {
                            Statistics.Parse(replay);
                            replay.IsStatisticsParsedSuccessfully = true;
                        }
                        catch
                        {
                            replay.IsGameEventsParsedSuccessfully = false;
                        }
                    }
                }

                // Replay Message Events
                if (parseOptions.ShouldParseMessageEvents)
                {
                    ReplayMessageEvents.Parse(replay, GetMpqFile(archive, ReplayMessageEvents.FileName));
                }

                // Replay Resumable Events
                // So far it doesn't look like this file has anything we would be interested in
                // ReplayResumableEvents.Parse(replay, GetMpqFile(archive, "replay.resumable.events"));
            }
        }