using System.Text.Json; namespace Inspectron.Epson.TemplateEngine.DataBinding; public class DataContext { private readonly JsonElement _root; private readonly DataContext? _parent; private readonly Dictionary _variables = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _loopVariables = new(StringComparer.OrdinalIgnoreCase); public DataContext(JsonElement root) { _root = root; } private DataContext(JsonElement root, DataContext parent) { _root = root; _parent = parent; } public DataContext CreateChildScope() { return new DataContext(_root, this); } public void SetVariable(string name, JsonElement value) { _variables[name] = value; } public void SetLoopVariable(string name, object value) { _loopVariables[name] = value; } public object? GetLoopVariable(string name) { if (_loopVariables.TryGetValue(name, out var value)) return value; return _parent?.GetLoopVariable(name); } public JsonElement? Resolve(string expression) { if (string.IsNullOrWhiteSpace(expression)) return null; var parts = expression.Split('.'); var firstPart = parts[0]; // Check local variables first JsonElement? current = null; if (_variables.TryGetValue(firstPart, out var varValue)) { current = varValue; } else if (_parent != null) { // Walk up scope chain for variables var ctx = _parent; while (ctx != null) { if (ctx._variables.TryGetValue(firstPart, out var parentVar)) { current = parentVar; break; } ctx = ctx._parent; } } // If not found in variables, try root if (current == null) { current = GetProperty(_root, firstPart); } if (current == null) return null; // Navigate remaining parts for (int i = 1; i < parts.Length; i++) { current = GetProperty(current.Value, parts[i]); if (current == null) return null; } return current; } private static JsonElement? GetProperty(JsonElement element, string propertyName) { if (element.ValueKind != JsonValueKind.Object) return null; // Case-insensitive property lookup foreach (var prop in element.EnumerateObject()) { if (string.Equals(prop.Name, propertyName, StringComparison.OrdinalIgnoreCase)) return prop.Value; } return null; } public static string GetStringValue(JsonElement element) { return element.ValueKind switch { JsonValueKind.String => element.GetString() ?? "", JsonValueKind.Number => element.TryGetInt64(out var l) ? l.ToString() : element.GetDouble().ToString(), JsonValueKind.True => "true", JsonValueKind.False => "false", JsonValueKind.Null => "", JsonValueKind.Undefined => "", _ => element.GetRawText() }; } }