private void BuildEntity(string[] debugViewLines, string entityName, int i, DebugViewParserResult result, List <string> properties, List <string> propertyLinks, string line, ref bool inProperties)
        {
            if (!string.IsNullOrEmpty(entityName))
            {
                var    isAbstract             = false;
                var    baseClass              = string.Empty;
                string changeTrackingStrategy = "ChangeTrackingStrategy.Snapshot";

                if (!string.IsNullOrEmpty(line))
                {
                    var parts = line.Trim().Split(' ').ToList();
                    isAbstract = parts.Contains("Abstract");
                    if (parts.Contains("Base:"))
                    {
                        baseClass = parts[parts.IndexOf("Base:") + 1];
                    }
                    changeTrackingStrategy = parts.Where(p => p.StartsWith("ChangeTrackingStrategy.")).FirstOrDefault();
                }
                if (string.IsNullOrEmpty(changeTrackingStrategy))
                {
                    changeTrackingStrategy = "ChangeTrackingStrategy.Snapshot";
                }

                var annotations = GetEntityAnnotations(i, debugViewLines);
                var annotation  = string.Join(Environment.NewLine, annotations);

                result.Nodes.Add(
                    $"<Node Id = \"{entityName}\" Label=\"{entityName}\" Name=\"{entityName}\" BaseClass=\"{baseClass}\" IsAbstract=\"{isAbstract}\" ChangeTrackingStrategy=\"{changeTrackingStrategy}\"  Annotations=\"{annotation}\" Category=\"EntityType\" Group=\"Expanded\" />");
                result.Links.Add(
                    $"<Link Source = \"IModel\" Target=\"{entityName}\" Category=\"Contains\" />");
                result.Nodes.AddRange(properties.Distinct());
                result.Links.AddRange(propertyLinks.Distinct());
                properties.Clear();
                propertyLinks.Clear();
            }
            inProperties = false;
        }
        public DebugViewParserResult Parse(string[] debugViewLines, string dbContextName)
        {
            var result = new DebugViewParserResult();

            var modelAnnotated          = false;
            var productVersion          = string.Empty;
            var modelAnnotations        = string.Empty;
            var modelPropertyAccessMode = "PropertyAccessMode.Default";
            var changeTrackingStrategy  = "ChangeTrackingStrategy.Snapshot";

            foreach (var line in debugViewLines)
            {
                if (line.StartsWith("Model:"))
                {
                    var props = line.Trim().Split(' ').ToList();
                    if (props.Count > 0)
                    {
                        changeTrackingStrategy = props.Where(p => p.StartsWith("ChangeTrackingStrategy.")).FirstOrDefault();
                        if (string.IsNullOrEmpty(changeTrackingStrategy))
                        {
                            changeTrackingStrategy = "ChangeTrackingStrategy.Snapshot";
                        }

                        modelPropertyAccessMode = GetPropertyAccessMode(props);
                    }
                }
                if (line.StartsWith("Annotations:"))
                {
                    modelAnnotated = true;
                }
                if (modelAnnotated)
                {
                    if (line.TrimStart().StartsWith("ProductVersion: "))
                    {
                        productVersion = line.Trim().Split(' ')[1];
                    }
                    if (!line.TrimStart().StartsWith("ProductVersion: ") &&
                        !line.TrimStart().StartsWith("Annotations:"))
                    {
                        modelAnnotations += line.Trim() + Environment.NewLine;
                    }
                }
            }
            result.Nodes.Add(
                $"<Node Id=\"IModel\" Label=\"{dbContextName}\" ChangeTrackingStrategy=\"{changeTrackingStrategy}\" PropertyAccessMode=\"{modelPropertyAccessMode}\" ProductVersion=\"{productVersion}\" Annotations=\"{modelAnnotations.Trim()}\" Category=\"Model\" Group=\"Expanded\" />");

            var entityName        = string.Empty;
            var properties        = new List <string>();
            var propertyLinks     = new List <string>();
            var inProperties      = false;
            var inOtherProperties = false;
            var i = -1;

            foreach (var line in debugViewLines)
            {
                i++;
                if (line.TrimStart().StartsWith("EntityType:"))
                {
                    entityName = System.Security.SecurityElement.Escape(line.Trim().Split(' ')[1]);
                    BuildEntity(debugViewLines, entityName, i, result, properties, propertyLinks, line, ref inProperties);
                }
                if (line.TrimStart().StartsWith("Properties:"))
                {
                    inProperties      = true;
                    inOtherProperties = false;
                }

                if (!string.IsNullOrEmpty(entityName) && inProperties)
                {
                    if (line.StartsWith("    Keys:") ||
                        line.StartsWith("    Navigations:") ||
                        line.StartsWith("    Annotations:") ||
                        line.StartsWith("    Foreign keys:"))
                    {
                        inOtherProperties = true;
                        continue;
                    }
                    if (line.StartsWith("      ") && !inOtherProperties)
                    {
                        var annotations = GetAnnotations(i, debugViewLines);

                        var navigations = GetNavigations(i, debugViewLines);

                        var foreignKeysFragment = GetForeignKeys(i, debugViewLines);

                        if (line.StartsWith("        Annotations:") ||
                            line.StartsWith("          "))
                        {
                            continue;
                        }

                        var annotation = string.Join(Environment.NewLine, annotations);

                        var foundLine = line.Replace("(no field, ", "(nofield,");
                        foundLine = foundLine.Replace(", ", ",");

                        var props = foundLine.Trim().Split(' ').ToList();

                        var name  = props[0];
                        var field = GetTypeValue(props[1], true);
                        var type  = GetTypeValue(props[1], false);

                        props.RemoveRange(0, 2);

                        var isRequired     = props.Contains("Required");
                        var isIndexed      = props.Contains("Index");
                        var isPrimaryKey   = props.Contains("PK");
                        var isForeignKey   = props.Contains("FK");
                        var isShadow       = props.Contains("Shadow");
                        var isAlternateKey = props.Contains("AlternateKey");
                        var isConcurrency  = props.Contains("Concurrency");
                        var isUnicode      = !props.Contains("Ansi");

                        var beforeSaveBehavior = "PropertySaveBehavior.Save";
                        if (props.Contains("BeforeSave:PropertySaveBehavior.Ignore"))
                        {
                            beforeSaveBehavior = "PropertySaveBehavior.Ignore";
                        }
                        if (props.Contains("BeforeSave:PropertySaveBehavior.Throw"))
                        {
                            beforeSaveBehavior = "PropertySaveBehavior.Throw";
                        }

                        var afterSaveBehavior = "PropertySaveBehavior.Save";
                        if (props.Contains("AfterSave:PropertySaveBehavior.Ignore"))
                        {
                            afterSaveBehavior = "PropertySaveBehavior.Ignore";
                        }
                        if (props.Contains("AfterSave:PropertySaveBehavior.Throw"))
                        {
                            afterSaveBehavior = "PropertySaveBehavior.Throw";
                        }

                        string propertyAccesMode = GetPropertyAccessMode(props);

                        var maxLength = props.FirstOrDefault(p => p.StartsWith("MaxLength"));
                        if (string.IsNullOrEmpty(maxLength))
                        {
                            maxLength = "None";
                        }
                        else
                        {
                            maxLength = maxLength.Replace("MaxLength", string.Empty);
                        }

                        var valueGenerated = props.FirstOrDefault(p => p.StartsWith("ValueGenerated.")) ?? "None";
                        var category       = "Property Required";
                        if (!isRequired)
                        {
                            category = "Property Optional";
                        }
                        if (isForeignKey)
                        {
                            category = "Property Foreign";
                        }
                        if (isPrimaryKey)
                        {
                            category = "Property Primary";
                        }

                        properties.Add(
                            $"<Node Id = \"{entityName}.{name}\" Label=\"{name}\" Name=\"{name}\" Category=\"{category}\" Type=\"{type}\" MaxLength=\"{maxLength}\" Field=\"{field}\" PropertyAccessMode=\"{propertyAccesMode}\" BeforeSaveBehavior=\"{beforeSaveBehavior}\" AfterSaveBehavior=\"{afterSaveBehavior}\" Annotations=\"{annotation}\" IsPrimaryKey=\"{isPrimaryKey}\" IsForeignKey=\"{isForeignKey}\" IsRequired=\"{isRequired}\" IsIndexed=\"{isIndexed}\" IsShadow=\"{isShadow}\" IsAlternateKey=\"{isAlternateKey}\" IsConcurrencyToken=\"{isConcurrency}\" IsUnicode=\"{isUnicode}\" ValueGenerated=\"{valueGenerated}\" />");

                        var navigationResult = ParseNavigations(navigations, entityName);

                        properties.AddRange(navigationResult.Item1);

                        propertyLinks.AddRange(navigationResult.Item2);

                        propertyLinks.Add($"<Link Source = \"{entityName}\" Target=\"{entityName}.{name}\" Category=\"Contains\" />");

                        propertyLinks.AddRange(ParseForeignKeys(foreignKeysFragment));
                    }
                }
            }
            BuildEntity(debugViewLines, entityName, i, result, properties, propertyLinks, null, ref inProperties);
            return(result);
        }