using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Text.RegularExpressions; using F4SD.ActionConnector.Payloads; namespace F4SD.ActionConnector.Execution { /// /// Resolves template variables such as {{Case.Id}} or {{Case.ClosedAt:yyyy-MM-ddTHH:mm:ssZ}} /// against a payload object. /// /// Variable format: {{ObjectName.PropertyName[:FormatSpecifier]}} /// internal static class PayloadVariableResolver { private static readonly Regex VariablePattern = new Regex(@"\{\{(?[^.}]+)\.(?[^:}]+)(?::(?[^}]+))?\}\}", RegexOptions.Compiled); /// /// Returns a new dictionary with every value in having /// its template variables replaced by the corresponding payload property values. /// Pure single-variable templates (e.g. {{Case.ClosedAt}}) yield the raw typed /// object; mixed or formatted templates yield a resolved string. /// internal static IDictionary Resolve( IDictionary rawParameters, PayloadBase payload) { var resolved = new Dictionary(rawParameters.Count); foreach (var pair in rawParameters) resolved[pair.Key] = ResolveValue(pair.Value, payload); return resolved; } private static object ResolveValue(string template, PayloadBase payload) { var match = VariablePattern.Match(template); // Pure single variable with no format specifier → return raw object if (match.Success && match.Value == template && !match.Groups["fmt"].Success) return ResolveRawProperty(match, payload); // Mixed template, literal, or explicit format specifier → return resolved string return ResolveString(template, payload); } private static object ResolveRawProperty(Match match, PayloadBase payload) { string propertyName = match.Groups["prop"].Value; PropertyInfo property = payload.GetType().GetProperty( propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); if (property == null) return match.Value; return property.GetValue(payload); } private static string ResolveString(string template, PayloadBase payload) { return VariablePattern.Replace(template, match => ResolveMatch(match, payload)); } private static string ResolveMatch(Match match, PayloadBase payload) { string propertyName = match.Groups["prop"].Value; string formatSpecifier = match.Groups["fmt"].Success ? match.Groups["fmt"].Value : null; PropertyInfo property = payload.GetType().GetProperty( propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); if (property == null) return match.Value; object value = property.GetValue(payload); if (value == null) return string.Empty; if (formatSpecifier != null && value is IFormattable formattable) return formattable.ToString(formatSpecifier, CultureInfo.InvariantCulture); return value.ToString(); } } }