EliteBGS/BGS/Report.cs

210 lines
8.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using EDJournal;
namespace EliteBGS.BGS {
public class Report {
private List<Objective> objectives = new List<Objective>();
public delegate void OnLogDelegate(string log);
public event OnLogDelegate OnLog;
public List<Objective> 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.MissionFailed) ||
e.Is(Events.MissionAccepted) ||
e.Is(Events.Docked) ||
e.Is(Events.FSDJump) ||
e.Is(Events.Location) ||
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
;
Dictionary<int, MissionAcceptedEntry> acceptedMissions = new Dictionary<int, MissionAcceptedEntry>();
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)) {
DockedEntry docked = e as DockedEntry;
/* gleem the current station from this message
*/
current_station = docked.StationName;
current_system = docked.StarSystem;
controlling_faction = docked.StationFaction;
} 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.Location)) {
/* Get current system, faction name and station from Location message
*/
LocationEntry location = e as LocationEntry;
current_system = location.StarSystem;
if (!string.IsNullOrEmpty(location.SystemFaction)) {
controlling_faction = location.SystemFaction;
}
if (!string.IsNullOrEmpty(location.StationName)) {
current_station = location.StationName;
}
} else if (e.Is(Events.MissionCompleted)) {
var completed = e as MissionCompletedEntry;
entry = new MissionCompleted(completed) {
System = current_system,
Station = 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.MissionAccepted)) {
MissionAcceptedEntry accepted = e as MissionAcceptedEntry;
acceptedMissions[accepted.MissionID] = accepted;
} else if (e.Is(Events.MissionFailed)) {
var failed = e as MissionFailedEntry;
var accepted = acceptedMissions[failed.MissionID];
if (accepted == null) {
OnLog?.Invoke("Mission failed that wasn't accepted, please adjust time frame.");
continue;
}
entry = new MissionFailed(accepted) { Failed = failed, System = current_system };
if (failed.HumanReadableName == null) {
OnLog?.Invoke("Human readable name for mission \"" +
failed.Name +
"\" was not recognised");
}
} 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))
;
Objective objective = null;
if (matches != null && matches.Count() > 0) {
/* Then select the one that matches the most.
*/
objective = matches
.OrderBy(x => x.Matches(entry))
.Reverse()
.First()
;
} else {
/* create a new objective if we don't have one */
objective = new Objective() {
Station = entry.Station,
Faction = entry.Faction,
System = entry.System,
};
objectives.Add(objective);
}
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);
}
}
}