using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Pf2e.Database.Model.Base.Source;
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
///
/// Класс коллекции книг, содержащих правила.
/// Реализует шаблон Singleton.
///
public class RuleTocCollection
{
///
/// Список книг, содержащих правила.
///
public List Books { get; } = [];
///
/// Поиск книги по числовому идентификатору.
///
public RuleTocBook this[int id] =>
Books.FirstOrDefault(i => i.SourceId == id) ?? throw new($"Book with id {id} not found");
///
/// Поиск книги по CLR-представлению источника.
///
public RuleTocBook this[Source source]
{
get
{
RuleTocBook? result = Books.FirstOrDefault(i => i.SourceId == source.Id);
if (result is not null)
{
return result;
}
result = new(source);
Books.Add(result);
return result;
}
}
///
/// Поиск книги по имени.
///
public RuleTocBook? FindName(string name)
{
foreach (RuleTocBook book in Books)
{
if (book.IsNameExists(name))
{
return book;
}
}
return null;
}
///
/// Поиск правила по идентификатору.
///
public RuleTocItem? FindEntityId(int id)
{
foreach (RuleTocBook book in Books)
{
RuleTocItem? result = book.GetByEntityId(id);
if (result is not null)
{
return result;
}
}
return null;
}
///
/// Возвращает строковое представление коллекции в файле YAML.
///
public override string ToString()
{
return string.Join("\n", Books.Select(book => book.ToString()).ToList());
}
///
/// Сохраняет коллекцию в файле YAML.
///
public void SaveFile()
{
string fileName =
$"rules-toc.{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds()}.debug.yaml";
using FileStream fileStream = File.Create(fileName);
using StreamWriter writer = new(fileStream);
writer.Write(ToString());
}
///
/// Экземпляр класса .
///
public static RuleTocCollection Instance { get; } = new();
}
///
/// Класс представляет собой книгу, содержащую правила.
///
internal class RuleTocBook(Source source)
{
///
/// Идентификатор источника.
///
public int SourceId { get; } = source.Id;
///
/// Названия источника.
///
public string SourceName { get; } = source.Name;
///
/// Список дочерних правил.
///
///
/// Список дочерних элементов.
///
public List Children { get; } = [];
///
/// Находит элемент по хлебным крошкам.
///
/// Массив хлебных крошек, указывающих на путь в дереве.
/// или null если элемент не найден.
public RuleTocItem Get(string[] breadcrumbs)
{
RuleTocItem? node = null;
while (true)
{
List children = node?.Children ?? Children;
if (breadcrumbs.Length == 0)
{
return node!;
}
string root = breadcrumbs[0];
RuleTocItem? item = children.FirstOrDefault(i => i.Name == root);
if (item is null)
{
item = new(root, node);
children.Add(item);
}
breadcrumbs = breadcrumbs[1..];
node = item;
}
}
///
/// Проверяет, существует ли имя в текущей книге или дочерних элементах.
///
/// Имя для проверки.
/// Начальный элемент для поиска.
/// true если имя.
public bool IsNameExists(string name, RuleTocItem? node = null)
{
foreach (RuleTocItem item in node?.Children ?? Children)
{
if (item.Name == name || IsNameExists(name, item))
{
return true;
}
}
return false;
}
///
/// Находит элемент по идентификатору сущности.
///
/// Идентификатор сущности.
/// Начальный узел для поиска.
/// или null если элемент не найден.
public RuleTocItem? GetByEntityId(int id, RuleTocItem? node = null)
{
if (node?.RuleId == id)
{
return node;
}
foreach (RuleTocItem item in node?.Children ?? Children)
{
RuleTocItem? result = GetByEntityId(id, item);
if (result is not null)
{
return result;
}
}
return null;
}
///
/// Возвращает строковое представление книги в файле YAML.
///
/// Строковое представление книги.
public override string ToString()
{
return $"\"{SourceName}\":\n"
+ string.Join(
"\n",
Children.Select(child => RuleTocItem.Indent(child.ToString())).ToList()
);
}
}
///
/// Класс представляет собой элемент дерева правил.
///
internal class RuleTocItem(string name, RuleTocItem? parent)
{
public string? Id { get; set; } = null;
///
/// Имя элемента.
///
public string Name { get; } = name;
///
/// Идентификатор правила.
///
public int? RuleId { get; set; } = null;
///
/// Указывает, что элемент обрабатывается.
///
public bool IsHandled { get; set; } = false;
///
/// Родительский элемент дерева.
///
public RuleTocItem? Parent { get; } = parent;
///
/// Порядок дочерних элементов.
///
public List? ChildrenOrder { get; set; } = null;
///
/// Коллекция дочерних элементов.
///
public List Children { get; } = [];
///
/// Предыдущий идентификатор.
///
public string? PreviousId { get; set; }
///
/// Следующий идентификатор.
///
public string? NextId { get; set; }
///
/// Идентификатор первого дочернего элемента.
///
public string? FirstChildId { get; set; }
///
/// Идентификатор последнего дочернего элемента.
///
public string? LastChildId { get; set; }
///
/// Возвращает строковое представление элемента содержания в файле YAML.
///
/// Строковое представление элемента содержания.
public override string ToString()
{
List rows =
[
$"{Name}:",
$"{Tab}aonprd: {Id ?? "null"}",
$"{Tab}entity: {RuleId?.ToString() ?? "null"}",
];
if (Children.Count == 0)
{
// rows.Add($"{TAB}children: None");
return string.Join("\n", rows);
}
rows.Add($"{Tab}children:");
foreach (RuleTocItem child in Children)
{
rows.Add(child.Indent(2));
}
return string.Join("\n", rows);
}
///
/// Увеличение отступа строкового представления элемента содержания в файле YAML.
///
/// Количество отступов.
/// Строковое представление элемента содержания с отступом.
///
public string Indent(int amount = 1)
{
string result = ToString();
for (int i = 0; i < amount; i++)
{
result = Indent(result);
}
return result;
}
///
/// Увеличение отступа строки.
///
/// Входная строка.
/// Строка с отступом.
///
public static string Indent(string str)
{
return Tab + str.Replace("\n", $"\n{Tab}");
}
///
/// Строка отступа строки.
///
///
///
public const string Tab = " ";
}