namespace RolemasterDb.ImportTool.Parsing; internal static class CriticalCellTextParser { internal static CriticalCellParseContent Parse(IReadOnlyList lines, AffixLegend affixLegend) { var validationErrors = new List(); var branchStartIndexes = FindBranchStartIndexes(lines); var baseLineCount = branchStartIndexes.Count == 0 ? lines.Count : branchStartIndexes[0]; var baseLines = lines.Take(baseLineCount).ToList(); var branches = new List(); var affixLegendSymbols = affixLegend.ClassificationSymbols; validationErrors.AddRange(ValidateSegmentCount(baseLines, affixLegendSymbols, "Base content")); for (var branchIndex = 0; branchIndex < branchStartIndexes.Count; branchIndex++) { var startIndex = branchStartIndexes[branchIndex]; var endIndex = branchIndex == branchStartIndexes.Count - 1 ? lines.Count : branchStartIndexes[branchIndex + 1]; branches.Add(ParseBranch( lines.Skip(startIndex).Take(endIndex - startIndex).ToList(), branchIndex + 1, affixLegend, validationErrors)); } var (rawCellText, descriptionText, rawAffixText) = BuildTextSections(baseLines, affixLegendSymbols); var effects = AffixEffectParser.Parse(rawAffixText, affixLegend); return new CriticalCellParseContent(baseLines, rawCellText, descriptionText, rawAffixText, effects, branches, validationErrors); } private static ParsedCriticalBranch ParseBranch( IReadOnlyList branchLines, int sortOrder, AffixLegend affixLegend, List validationErrors) { var firstLine = branchLines[0]; var separatorIndex = firstLine.IndexOf(':', StringComparison.Ordinal); var conditionText = CriticalTableParserSupport.CollapseWhitespace(firstLine[..separatorIndex]); var firstPayloadLine = CriticalTableParserSupport.CollapseWhitespace(firstLine[(separatorIndex + 1)..]); var payloadLines = new List(); if (!string.IsNullOrWhiteSpace(firstPayloadLine)) { payloadLines.Add(firstPayloadLine); } foreach (var continuationLine in branchLines.Skip(1)) { var normalized = CriticalTableParserSupport.CollapseWhitespace(continuationLine); if (!string.IsNullOrWhiteSpace(normalized)) { payloadLines.Add(normalized); } } var affixLegendSymbols = affixLegend.ClassificationSymbols; validationErrors.AddRange(ValidateSegmentCount(payloadLines, affixLegendSymbols, $"Branch '{conditionText}'")); var (_, descriptionText, rawAffixText) = BuildTextSections(payloadLines, affixLegendSymbols); var effects = AffixEffectParser.Parse(rawAffixText, affixLegend); return new ParsedCriticalBranch( "conditional", CriticalTableParserSupport.NormalizeConditionKey(conditionText), conditionText, string.Join(Environment.NewLine, branchLines), descriptionText, rawAffixText, effects, sortOrder); } private static List FindBranchStartIndexes(IReadOnlyList lines) { var branchStartIndexes = new List(); for (var index = 0; index < lines.Count; index++) { if (CriticalTableParserSupport.IsConditionalBranchStartLine(lines[index])) { branchStartIndexes.Add(index); } } return branchStartIndexes; } private static IReadOnlyList ValidateSegmentCount( IReadOnlyList lines, IReadOnlySet affixLegendSymbols, string scope) { if (lines.Count == 0) { return []; } var segmentCount = CriticalTableParserSupport.CountLineTypeSegments(lines, affixLegendSymbols); return segmentCount > 2 ? [$"{scope} interleaves prose and affix lines."] : []; } private static (string RawText, string DescriptionText, string? RawAffixText) BuildTextSections( IReadOnlyList lines, IReadOnlySet affixLegendSymbols) { var rawText = string.Join(Environment.NewLine, lines); var rawAffixLines = lines.Where(line => CriticalTableParserSupport.IsAffixLikeLine(line, affixLegendSymbols)).ToList(); var descriptionLines = lines.Where(line => !CriticalTableParserSupport.IsAffixLikeLine(line, affixLegendSymbols)).ToList(); var descriptionText = CriticalTableParserSupport.CollapseWhitespace(string.Join(' ', descriptionLines)); var rawAffixText = rawAffixLines.Count == 0 ? null : string.Join(Environment.NewLine, rawAffixLines); return (rawText, descriptionText, rawAffixText); } }