/// <summary>
 /// Parses from the given stream. On parsing failure, parsingFailureReason will be filled with the reason of the failure and the method will return null
 /// <see cref="ParsingFailureReason"/>
 /// </summary>
 /// <param name="operation">Operation object bound to the UI</param>
 /// <param name="evtcStream">The stream of the log</param>
 /// <param name="parsingFailureReason">The reason why the parsing failed, if applicable</param>
 /// <returns>the ParsedEvtcLog</returns>
 public ParsedEvtcLog ParseLog(ParserController operation, Stream evtcStream, out ParsingFailureReason parsingFailureReason)
 {
     parsingFailureReason = null;
     try
     {
         using (BinaryReader reader = CreateReader(evtcStream))
         {
             operation.UpdateProgressWithCancellationCheck("Reading Binary");
             operation.UpdateProgressWithCancellationCheck("Parsing fight data");
             ParseFightData(reader, operation);
             operation.UpdateProgressWithCancellationCheck("Parsing agent data");
             ParseAgentData(reader, operation);
             operation.UpdateProgressWithCancellationCheck("Parsing skill data");
             ParseSkillData(reader, operation);
             operation.UpdateProgressWithCancellationCheck("Parsing combat list");
             ParseCombatList(reader, operation);
             operation.UpdateProgressWithCancellationCheck("Linking agents to combat list");
             CompleteAgents();
             operation.UpdateProgressWithCancellationCheck("Preparing data for log generation");
             PreProcessEvtcData();
             operation.UpdateProgressWithCancellationCheck("Data parsed");
             return(new ParsedEvtcLog(_buildVersion, _fightData, _agentData, _skillData, _combatItems, _playerList, _logEndTime - _logStartTime, _parserSettings, operation));
         }
     }
     catch (Exception ex)
     {
         parsingFailureReason = new ParsingFailureReason(ex);
         return(null);
     }
 }
 //Main Parse method------------------------------------------------------------------------------------------------------------------------------------------------
 /// <summary>
 /// Parses the given log. On parsing failure, parsingFailureReason will be filled with the reason of the failure and the method will return null
 /// <see cref="ParsingFailureReason"/>
 /// </summary>
 /// <param name="operation">Operation object bound to the UI</param>
 /// <param name="evtc">The path to the log to parse</param>
 /// <param name="parsingFailureReason">The reason why the parsing failed, if applicable</param>
 /// <param name="multiThreadAccelerationForBuffs">Will preprocess buff simulation using multi threading </param>
 /// <returns>the ParsedEvtcLog</returns>
 public ParsedEvtcLog ParseLog(ParserController operation, FileInfo evtc, out ParsingFailureReason parsingFailureReason, bool multiThreadAccelerationForBuffs = false)
 {
     parsingFailureReason = null;
     try
     {
         if (!evtc.Exists)
         {
             throw new EvtcFileException("File " + evtc.FullName + " does not exist");
         }
         if (!ParserHelper.IsSupportedFormat(evtc.Name))
         {
             throw new EvtcFileException("Not EVTC");
         }
         ParsedEvtcLog evtcLog;
         using (var fs = new FileStream(evtc.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
         {
             if (ParserHelper.IsCompressedFormat(evtc.Name))
             {
                 using (var arch = new ZipArchive(fs, ZipArchiveMode.Read))
                 {
                     if (arch.Entries.Count != 1)
                     {
                         throw new EvtcFileException("Invalid Archive");
                     }
                     using (Stream data = arch.Entries[0].Open())
                     {
                         using (var ms = new MemoryStream())
                         {
                             data.CopyTo(ms);
                             ms.Position = 0;
                             evtcLog     = ParseLog(operation, ms, out parsingFailureReason, multiThreadAccelerationForBuffs);
                         };
                     }
                 }
             }
             else
             {
                 evtcLog = ParseLog(operation, fs, out parsingFailureReason, multiThreadAccelerationForBuffs);
             }
         }
         return(evtcLog);
     }
     catch (Exception ex)
     {
         parsingFailureReason = new ParsingFailureReason(ex);
         return(null);
     }
 }
        /// <summary>
        /// Parses from the given stream. On parsing failure, parsingFailureReason will be filled with the reason of the failure and the method will return null
        /// <see cref="ParsingFailureReason"/>
        /// </summary>
        /// <param name="operation">Operation object bound to the UI</param>
        /// <param name="evtcStream">The stream of the log</param>
        /// <param name="parsingFailureReason">The reason why the parsing failed, if applicable</param>
        /// <param name="multiThreadAccelerationForBuffs">Will preprocess buff simulation using multi threading </param>
        /// <returns>the ParsedEvtcLog</returns>
        public ParsedEvtcLog ParseLog(ParserController operation, Stream evtcStream, out ParsingFailureReason parsingFailureReason, bool multiThreadAccelerationForBuffs = false)
        {
            parsingFailureReason = null;
            try
            {
                using (BinaryReader reader = CreateReader(evtcStream))
                {
                    operation.UpdateProgressWithCancellationCheck("Reading Binary");
                    operation.UpdateProgressWithCancellationCheck("Parsing fight data");
                    ParseFightData(reader, operation);
                    operation.UpdateProgressWithCancellationCheck("Parsing agent data");
                    ParseAgentData(reader, operation);
                    operation.UpdateProgressWithCancellationCheck("Parsing skill data");
                    ParseSkillData(reader, operation);
                    operation.UpdateProgressWithCancellationCheck("Parsing combat list");
                    ParseCombatList(reader, operation);
                    operation.UpdateProgressWithCancellationCheck("Linking agents to combat list");
                    CompleteAgents(operation);
                    operation.UpdateProgressWithCancellationCheck("Preparing data for log generation");
                    PreProcessEvtcData(operation);
                    operation.UpdateProgressWithCancellationCheck("Data parsed");
                    var log = new ParsedEvtcLog(_evtcVersion, _fightData, _agentData, _skillData, _combatItems, _playerList, _enabledExtensions, _logEndTime - _logStartTime, _parserSettings, operation);
                    //
                    if (multiThreadAccelerationForBuffs)
                    {
                        IReadOnlyList <PhaseData> phases = log.FightData.GetPhases(log);
                        operation.UpdateProgressWithCancellationCheck("Multi threading");
                        var friendliesAndTargets = new List <AbstractSingleActor>(log.Friendlies);
                        friendliesAndTargets.AddRange(log.FightData.Logic.Targets);
                        var friendliesAndTargetsAndMobs = new List <AbstractSingleActor>(log.FightData.Logic.TrashMobs);
                        friendliesAndTargetsAndMobs.AddRange(friendliesAndTargets);
                        foreach (AbstractSingleActor actor in friendliesAndTargetsAndMobs)
                        {
                            // that part can't be // due to buff extensions
                            actor.GetTrackedBuffs(log);
                            actor.GetMinions(log);
                        }
                        Parallel.ForEach(friendliesAndTargets, actor => actor.GetStatus(log));

                        /*if (log.CombatData.HasMovementData)
                         * {
                         *  // init all positions
                         *  Parallel.ForEach(friendliesAndTargetsAndMobs, actor => actor.GetCombatReplayPolledPositions(log));
                         * }*/
                        Parallel.ForEach(friendliesAndTargetsAndMobs, actor => actor.GetBuffGraphs(log));
                        Parallel.ForEach(friendliesAndTargets, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffDistribution(log, phase.Start, phase.End);
                            }
                        });
                        Parallel.ForEach(friendliesAndTargets, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffPresence(log, phase.Start, phase.End);
                            }
                        });
                        //
                        //Parallel.ForEach(log.PlayerList, player => player.GetDamageModifierStats(log, null));
                        Parallel.ForEach(log.Friendlies, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffs(BuffEnum.Self, log, phase.Start, phase.End);
                            }
                        });
                        Parallel.ForEach(log.PlayerList, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffs(BuffEnum.Group, log, phase.Start, phase.End);
                            }
                        });
                        Parallel.ForEach(log.PlayerList, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffs(BuffEnum.OffGroup, log, phase.Start, phase.End);
                            }
                        });
                        Parallel.ForEach(log.PlayerList, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffs(BuffEnum.Squad, log, phase.Start, phase.End);
                            }
                        });
                        Parallel.ForEach(log.FightData.Logic.Targets, actor =>
                        {
                            foreach (PhaseData phase in phases)
                            {
                                actor.GetBuffs(BuffEnum.Self, log, phase.Start, phase.End);
                            }
                        });
                    }
                    //
                    return(log);
                }
            }
            catch (Exception ex)
            {
                parsingFailureReason = new ParsingFailureReason(ex);
                return(null);
            }
        }