private IDirectiveParser CreateParser(string directive, DirectiveHolder current)
        {
            switch (directive.ToLower())
            {
            case "if": return(new IfParser(_metadataContainer));

            case "list": return(new ListDirective(_metadataContainer));

            case "elseif":
            {
                current.ApplyInDirective("else");
                return(new IfParser(_metadataContainer));
            }
            }
            throw new Exception($"Directive {directive} is not supported.");
        }
        private void SetTemplate(string template)
        {
            var matches =
                Regex.Matches(template, @"\$\{([^\}]*)\}").OfType <Match>()
                .Select(item => new { match = item, type = PlaceholderType.Field })
                .Union(
                    Regex.Matches(template, @"(?:&lt;|<)#([[a-zA-Z]*)[\s]([^>&]*)(:?>|&gt;)")
                    .OfType <Match>()
                    .Select(item => new { match = item, type = PlaceholderType.Directive }))
                .Union(
                    Regex.Matches(template, @"(?:&lt;|<)#([[a-zA-Z]*)(:?>|&gt;)")
                    .OfType <Match>()
                    .Select(item => new { match = item, type = PlaceholderType.InDirective }))
                .Union(
                    Regex.Matches(template, @"(?:&lt;|<)\/#([[a-zA-Z]*)(:?>|&gt;)")
                    .OfType <Match>()
                    .Select(item => new { match = item, type = PlaceholderType.DirectiveEnd }));

            _placeholders = new List <IPlaceholder>();

            var             templateIndex    = 0;
            var             position         = 0;
            var             directives       = new Stack <DirectiveHolder>();
            DirectiveHolder currentDirective = null;
            var             holders          = _placeholders;

            foreach (var match in matches.OrderBy(item => item.match.Index))
            {
                var text = template.Substring(templateIndex, match.match.Index - templateIndex);
                holders.Add(new TextHolder(text, position++));

                templateIndex = match.match.Index + match.match.Length;

                switch (match.type)
                {
                case PlaceholderType.Field:
                {
                    var value = match.match.Value.Trim('$', '{', '}');
                    holders.Add(value.StartsWith(".")
                                ? (IPlaceholder) new FunctionHolder(_metadataContainer, value, position++)
                                : new Placeholder(_metadataContainer, value, position++));
                    break;
                }

                case PlaceholderType.Directive:
                {
                    var directive = match.match.Groups[1].Value;
                    var parser    = CreateParser(directive, currentDirective);
                    if (currentDirective != null)
                    {
                        directives.Push(currentDirective);
                        holders = currentDirective.CurrentItems;
                    }
                    currentDirective = new DirectiveHolder(directive, match.match.Groups[2].Value, parser, position++);
                    holders.Add(currentDirective);
                    holders = currentDirective.CurrentItems;
                    break;
                }

                case PlaceholderType.InDirective:
                {
                    var indirective = match.match.Groups[1].Value;
                    if (currentDirective == null)
                    {
                        throw new Exception($"Incorrect In directive {indirective} outside of any other directives");
                    }
                    holders = currentDirective.ApplyInDirective(indirective);
                    break;
                }

                case PlaceholderType.DirectiveEnd:
                {
                    if (currentDirective == null)
                    {
                        throw new Exception($"End of the directive {match.match.Value} don't fit any directive beginning");
                    }

                    while (currentDirective.Directive == "elseif")
                    {
                        currentDirective = directives.Pop();
                    }
                    if (!currentDirective.Directive.Equals(match.match.Groups[1].Value, StringComparison.InvariantCultureIgnoreCase))
                    {
                        throw new Exception($"End of the directive {match.match.Value} don't fit any directive beginning");
                    }

                    if (directives.Count > 0)
                    {
                        currentDirective = directives.Pop();
                        holders          = currentDirective.CurrentItems;
                    }
                    else
                    {
                        currentDirective = null;
                        holders          = _placeholders;
                    }
                    break;
                }
                }
            }
            if (directives.Count > 0)
            {
                throw new Exception($"Not all directives ({directives.Count}) are closed");
            }
            _placeholders.Add(new TextHolder(template.Substring(templateIndex), position));
        }