using System; using System.Collections.Generic; using System.Linq; using EDJournal; namespace NonaBGS.BGS { public class Report { private List objectives = new List(); public delegate void OnLogDelegate(string log); public event OnLogDelegate OnLog; public List Objectives { get { return objectives; } set { objectives = value; } } public bool AddObjective(Objective objective) { var found = objectives.Find(x => x.CompareTo(objective) == 0); bool added = false; if (found == null) { objectives.Add(objective); added = true; } return added; } private bool IsRelevant(Entry e) { return e.Is(Events.MissionCompleted) || e.Is(Events.Docked) || e.Is(Events.FSDJump) || e.Is(Events.MultiSellExplorationData) || e.Is(Events.SellMicroResources) || e.Is(Events.RedeemVoucher) || e.Is(Events.FactionKillBond) || e.Is(Events.MarketSell) ; } public void Scan(PlayerJournal journal, DateTime start, DateTime end) { var entries = from file in journal.Files where file.NormalisedTimestamp >= start && file.NormalisedTimestamp <= end select file.Entries ; var relevant = from log in entries.SelectMany(array => array) where IsRelevant(log) select log ; string current_system = null; string current_station = null; string controlling_faction = null; objectives.ForEach(x => x.Clear()); foreach (var e in relevant) { LogEntry entry = null; bool collate = false; if (e.Is(Events.Docked)) { /* gleem the current station from this message */ current_station = (e as DockedEntry).StationName; } else if (e.Is(Events.FSDJump)) { /* Gleem current system and controlling faction from this message. */ current_system = (e as FSDJumpEntry).StarSystem; controlling_faction = (e as FSDJumpEntry).SystemFaction; } else if (e.Is(Events.MissionCompleted)) { var completed = e as MissionCompletedEntry; entry = new MissionCompleted(completed, current_system, current_station); if (completed.HumanReadableNameWasGenerated) { /* If the human readable name was generated, we send a log message. Because the * generated names all sort of suck, we should have more human readable names in * in the lookup dictionary. */ OnLog?.Invoke("Human readable name for mission \"" + completed.Name + "\" was generated, please report this."); } } else if (e.Is(Events.MultiSellExplorationData)) { /* For multi-sell-exploraton-data only the controlling faction of the station sold to matters. */ entry = new Cartographics(e as MultiSellExplorationDataEntry, current_system, current_station); entry.Faction = controlling_faction; } else if (e.Is(Events.RedeemVoucher)) { /* Same for selling combat vouchers. Only the current controlling faction matters here. */ entry = new Vouchers(); entry.Entries.Add(e); entry.System = current_system; entry.Station = current_station; entry.Faction = (e as RedeemVoucherEntry).Factions.FirstOrDefault() ?? ""; entry.ControllingFaction = controlling_faction; collate = true; } else if (e.Is(Events.SellMicroResources)) { entry = new SellMicroResources() { Faction = controlling_faction, Station = current_station, System = current_system }; entry.Entries.Add(e); } else if (e.Is(Events.MarketSell)) { entry = new SellCargo() { Faction = controlling_faction, Station = current_station, System = current_system }; entry.Entries.Add(e); } if (entry == null) { continue; } /* Find all objectives that generally match. */ var matches = objectives .Where(x => x.Matches(entry) > 0) .OrderBy(x => x.Matches(entry)) ; if (matches == null || matches.Count() <= 0) { continue; } /* Then select the one that matches the most. */ var objective = matches .OrderBy(x => x.Matches(entry)) .Reverse() .First() ; if (objective == null) { continue; } LogEntry existing = null; existing = objective.LogEntries.Find(x => { try { return x.CompareTo(entry) == 0; } catch (NotImplementedException) { return false; } }); if (collate && existing != null) { existing.Entries.Add(e); } else if (!collate || existing == null) { objective.LogEntries.Add(entry); } } } public void Scan(PlayerJournal journal) { Scan(journal, DateTime.Now, DateTime.Now); } } }