using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Questionable.Model; using Questionable.Model.Questing; namespace Questionable.Validation; internal sealed class QuestValidator { private readonly IReadOnlyList _validators; private readonly ILogger _logger; private List _validationIssues = new List(); public IReadOnlyList Issues => _validationIssues; public int IssueCount => _validationIssues.Count; public int ErrorCount => _validationIssues.Count((ValidationIssue x) => x.Severity == EIssueSeverity.Error); public QuestValidator(IEnumerable validators, ILogger logger) { _validators = validators.ToList(); _logger = logger; _logger.LogInformation("Validators: {Validators}", string.Join(", ", _validators.Select((IQuestValidator x) => x.GetType().Name))); } public void Reset() { foreach (IQuestValidator validator in _validators) { validator.Reset(); } _validationIssues.Clear(); } public void AddValidationIssue(ValidationIssue issue) { _validationIssues.Add(issue); } public void Validate(IEnumerable quests) { Task.Factory.StartNew(delegate { try { List first = _validationIssues.ToList(); _validationIssues.Clear(); List list = new List(); Dictionary> dictionary = new Dictionary>(); foreach (Quest quest in quests) { foreach (IQuestValidator validator in _validators) { foreach (ValidationIssue item in validator.Validate(quest)) { if (item.Type == EIssueType.QuestDisabled && quest.Info.AlliedSociety != EAlliedSociety.None) { if (!dictionary.TryGetValue(quest.Info.AlliedSociety, out var value)) { value = new List(); dictionary[quest.Info.AlliedSociety] = value; } value.Add(quest.Id); } else { list.Add(item); } } } } List disabledQuests = (from x in list where x.Type == EIssueType.QuestDisabled select x.ElementId).ToList(); _validationIssues = (from x in first.Concat(list.Where((ValidationIssue x) => !disabledQuests.Contains(x.ElementId) || x.Type == EIssueType.QuestDisabled)).Concat(DisabledTribesAsIssues(dictionary)) orderby x.ElementId, x.Sequence, x.Step, x.Description select x).ToList(); } catch (Exception exception) { _logger.LogError(exception, "Unable to validate quests"); } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } public List GetIssues(ElementId elementId) { return _validationIssues.Where((ValidationIssue x) => x.ElementId == elementId).ToList(); } private static IEnumerable DisabledTribesAsIssues(Dictionary> disabledTribeQuests) { return disabledTribeQuests.OrderBy>, EAlliedSociety>((KeyValuePair> x) => x.Key).Select(delegate(KeyValuePair> x) { string value = ((x.Value.Count > 0) ? string.Join(", ", x.Value.Select((ElementId id) => id.ToString())) : "(none)"); return new ValidationIssue { ElementId = null, Sequence = null, Step = null, AlliedSociety = x.Key, Type = EIssueType.QuestDisabled, Severity = EIssueSeverity.None, Description = $"{x.Value.Count} disabled quest(s): {value}" }; }); } }