using System.Text; namespace RolemasterDb.ImportTool; public sealed class ImportArtifactPaths { private ImportArtifactPaths( string artifactsRootPath, string tableSlug, string directoryPath, string xmlPath, string ocrTsvPath, string fragmentsJsonPath, string parsedCellsJsonPath, string validationReportPath, string ocrPagesDirectoryPath, string pagesDirectoryPath, string cellsDirectoryPath) { ArtifactsRootPath = artifactsRootPath; TableSlug = tableSlug; DirectoryPath = directoryPath; XmlPath = xmlPath; OcrTsvPath = ocrTsvPath; FragmentsJsonPath = fragmentsJsonPath; ParsedCellsJsonPath = parsedCellsJsonPath; ValidationReportPath = validationReportPath; OcrPagesDirectoryPath = ocrPagesDirectoryPath; PagesDirectoryPath = pagesDirectoryPath; CellsDirectoryPath = cellsDirectoryPath; } public string ArtifactsRootPath { get; } public string TableSlug { get; } public string DirectoryPath { get; } public string XmlPath { get; } public string OcrTsvPath { get; } public string FragmentsJsonPath { get; } public string ParsedCellsJsonPath { get; } public string ValidationReportPath { get; } public string OcrPagesDirectoryPath { get; } public string PagesDirectoryPath { get; } public string CellsDirectoryPath { get; } public static ImportArtifactPaths Create(string artifactsRootPath, string tableSlug) { var directoryPath = Path.Combine(artifactsRootPath, tableSlug); var ocrPagesDirectoryPath = Path.Combine(directoryPath, "ocr-pages"); var pagesDirectoryPath = Path.Combine(directoryPath, "pages"); var cellsDirectoryPath = Path.Combine(directoryPath, "cells"); return new ImportArtifactPaths( artifactsRootPath, tableSlug, directoryPath, Path.Combine(directoryPath, "source.xml"), Path.Combine(directoryPath, "source.ocr.tsv"), Path.Combine(directoryPath, "fragments.json"), Path.Combine(directoryPath, "parsed-cells.json"), Path.Combine(directoryPath, "validation-report.json"), ocrPagesDirectoryPath, pagesDirectoryPath, cellsDirectoryPath); } public string GetSourceArtifactPath(string extractionMethod) => string.Equals(extractionMethod, "ocr", StringComparison.OrdinalIgnoreCase) ? OcrTsvPath : XmlPath; public string GetOcrPageImagePath(int pageNumber) => Path.Combine(OcrPagesDirectoryPath, $"page-{pageNumber:000}.png"); public string GetPageImagePath(int pageNumber) => Path.Combine(PagesDirectoryPath, $"page-{pageNumber:000}.png"); public string GetRelativeCellImagePath(string? groupKey, string columnKey, string rollBandLabel) => Path.Combine( TableSlug, "cells", $"{NormalizeFileSegment(groupKey ?? "none")}__{NormalizeFileSegment(columnKey)}__{NormalizeFileSegment(rollBandLabel)}.png") .Replace('\\', '/'); public string ResolveRelativePath(string relativePath) => Path.GetFullPath(Path.Combine(ArtifactsRootPath, relativePath.Replace('/', Path.DirectorySeparatorChar))); private static string NormalizeFileSegment(string value) { var builder = new StringBuilder(); foreach (var character in value.Trim().ToLowerInvariant()) { if (char.IsLetterOrDigit(character)) { builder.Append(character); continue; } if (character is '-' or '_') { builder.Append(character); continue; } if (character == '+') { builder.Append("plus"); continue; } builder.Append('_'); } var normalized = builder.ToString().Trim('_'); return string.IsNullOrWhiteSpace(normalized) ? "empty" : normalized; } }