using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace JDSongConverter
{
///
/// Evaluate an expression containing text mixed with place holders.
///
public class EvaluateExpression
{
private static Regex _regex = new Regex(@"\$\{(?[\w]+)\}");
private MatchEvaluator _evaluator;
private Stack _keysStack;
private IDictionary _definitions;
#region Constructor
public EvaluateExpression(IDictionary definitions)
{
_evaluator = new MatchEvaluator(Evaluator);
_keysStack = new Stack();
_definitions = definitions;
}
#endregion
#region Public Methods
///
/// Evaluate given expressions.
/// Need constant definition in parameter, and if used environment variable have to be
/// expanded.
///
public static string Do(string expression, IDictionary definitions, bool expandEnvironment = false)
{
if (string.IsNullOrEmpty(expression))
{
return expression;
}
EvaluateExpression context = new EvaluateExpression(definitions);
string evaluatedExpression = context.Recursive(expression);
return expandEnvironment ? Environment.ExpandEnvironmentVariables(evaluatedExpression) : evaluatedExpression;
}
///
/// Indicates an expression is fully evaluated.
///
public static bool IsEvaluated(string expression)
{
if (string.IsNullOrEmpty(expression))
{
return true;
}
return !_regex.IsMatch(expression);
}
#endregion
#region Private Methods
private string GetKeyName(Match match)
{
return (null != match) ? match.Groups["keyName"].Value : string.Empty;
}
private string Recursive(string expression)
{
try
{
Match match = _regex.Match(expression);
if (!match.Success)
{
return expression;
}
string evaluated = _regex.Replace(expression, _evaluator);
return (evaluated != expression) ? Recursive(evaluated) : evaluated;
}
catch (System.Exception ex)
{
throw new Exception("Impossible to evaluate : " + expression, ex);
}
}
private string Evaluator(Match match)
{
string keyName = GetKeyName(match);
string keyValue;
if (!_definitions.TryGetValue(keyName, out keyValue))
{
return match.Value;
}
if (_keysStack.Contains(keyName))
{
throw new Exception(keyName + " is used in a cyclic manner");
}
_keysStack.Push(keyName);
string expression = Recursive(keyValue);
_keysStack.Pop();
return expression;
}
#endregion
}
}