;*****************************************
;Mustache.au3 by Churanos
;Created with ISN AutoIt Studio v. 1.07
;*****************************************
#include-once
#include <Array.au3>
#include <StringConstants.au3>

Const $__g_iMustache_OK = 0
Const $__g_iMustache_ERROR_SYSTEM = -1
Const $__g_iMustache_ERROR_UNEXPECTED_END = -2
Const $__g_iMustache_ERROR_EMPTY_TAG = -3
Const $__g_iMustache_ERROR_TAG_TOO_LONG = -4
Const $__g_iMustache_ERROR_BAD_SEPARATORS = -5
Const $__g_iMustache_ERROR_TOO_DEPTH = -6
Const $__g_iMustache_ERROR_CLOSING = -7
Const $__g_iMustache_ERROR_BAD_UNESCAPE_TAG = -8

Global $__g_sMustache_REGEX_Partial           = "(?im)({{\>([\w\d]+)}})"
Global $__g_sMustache_REGEX_Section           = "(?im)({{\#([\w\d]+)}})([\W\w\d\s]+)({{\/\2}})"
Global $__g_sMustache_REGEX_InvertedSection   = "(?im)({{\^([\w\d]+)}})([\W\w\d\s]+)({{\/\2}})"
Global $__g_sMustache_REGEX_Variable          = "(?im)({{([\w\d]+)}})"
Global $__g_sMustache_REGEX_UnescapedVariable = "(?im)({{\&([\w\d]+)}})"
Global $__g_sMustache_REGEX_Comment           = "(?im)({{\![\w\d\s]+}})"

Global $__g_oMustache_EscapeChars = __Mustache_Dict(false)
$__g_oMustache_EscapeChars.Add("&", "&amp;")
$__g_oMustache_EscapeChars.Add("<", "&lt;")
$__g_oMustache_EscapeChars.Add(">", "&gt;")
$__g_oMustache_EscapeChars.Add('"', "&qout;")
$__g_oMustache_EscapeChars.Add("'", "&#39;")
$__g_oMustache_EscapeChars.Add("/", "&#x2F;")



; #FUNCTION# ====================================================================================================================
; Name ..........: _Mustache_Render
; Description ...: 
; Syntax ........: _Mustache_Render($sTemplatePath, ByRef $vData [, $oPartials = __Mustache_Dict()])
; Parameters ....: $sTemplatePath       - A string value.
;                  ByRef $vData         - An unknown value.
;                  $oPartials           - [optional] A object value. Default is __Mustache_Dict().
; Return values .: None
; Author ........: Churanos
; Modified ......: 
; Remarks .......: 
; Related .......: 
; Link ..........: 
; Example .......: No
; ===============================================================================================================================
Func _Mustache_Render($sTemplatePath, ByRef $vData, $oPartials = __Mustache_Dict())
	local $data = ObjCreate("Scripting.Dictionary")
	$data.CompareMode = 1
	
	#Region Comments
	local $asComments = StringRegExp($sTemplatePath, $__g_sMustache_REGEX_Comment, $STR_REGEXPARRAYGLOBALFULLMATCH)
	If @error Then
		$data.Add("comments", __Mustache_Array())
	Else
		$data.Add("comments", $asComments)
	EndIf
	
	For $item in ($data("comments"))
		$sTemplatePath = StringReplace($sTemplatePath, $item[0], "", 1)
	Next
	#EndRegion
	
	
	#Region Partials
	local $asPartials = StringRegExp($sTemplatePath, $__g_sMustache_REGEX_Partial, $STR_REGEXPARRAYGLOBALFULLMATCH)
	If @error Then
		$data.Add("partials", __Mustache_Array())
	Else
		$data.Add("partials", $asPartials)
	EndIf
	
	For $item in ($data("partials"))
		If $oPartials.Exists($item[2]) Then
			$sTemplatePath = StringReplace($sTemplatePath, $item[1], _Mustache_Render($oPartials($item[2]), $vData, $oPartials))
		Else
			ConsoleWrite("Partial " & $item[2] & " not found!" & @CRLF)
		EndIf
	Next
	#EndRegion
	
	
	#Region Inverted Sections
	local $asInvertedSections = StringRegExp($sTemplatePath, $__g_sMustache_REGEX_InvertedSection, $STR_REGEXPARRAYGLOBALFULLMATCH)
	If @error Then
		$data.Add("inverted_sections", __Mustache_Array())
	Else
		$data.Add("inverted_sections", $asInvertedSections)
	EndIf
	
	For $item in ($data("inverted_sections"))
		If $vData($item[2]) = False Then
			$sTemplatePath = StringReplace($sTemplatePath, $item[0], _Mustache_Render($item[3], $vData, $oPartials))
		ElseIf UBound($vData($item[2])) <= 0 Then
			$sTemplatePath = StringReplace($sTemplatePath, $item[0], _Mustache_Render($item[3], $vData, $oPartials))
		Else
			
		EndIf
	Next
	#EndRegion
	
	
	#Region Sections
	local $asSections = StringRegExp($sTemplatePath, $__g_sMustache_REGEX_Section, $STR_REGEXPARRAYGLOBALFULLMATCH)
	If @error Then
		$data.Add("sections", __Mustache_Array())
	Else
		$data.Add("sections", $asSections)
	EndIf
	
	For $item in ($data("sections"))
		Switch VarGetType($vData($item[2]))
			Case "UserFunction"
				$sTemplatePath = StringReplace($sTemplatePath, $item[0], ($vData($item[2]))($item[3], $vData))
			Case "Array"
				local $sTempString = ""
				For $tempData in ($vData[$item[2]])
					$sTempString &= _Mustache_Render($item[3], $tempData)
				Next
				$sTemplatePath = StringReplace($sTemplatePath, $item[1], $sTempString)
			Case "Object"
				$sTemplatePath = StringReplace($sTemplatePath, $item[1], _Mustache_Render($item[3], $vData[$item[2]]))
			Case Else
				If ($vData($item[2])) Then
					$sTemplatePath = StringReplace($sTemplatePath, $item[0], $item[3])
				Else
					$sTemplatePath = StringReplace($sTemplatePath, $item[0], "")
				EndIf
		EndSwitch
	Next
	#EndRegion
	
	
	#Region Variables
	local $asVariables = StringRegExp($sTemplatePath, $__g_sMustache_REGEX_Variable, $STR_REGEXPARRAYGLOBALFULLMATCH)
	If @error Then
		$data.Add("variables", __Mustache_Array())
	Else
		$data.Add("variables", $asVariables)
	EndIf
	
	For $item in ($data("variables"))
		local $rep = $vData($item[2])
		For $esc in $__g_oMustache_EscapeChars.Keys
			$rep = StringRegExpReplace($rep, $esc, $__g_oMustache_EscapeChars($esc))
		Next
		$sTemplatePath = StringReplace($sTemplatePath, $item[1], $rep, 1)
	Next
	#EndRegion
	
	
	#Region Unescaped Variables
	local $asUnescapedVariables = StringRegExp($sTemplatePath, $__g_sMustache_REGEX_UnescapedVariable, $STR_REGEXPARRAYGLOBALFULLMATCH)
	If @error Then
		$data.Add("unescaped_variables", __Mustache_Array())
	Else
		$data.Add("unescaped_variables", $asUnescapedVariables)
	EndIf
	
	For $item in ($data("unescaped_variables"))
		$sTemplatePath = StringReplace($sTemplatePath, $item[1], $vData($item[2]), 1)
	Next
	#EndRegion
	
	
	
	return $sTemplatePath
EndFunc


Func __Mustache_Array()
	local $arr[0]
	return $arr
EndFunc

Func __Mustache_Dict($bCompareMode = True)
	local $dict = ObjCreate("Scripting.Dictionary")
	$dict.CompareMode = $bCompareMode ? 1 : 0
	return $dict
EndFunc