using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace BrewMonster.Scripts.Chat.EmotionData
{
///
/// Parser token giống thứ tự đọc trong AUIManager.cpp (Emotions{N}.txt).
/// Token order matches AUIManager.cpp when loading Emotions{N}.txt.
///
public static class EmotionTxtParser
{
public const int MaxFrames = 20; // AUITEXTAREA_EMOTHION_MAXFRAME
public readonly struct ParseResult
{
public readonly List Entries;
public readonly string ErrorMessage;
public bool Success => string.IsNullOrEmpty(ErrorMessage);
public ParseResult(List entries, string error)
{
Entries = entries;
ErrorMessage = error ?? "";
}
}
///
/// Đọc toàn bộ nội dung file txt; token tách bằng whitespace (giống GetNextToken cơ bản).
/// Reads full txt; tokens split by whitespace (basic GetNextToken behavior).
///
public static ParseResult Parse(string text)
{
if (string.IsNullOrWhiteSpace(text))
return new ParseResult(new List(), "Empty text.");
var tokens = Tokenize(text);
var entries = new List();
int t = 0;
while (t < tokens.Count)
{
if (!TryParseInt(tokens[t], out int startPos))
return new ParseResult(null, $"Invalid nStartPos at token index {t}: '{tokens[t]}'");
t++;
if (t >= tokens.Count)
return new ParseResult(null, "Unexpected EOF after nStartPos.");
if (!TryParseInt(tokens[t], out int numFramesRaw))
return new ParseResult(null, $"Invalid nNumFrames at token index {t}.");
int numFrames = Math.Min(Math.Max(0, numFramesRaw), MaxFrames);
t++;
if (t >= tokens.Count)
return new ParseResult(null, "Unexpected EOF after nNumFrames (missing hint).");
string hint = tokens[t];
t++;
var frameTicks = new int[numFrames];
for (int i = 0; i < numFrames; i++)
{
if (t >= tokens.Count)
return new ParseResult(null,
$"Unexpected EOF: need {numFrames} frame tick values for entry starting at StartPos={startPos}.");
if (!TryParseInt(tokens[t], out frameTicks[i]))
return new ParseResult(null, $"Invalid nFrameTick[{i}] at token index {t}.");
t++;
}
entries.Add(new EmotionEntryData
{
StartPos = startPos,
NumFrames = numFrames,
Hint = hint,
FrameTicks = frameTicks
});
}
return new ParseResult(entries, null);
}
private static bool TryParseInt(string s, out int v)
{
return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v);
}
///
/// Tách token: khoảng trắng; hỗ trợ chuỗi trong dấu ngoặc kép cho hint nếu sau này cần.
///
private static List Tokenize(string text)
{
var list = new List();
var sb = new StringBuilder();
bool inQuotes = false;
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (inQuotes)
{
if (c == '"')
inQuotes = false;
else
sb.Append(c);
continue;
}
if (c == '"')
{
if (sb.Length > 0)
{
list.Add(sb.ToString());
sb.Clear();
}
inQuotes = true;
continue;
}
if (char.IsWhiteSpace(c))
{
if (sb.Length > 0)
{
list.Add(sb.ToString());
sb.Clear();
}
continue;
}
sb.Append(c);
}
if (sb.Length > 0)
list.Add(sb.ToString());
return list;
}
}
}