using System;
using System.Collections.Generic;
namespace PKHeX.Core.Bulk;
///
/// Analyzes content within a for overall legality analysis.
///
public sealed class BulkAnalysis
{
public readonly IReadOnlyList AllData;
public readonly IReadOnlyList AllAnalysis;
public readonly ITrainerInfo Trainer;
public readonly List Parse = new();
public readonly Dictionary Trackers = new();
public readonly bool Valid;
public readonly IBulkAnalysisSettings Settings;
private readonly bool[] CloneFlags;
///
/// Checks if the entity at was previously marked as a clone of another index.
///
public bool GetIsClone(int entryIndex) => CloneFlags[entryIndex];
///
/// Marks the entity at as a clone of another index.
///
public bool SetIsClone(int entryIndex, bool value = true) => CloneFlags[entryIndex] = value;
public BulkAnalysis(SaveFile sav, IBulkAnalysisSettings settings)
{
Trainer = sav;
Settings = settings;
var list = new List(sav.BoxSlotCount + (sav.HasParty ? 6 : 0) + 5);
SlotInfoLoader.AddFromSaveFile(sav, list);
list.RemoveAll(IsEmptyData);
AllData = list;
AllAnalysis = GetIndividualAnalysis(list);
CloneFlags = new bool[AllData.Count];
ScanAll();
Valid = Parse.Count == 0 || Parse.TrueForAll(static z => z.Valid);
}
// Remove things that aren't actual stored data, or already flagged by legality checks.
private static bool IsEmptyData(SlotCache obj)
{
var pk = obj.Entity;
if ((uint)(pk.Species - 1) >= pk.MaxSpeciesID)
return true;
if (!pk.ChecksumValid)
return true;
return false;
}
///
/// Supported checkers that will be iterated through to check all entities.
///
public static readonly List Analyzers = new()
{
new StandardCloneChecker(),
new DuplicateTrainerChecker(),
new DuplicatePIDChecker(),
new DuplicateEncryptionChecker(),
new HandlerChecker(),
new DuplicateGiftChecker(),
};
private void ScanAll()
{
foreach (var analyzer in Analyzers)
analyzer.Analyze(this);
}
private static string GetSummary(SlotCache entry) => $"[{entry.Identify()}]";
///
/// Adds a new entry to the list.
///
public void AddLine(SlotCache first, SlotCache second, string msg, CheckIdentifier i, Severity s = Severity.Invalid)
{
var c = $"{msg}{Environment.NewLine}{GetSummary(first)}{Environment.NewLine}{GetSummary(second)}{Environment.NewLine}";
var chk = new CheckResult(s, i, c);
Parse.Add(chk);
}
///
/// Adds a new entry to the list.
///
public void AddLine(SlotCache first, string msg, CheckIdentifier i, Severity s = Severity.Invalid)
{
var c = $"{msg}{Environment.NewLine}{GetSummary(first)}{Environment.NewLine}";
var chk = new CheckResult(s, i, c);
Parse.Add(chk);
}
private static IReadOnlyList GetIndividualAnalysis(IReadOnlyList pkms)
{
var results = new LegalityAnalysis[pkms.Count];
for (int i = 0; i < pkms.Count; i++)
results[i] = Get(pkms[i]);
return results;
}
private static LegalityAnalysis Get(SlotCache cache) => new(cache.Entity, cache.SAV.Personal, cache.Source.Origin);
}