internal void GetElementContext(List <string> tagNameHierarchy, out ControlMetadata currentControl, out ControlPropertyMetadata currentProperty)
        {
            currentProperty = null;
            currentControl  = null;

            for (int i = 0; i < tagNameHierarchy.Count; i++)
            {
                currentProperty = null;
                currentControl  = null;

                var tagName = tagNameHierarchy[i];
                if (metadata.ContainsKey(tagName))
                {
                    // we have found a control
                    currentControl = metadata[tagName];

                    // the next element in the hierarchy might be a property
                    if (i + 1 < tagNameHierarchy.Count)
                    {
                        currentProperty = currentControl.Properties.FirstOrDefault(p => p.Name == tagNameHierarchy[i + 1] && p.IsElement);
                        if (currentProperty != null)
                        {
                            i++;
                        }
                    }
                }
                else
                {
                    // HTML or unknown element
                    currentControl = htmlGenericControlMetadata;
                }
            }
        }
        internal ControlMetadata GetMetadata(string tagName)
        {
            ControlMetadata result = null;

            metadata.TryGetValue(tagName, out result);
            return(result);
        }
        internal List <CompletionData> ReloadAllControls(DothtmlCompletionContext context)
        {
            // get all possible control symbols
            var allClasses     = ReloadAllClasses(context);
            var controlClasses = allClasses
                                 .Where(c => CompletionHelper.GetBaseTypes(c).Any(t => CheckType(t, typeof(DotvvmBindableObject))))
                                 .ToList();

            var result = new List <CompletionData>();

            metadata = new ConcurrentDictionary <string, ControlMetadata>(StringComparer.CurrentCultureIgnoreCase);
            htmlGenericControlMetadata = null;

            foreach (var rule in context.Configuration.Markup.Controls)
            {
                string tagName;
                if (!string.IsNullOrEmpty(rule.Src))
                {
                    // markup control
                    tagName = rule.TagPrefix + ":" + rule.TagName;

                    // TODO: parse markup, find base type and extract metadata

                    result.Add(new CompletionData(tagName));
                }
                else
                {
                    // find all classes declared in the project
                    var controls = controlClasses.Where(c => c.ContainingAssembly.Name == rule.Assembly && c.ContainingNamespace.ToDisplayString() == rule.Namespace);
                    foreach (var control in controls)
                    {
                        tagName = rule.TagPrefix + ":" + control.Name;
                        var controlMetadata = GetControlMetadata(control, rule.TagPrefix, control.Name);
                        metadata[tagName] = controlMetadata;
                        result.Add(new CompletionData(tagName));

                        if (CheckType(control, typeof(HtmlGenericControl)))
                        {
                            htmlGenericControlMetadata = controlMetadata;
                        }
                    }
                }
            }

            return(result);
        }