using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
namespace UnityAtoms.Editor
{
///
/// Internal class used for templating when generating new Atoms using the `Generator`.
///
internal class Templating
{
///
/// Resolve conditionals from the provided tempalte.
///
/// Template to resolve the conditionals from.
/// A list of conditionals that are `true`.
/// A new template string resolved and based on the provided `template`.
public static string ResolveConditionals(string template, List trueConditions)
{
var templateCopy = String.Copy(template);
templateCopy = templateCopy.Replace("\r\n", "\n");
var indexIfOpened = templateCopy.LastIndexOf("<%IF ", StringComparison.Ordinal);
if (indexIfOpened == -1) return templateCopy; // No IF blocks left and nothing else to resolve. Return template.
var indexIfClosed = templateCopy.IndexOf("%>", indexIfOpened + 5, StringComparison.Ordinal);
if (indexIfClosed == -1) throw new Exception("Found <%IF block but it was never closed (missing %>)");
// NOTE: Only supports OR:ed conditions ATM
var conditions = new List>();
var conditionStrings = templateCopy.Substring(indexIfOpened + 5, indexIfClosed - (indexIfOpened + 5)).Split('|').ToList();
conditionStrings.ForEach((c) => {
var isNegated = c.Substring(0, 1) == "!";
conditions.Add(new Tuple(
isNegated ? c.Substring(1) : c,
isNegated
));
});
var indexOfNextEndIf = templateCopy.IndexOf("<%ENDIF%>", indexIfClosed, StringComparison.Ordinal);
if (indexOfNextEndIf == -1) throw new Exception("No closing <%ENDIF%> for condition.");
// NOTE: We are assuming that when the next char after the conditional is a new line char that it's not inline.
// However, this is not always true (you can have an inline conditional at the end of a line). This implementation
// works for our cases for now, but we might need to come back and change this in the future for other use cases.
var indexOfNextCharAfterEndIf = indexOfNextEndIf + "<%ENDIF%>".Length;
var indexOfLFAfterEndIf =
templateCopy.IndexOf("\n", indexOfNextEndIf, StringComparison.Ordinal);
var inline = true;
if (indexOfLFAfterEndIf == indexOfNextCharAfterEndIf)
{
indexOfNextCharAfterEndIf = indexOfLFAfterEndIf + 1;
inline = false;
}
var indexOfNextElse = templateCopy.IndexOf("<%ELSE%>", indexIfClosed, StringComparison.Ordinal);
if (indexOfNextElse >= indexOfNextEndIf) indexOfNextElse = -1;
var endThenBlock = indexOfNextElse != -1 ? indexOfNextElse : indexOfNextEndIf;
var resolved = "";
if (conditions.Any((condition) => trueConditions.Contains(condition.Item1) ^ condition.Item2))
{
resolved = templateCopy.Substring(indexIfClosed + 2, endThenBlock - (indexIfClosed + 2));
}
else if (indexOfNextElse != -1)
{
resolved = templateCopy.Substring(indexOfNextElse + 8, indexOfNextEndIf - (indexOfNextElse + 8));
}
resolved = resolved.Trim('\n');
templateCopy = templateCopy.Remove(indexIfOpened, indexOfNextCharAfterEndIf - indexIfOpened);
templateCopy = templateCopy.Insert(indexIfOpened, string.IsNullOrEmpty(resolved) ? "" : $"{resolved}" + (inline ? "" : "\n"));
return ResolveConditionals(templateCopy, trueConditions);
}
///
/// Resolve variables in the provided string.
///
/// Dictionay mapping template variables and their resolutions.
/// The string to resolve.
/// A new template string resolved and based on the provided `toResolve` string.
public static string ResolveVariables(Dictionary templateVariables, string toResolve)
{
var resolvedString = toResolve;
foreach (var kvp in templateVariables)
{
resolvedString = resolvedString.Replace("{" + kvp.Key + "}", kvp.Value);
}
return resolvedString;
}
}
}