JsonSchemaModelBuilder
                    class JsonSchemaModelBuilder
                
                using Newtonsoft.Json.Utilities.LinqBridge;
using System;
using System.Collections.Generic;
namespace Newtonsoft.Json.Schema
{
    [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")]
    internal class JsonSchemaModelBuilder
    {
        private JsonSchemaNodeCollection _nodes = new JsonSchemaNodeCollection();
        private Dictionary<JsonSchemaNode, JsonSchemaModel> _nodeModels = new Dictionary<JsonSchemaNode, JsonSchemaModel>();
        private JsonSchemaNode _node;
        public JsonSchemaModel Build(JsonSchema schema)
        {
            _nodes = new JsonSchemaNodeCollection();
            _node = AddSchema(null, schema);
            _nodeModels = new Dictionary<JsonSchemaNode, JsonSchemaModel>();
            return BuildNodeModel(_node);
        }
        public JsonSchemaNode AddSchema(JsonSchemaNode existingNode, JsonSchema schema)
        {
            string id;
            if (existingNode != null) {
                if (existingNode.Schemas.Contains(schema))
                    return existingNode;
                id = JsonSchemaNode.GetId(existingNode.Schemas.Union(new JsonSchema[1] {
                    schema
                }));
            } else
                id = JsonSchemaNode.GetId(new JsonSchema[1] {
                    schema
                });
            if (_nodes.Contains(id))
                return _nodes[id];
            JsonSchemaNode jsonSchemaNode = (existingNode != null) ? existingNode.Combine(schema) : new JsonSchemaNode(schema);
            _nodes.Add(jsonSchemaNode);
            AddProperties(schema.Properties, jsonSchemaNode.Properties);
            AddProperties(schema.PatternProperties, jsonSchemaNode.PatternProperties);
            if (schema.Items != null) {
                for (int i = 0; i < schema.Items.Count; i++) {
                    AddItem(jsonSchemaNode, i, schema.Items[i]);
                }
            }
            if (schema.AdditionalItems != null)
                AddAdditionalItems(jsonSchemaNode, schema.AdditionalItems);
            if (schema.AdditionalProperties != null)
                AddAdditionalProperties(jsonSchemaNode, schema.AdditionalProperties);
            if (schema.Extends != null) {
                foreach (JsonSchema extend in schema.Extends) {
                    jsonSchemaNode = AddSchema(jsonSchemaNode, extend);
                }
                return jsonSchemaNode;
            }
            return jsonSchemaNode;
        }
        public void AddProperties(IDictionary<string, JsonSchema> source, IDictionary<string, JsonSchemaNode> target)
        {
            if (source != null) {
                foreach (KeyValuePair<string, JsonSchema> item in source) {
                    AddProperty(target, item.Key, item.Value);
                }
            }
        }
        public void AddProperty(IDictionary<string, JsonSchemaNode> target, string propertyName, JsonSchema schema)
        {
            target.TryGetValue(propertyName, out JsonSchemaNode value);
            target[propertyName] = AddSchema(value, schema);
        }
        public void AddItem(JsonSchemaNode parentNode, int index, JsonSchema schema)
        {
            JsonSchemaNode existingNode = (parentNode.Items.Count > index) ? parentNode.Items[index] : null;
            JsonSchemaNode jsonSchemaNode = AddSchema(existingNode, schema);
            if (parentNode.Items.Count <= index)
                parentNode.Items.Add(jsonSchemaNode);
            else
                parentNode.Items[index] = jsonSchemaNode;
        }
        public void AddAdditionalProperties(JsonSchemaNode parentNode, JsonSchema schema)
        {
            parentNode.AdditionalProperties = AddSchema(parentNode.AdditionalProperties, schema);
        }
        public void AddAdditionalItems(JsonSchemaNode parentNode, JsonSchema schema)
        {
            parentNode.AdditionalItems = AddSchema(parentNode.AdditionalItems, schema);
        }
        private JsonSchemaModel BuildNodeModel(JsonSchemaNode node)
        {
            if (_nodeModels.TryGetValue(node, out JsonSchemaModel value))
                return value;
            value = JsonSchemaModel.Create(node.Schemas);
            _nodeModels[node] = value;
            Dictionary<string, JsonSchemaNode>.Enumerator enumerator = node.Properties.GetEnumerator();
            try {
                while (enumerator.MoveNext()) {
                    KeyValuePair<string, JsonSchemaNode> current = enumerator.Current;
                    if (value.Properties == null)
                        value.Properties = new Dictionary<string, JsonSchemaModel>();
                    value.Properties[current.Key] = BuildNodeModel(current.Value);
                }
            } finally {
                ((IDisposable)enumerator).Dispose();
            }
            enumerator = node.PatternProperties.GetEnumerator();
            try {
                while (enumerator.MoveNext()) {
                    KeyValuePair<string, JsonSchemaNode> current2 = enumerator.Current;
                    if (value.PatternProperties == null)
                        value.PatternProperties = new Dictionary<string, JsonSchemaModel>();
                    value.PatternProperties[current2.Key] = BuildNodeModel(current2.Value);
                }
            } finally {
                ((IDisposable)enumerator).Dispose();
            }
            foreach (JsonSchemaNode item in node.Items) {
                if (value.Items == null)
                    value.Items = new List<JsonSchemaModel>();
                value.Items.Add(BuildNodeModel(item));
            }
            if (node.AdditionalProperties != null)
                value.AdditionalProperties = BuildNodeModel(node.AdditionalProperties);
            if (node.AdditionalItems != null)
                value.AdditionalItems = BuildNodeModel(node.AdditionalItems);
            return value;
        }
    }
}