using System; namespace NexusReader.UI.Shared.Services; /// /// AOT-safe string parsing utility to isolate paywall teaser details without regex overhead. /// public static class PaywallParser { public static bool TryParsePaywallTrigger( string rawText, out string displayTeaserText, out Guid lockedBookId, out string lockedBookTitle, out int localScore, out int globalScore) { displayTeaserText = rawText; lockedBookId = Guid.Empty; lockedBookTitle = string.Empty; localScore = 0; globalScore = 0; if (string.IsNullOrEmpty(rawText)) return false; ReadOnlySpan span = rawText.AsSpan(); int tokenStartIndex = span.IndexOf("[PAYWALL_TRIGGER:"); if (tokenStartIndex == -1) return false; displayTeaserText = span.Slice(0, tokenStartIndex).Trim().ToString(); ReadOnlySpan tokenContent = span.Slice(tokenStartIndex + "[PAYWALL_TRIGGER:".Length); int tokenEndIndex = tokenContent.IndexOf(']'); if (tokenEndIndex == -1) return false; tokenContent = tokenContent.Slice(0, tokenEndIndex); int firstColonIdx = tokenContent.IndexOf(':'); if (firstColonIdx == -1) return false; ReadOnlySpan guidSpan = tokenContent.Slice(0, firstColonIdx); if (!Guid.TryParse(guidSpan, out lockedBookId)) return false; ReadOnlySpan remaining = tokenContent.Slice(firstColonIdx + 1); int lastColonIdx = remaining.LastIndexOf(':'); if (lastColonIdx == -1) return false; ReadOnlySpan globalScoreSpan = remaining.Slice(lastColonIdx + 1); if (!int.TryParse(globalScoreSpan, out globalScore)) return false; remaining = remaining.Slice(0, lastColonIdx); int secondLastColonIdx = remaining.LastIndexOf(':'); if (secondLastColonIdx == -1) return false; ReadOnlySpan localScoreSpan = remaining.Slice(secondLastColonIdx + 1); if (!int.TryParse(localScoreSpan, out localScore)) return false; lockedBookTitle = remaining.Slice(0, secondLastColonIdx).ToString(); return true; } }