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();
}
}
}