private void Push(JsonSchema value)
		{
			_currentSchema = value;
			_stack.Add(value);
			_resolver.LoadedSchemas.Add(value);
			_documentSchemas.Add(value.Location, value);
		}
			public TypeSchema(Type type, JsonSchema schema)
			{
				ValidationUtils.ArgumentNotNull(type, "type");
				ValidationUtils.ArgumentNotNull(schema, "schema");

				Type = type;
				Schema = schema;
			}
		private JsonSchema Pop()
		{
			JsonSchema poppedSchema = _currentSchema;
			_stack.RemoveAt(_stack.Count - 1);
			_currentSchema = _stack.LastOrDefault();

			return poppedSchema;
		}
		public JsonSchemaNode(JsonSchema schema)
		{
			Schemas = new ReadOnlyCollection<JsonSchema>(new[] {schema});
			Properties = new Dictionary<string, JsonSchemaNode>();
			PatternProperties = new Dictionary<string, JsonSchemaNode>();
			Items = new List<JsonSchemaNode>();

			Id = GetId(Schemas);
		}
		/// <summary>
		/// Determines whether the <see cref="JToken"/> is valid.
		/// </summary>
		/// <param name="source">The source <see cref="JToken"/> to test.</param>
		/// <param name="schema">The schema to test with.</param>
		/// <param name="errorMessages">When this method returns, contains any error messages generated while validating. </param>
		/// <returns>
		/// 	<c>true</c> if the specified <see cref="JToken"/> is valid; otherwise, <c>false</c>.
		/// </returns>
		public static bool IsValid(this JToken source, JsonSchema schema, out IList<string> errorMessages)
		{
			IList<string> errors = new List<string>();

			source.Validate(schema, (sender, args) => errors.Add(args.Message));

			errorMessages = errors;
			return (errorMessages.Count == 0);
		}
		public JsonSchemaModel Build(JsonSchema schema)
		{
			_nodes = new JsonSchemaNodeCollection();
			_node = AddSchema(null, schema);

			_nodeModels = new Dictionary<JsonSchemaNode, JsonSchemaModel>();
			JsonSchemaModel model = BuildNodeModel(_node);

			return model;
		}
		private JsonSchemaNode(JsonSchemaNode source, JsonSchema schema)
		{
			Schemas = new ReadOnlyCollection<JsonSchema>(source.Schemas.Union(new[] {schema}).ToList());
			Properties = new Dictionary<string, JsonSchemaNode>(source.Properties);
			PatternProperties = new Dictionary<string, JsonSchemaNode>(source.PatternProperties);
			Items = new List<JsonSchemaNode>(source.Items);
			AdditionalProperties = source.AdditionalProperties;
			AdditionalItems = source.AdditionalItems;

			Id = GetId(Schemas);
		}
		public JsonSchemaNode AddSchema(JsonSchemaNode existingNode, JsonSchema schema)
		{
			string newId;
			if (existingNode != null)
			{
				if (existingNode.Schemas.Contains(schema))
					return existingNode;

				newId = JsonSchemaNode.GetId(existingNode.Schemas.Union(new[] {schema}));
			}
			else
			{
				newId = JsonSchemaNode.GetId(new[] {schema});
			}

			if (_nodes.Contains(newId))
				return _nodes[newId];

			JsonSchemaNode currentNode = (existingNode != null) ? existingNode.Combine(schema) : new JsonSchemaNode(schema);

			_nodes.Add(currentNode);

			AddProperties(schema.Properties, currentNode.Properties);

			AddProperties(schema.PatternProperties, currentNode.PatternProperties);

			if (schema.Items != null)
			{
				for (int i = 0; i < schema.Items.Count; i++)
				{
					AddItem(currentNode, i, schema.Items[i]);
				}
			}

			if (schema.AdditionalItems != null)
				AddAdditionalItems(currentNode, schema.AdditionalItems);

			if (schema.AdditionalProperties != null)
				AddAdditionalProperties(currentNode, schema.AdditionalProperties);

			if (schema.Extends != null)
			{
				foreach (var jsonSchema in schema.Extends)
				{
					currentNode = AddSchema(currentNode, jsonSchema);
				}
			}

			return currentNode;
		}
		private void ReferenceOrWriteSchema(JsonSchema schema)
		{
			if (schema.Id != null && _resolver.GetSchema(schema.Id) != null)
			{
				_writer.WriteStartObject();
				_writer.WritePropertyName(JsonSchemaConstants.ReferencePropertyName);
				_writer.WriteValue(schema.Id);
				_writer.WriteEndObject();
			}
			else
			{
				WriteSchema(schema);
			}
		}
		private static void Combine(JsonSchemaModel model, JsonSchema schema)
		{
			// Version 3 of the Draft JSON Schema has the default value of Not Required
			model.Required = model.Required || (schema.Required ?? false);
			model.Type = model.Type & (schema.Type ?? JsonSchemaType.Any);

			model.MinimumLength = MathUtils.Max(model.MinimumLength, schema.MinimumLength);
			model.MaximumLength = MathUtils.Min(model.MaximumLength, schema.MaximumLength);

			// not sure what is the best way to combine divisibleBy
			model.DivisibleBy = MathUtils.Max(model.DivisibleBy, schema.DivisibleBy);

			model.Minimum = MathUtils.Max(model.Minimum, schema.Minimum);
			model.Maximum = MathUtils.Max(model.Maximum, schema.Maximum);
			model.ExclusiveMinimum = model.ExclusiveMinimum || (schema.ExclusiveMinimum ?? false);
			model.ExclusiveMaximum = model.ExclusiveMaximum || (schema.ExclusiveMaximum ?? false);

			model.MinimumItems = MathUtils.Max(model.MinimumItems, schema.MinimumItems);
			model.MaximumItems = MathUtils.Min(model.MaximumItems, schema.MaximumItems);
			model.PositionalItemsValidation = model.PositionalItemsValidation || schema.PositionalItemsValidation;
			model.AllowAdditionalProperties = model.AllowAdditionalProperties && schema.AllowAdditionalProperties;
			model.AllowAdditionalItems = model.AllowAdditionalItems && schema.AllowAdditionalItems;
			model.UniqueItems = model.UniqueItems || schema.UniqueItems;
			if (schema.Enum != null)
			{
				if (model.Enum == null)
					model.Enum = new List<JToken>();

				model.Enum.AddRangeDistinct(schema.Enum, JToken.EqualityComparer);
			}
			model.Disallow = model.Disallow | (schema.Disallow ?? JsonSchemaType.None);

			if (schema.Pattern != null)
			{
				if (model.Patterns == null)
					model.Patterns = new List<string>();

				model.Patterns.AddDistinct(schema.Pattern);
			}
		}
		/// <summary>
		/// Validates the specified <see cref="JToken"/>.
		/// </summary>
		/// <param name="source">The source <see cref="JToken"/> to test.</param>
		/// <param name="schema">The schema to test with.</param>
		public static void Validate(this JToken source, JsonSchema schema)
		{
			source.Validate(schema, null);
		}
 public void AddAdditionalItems(JsonSchemaNode parentNode, JsonSchema schema)
 {
     parentNode.AdditionalItems = AddSchema(parentNode.AdditionalItems, schema);
 }
		public void AddAdditionalItems(JsonSchemaNode parentNode, JsonSchema schema)
		{
			parentNode.AdditionalItems = AddSchema(parentNode.AdditionalItems, schema);
		}
 public void AddAdditionalProperties(JsonSchemaNode parentNode, JsonSchema schema)
 {
     parentNode.AdditionalProperties = AddSchema(parentNode.AdditionalProperties, schema);
 }
		private JsonSchema ResolveReferences(JsonSchema schema)
		{
			if (schema.DeferredReference != null)
			{
				string reference = schema.DeferredReference;

				bool locationReference = (reference.StartsWith("#", StringComparison.OrdinalIgnoreCase));
				if (locationReference)
					reference = UnescapeReference(reference);

				JsonSchema resolvedSchema = _resolver.GetSchema(reference);

				if (resolvedSchema == null)
				{
					if (locationReference)
					{
						string[] escapedParts = schema.DeferredReference.TrimStart('#').Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
						JToken currentToken = _rootSchema;
						foreach (var escapedPart in escapedParts)
						{
							string part = UnescapeReference(escapedPart);

							if (currentToken.Type == JTokenType.Object)
							{
								currentToken = currentToken[part];
							}
							else if (currentToken.Type == JTokenType.Array || currentToken.Type == JTokenType.Constructor)
							{
								int index;
								if (int.TryParse(part, out index) && index >= 0 && index < currentToken.Count())
									currentToken = currentToken[index];
								else
									currentToken = null;
							}

							if (currentToken == null)
								break;
						}

						if (currentToken != null)
							resolvedSchema = BuildSchema(currentToken);
					}

					if (resolvedSchema == null)
						throw new JsonException("Could not resolve schema reference '{0}'.".FormatWith(CultureInfo.InvariantCulture, schema.DeferredReference));
				}

				schema = resolvedSchema;
			}

			if (schema.ReferencesResolved)
				return schema;

			schema.ReferencesResolved = true;

			if (schema.Extends != null)
			{
				for (int i = 0; i < schema.Extends.Count; i++)
				{
					schema.Extends[i] = ResolveReferences(schema.Extends[i]);
				}
			}

			if (schema.Items != null)
			{
				for (int i = 0; i < schema.Items.Count; i++)
				{
					schema.Items[i] = ResolveReferences(schema.Items[i]);
				}
			}

			if (schema.AdditionalItems != null)
				schema.AdditionalItems = ResolveReferences(schema.AdditionalItems);

			if (schema.PatternProperties != null)
			{
				foreach (var patternProperty in schema.PatternProperties.ToList())
				{
					schema.PatternProperties[patternProperty.Key] = ResolveReferences(patternProperty.Value);
				}
			}

			if (schema.Properties != null)
			{
				foreach (var property in schema.Properties.ToList())
				{
					schema.Properties[property.Key] = ResolveReferences(property.Value);
				}
			}

			if (schema.AdditionalProperties != null)
				schema.AdditionalProperties = ResolveReferences(schema.AdditionalProperties);

			return schema;
		}
		private TypeSchema Pop()
		{
			TypeSchema popped = _stack[_stack.Count - 1];
			_stack.RemoveAt(_stack.Count - 1);
			TypeSchema newValue = _stack.LastOrDefault();
			if (newValue != null)
			{
				_currentSchema = newValue.Schema;
			}
			else
			{
				_currentSchema = null;
			}

			return popped;
		}
		public JsonSchemaNode Combine(JsonSchema schema)
		{
			return new JsonSchemaNode(this, schema);
		}
		private void Push(TypeSchema typeSchema)
		{
			_currentSchema = typeSchema.Schema;
			_stack.Add(typeSchema);
			_resolver.LoadedSchemas.Add(typeSchema.Schema);
		}
		/// <summary>
		/// Determines whether the <see cref="JToken"/> is valid.
		/// </summary>
		/// <param name="source">The source <see cref="JToken"/> to test.</param>
		/// <param name="schema">The schema to test with.</param>
		/// <returns>
		/// 	<c>true</c> if the specified <see cref="JToken"/> is valid; otherwise, <c>false</c>.
		/// </returns>
		public static bool IsValid(this JToken source, JsonSchema schema)
		{
			bool valid = true;
			source.Validate(schema, (sender, args) => { valid = false; });
			return valid;
		}
		private JsonSchema BuildSchema(JToken token)
		{
			var schemaObject = token as JObject;
			if (schemaObject == null)
				throw JsonException.Create(token, token.Path, "Expected object while parsing schema object, got {0}.".FormatWith(CultureInfo.InvariantCulture, token.Type));

			JToken referenceToken;
			if (schemaObject.TryGetValue(JsonSchemaConstants.ReferencePropertyName, out referenceToken))
			{
				var deferredSchema = new JsonSchema();
				deferredSchema.DeferredReference = (string) referenceToken;

				return deferredSchema;
			}

			string location = token.Path.Replace(".", "/").Replace("[", "/").Replace("]", string.Empty);
			if (!string.IsNullOrEmpty(location))
				location = "/" + location;
			location = "#" + location;

			JsonSchema existingSchema;
			if (_documentSchemas.TryGetValue(location, out existingSchema))
				return existingSchema;

			Push(new JsonSchema {Location = location});

			ProcessSchemaProperties(schemaObject);

			return Pop();
		}
		/// <summary>
		/// Validates the specified <see cref="JToken"/>.
		/// </summary>
		/// <param name="source">The source <see cref="JToken"/> to test.</param>
		/// <param name="schema">The schema to test with.</param>
		/// <param name="validationEventHandler">The validation event handler.</param>
		public static void Validate(this JToken source, JsonSchema schema, ValidationEventHandler validationEventHandler)
		{
			ValidationUtils.ArgumentNotNull(source, "source");
			ValidationUtils.ArgumentNotNull(schema, "schema");

			using (var reader = new JsonValidatingReader(source.CreateReader()))
			{
				reader.Schema = schema;
				if (validationEventHandler != null)
					reader.ValidationEventHandler += validationEventHandler;

				while (reader.Read())
				{
				}
			}
		}
		public void AddProperty(IDictionary<string, JsonSchemaNode> target, string propertyName, JsonSchema schema)
		{
			JsonSchemaNode propertyNode;
			target.TryGetValue(propertyName, out propertyNode);

			target[propertyName] = AddSchema(propertyNode, schema);
		}
		public void AddItem(JsonSchemaNode parentNode, int index, JsonSchema schema)
		{
			JsonSchemaNode existingItemNode = (parentNode.Items.Count > index) ? parentNode.Items[index] : null;

			JsonSchemaNode newItemNode = AddSchema(existingItemNode, schema);

			if (!(parentNode.Items.Count > index))
			{
				parentNode.Items.Add(newItemNode);
			}
			else
			{
				parentNode.Items[index] = newItemNode;
			}
		}
		private void WriteItems(JsonSchema schema)
		{
			if (schema.Items == null && !schema.PositionalItemsValidation)
				return;

			_writer.WritePropertyName(JsonSchemaConstants.ItemsPropertyName);

			if (!schema.PositionalItemsValidation)
			{
				if (schema.Items != null && schema.Items.Count > 0)
				{
					ReferenceOrWriteSchema(schema.Items[0]);
				}
				else
				{
					_writer.WriteStartObject();
					_writer.WriteEndObject();
				}
				return;
			}

			_writer.WriteStartArray();
			if (schema.Items != null)
			{
				foreach (var itemSchema in schema.Items)
				{
					ReferenceOrWriteSchema(itemSchema);
				}
			}
			_writer.WriteEndArray();
		}
		public void AddAdditionalProperties(JsonSchemaNode parentNode, JsonSchema schema)
		{
			parentNode.AdditionalProperties = AddSchema(parentNode.AdditionalProperties, schema);
		}
		public void WriteSchema(JsonSchema schema)
		{
			ValidationUtils.ArgumentNotNull(schema, "schema");

			if (!_resolver.LoadedSchemas.Contains(schema))
				_resolver.LoadedSchemas.Add(schema);

			_writer.WriteStartObject();
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.IdPropertyName, schema.Id);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.TitlePropertyName, schema.Title);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.DescriptionPropertyName, schema.Description);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.RequiredPropertyName, schema.Required);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.ReadOnlyPropertyName, schema.ReadOnly);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.HiddenPropertyName, schema.Hidden);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.TransientPropertyName, schema.Transient);
			if (schema.Type != null)
				WriteType(JsonSchemaConstants.TypePropertyName, _writer, schema.Type.Value);
			if (!schema.AllowAdditionalProperties)
			{
				_writer.WritePropertyName(JsonSchemaConstants.AdditionalPropertiesPropertyName);
				_writer.WriteValue(schema.AllowAdditionalProperties);
			}
			else
			{
				if (schema.AdditionalProperties != null)
				{
					_writer.WritePropertyName(JsonSchemaConstants.AdditionalPropertiesPropertyName);
					ReferenceOrWriteSchema(schema.AdditionalProperties);
				}
			}
			if (!schema.AllowAdditionalItems)
			{
				_writer.WritePropertyName(JsonSchemaConstants.AdditionalItemsPropertyName);
				_writer.WriteValue(schema.AllowAdditionalItems);
			}
			else
			{
				if (schema.AdditionalItems != null)
				{
					_writer.WritePropertyName(JsonSchemaConstants.AdditionalItemsPropertyName);
					ReferenceOrWriteSchema(schema.AdditionalItems);
				}
			}
			WriteSchemaDictionaryIfNotNull(_writer, JsonSchemaConstants.PropertiesPropertyName, schema.Properties);
			WriteSchemaDictionaryIfNotNull(_writer, JsonSchemaConstants.PatternPropertiesPropertyName, schema.PatternProperties);
			WriteItems(schema);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.MinimumPropertyName, schema.Minimum);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.MaximumPropertyName, schema.Maximum);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.ExclusiveMinimumPropertyName, schema.ExclusiveMinimum);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.ExclusiveMaximumPropertyName, schema.ExclusiveMaximum);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.MinimumLengthPropertyName, schema.MinimumLength);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.MaximumLengthPropertyName, schema.MaximumLength);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.MinimumItemsPropertyName, schema.MinimumItems);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.MaximumItemsPropertyName, schema.MaximumItems);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.DivisibleByPropertyName, schema.DivisibleBy);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.FormatPropertyName, schema.Format);
			WritePropertyIfNotNull(_writer, JsonSchemaConstants.PatternPropertyName, schema.Pattern);
			if (schema.Enum != null)
			{
				_writer.WritePropertyName(JsonSchemaConstants.EnumPropertyName);
				_writer.WriteStartArray();
				foreach (var token in schema.Enum)
				{
					token.WriteTo(_writer);
				}
				_writer.WriteEndArray();
			}
			if (schema.Default != null)
			{
				_writer.WritePropertyName(JsonSchemaConstants.DefaultPropertyName);
				schema.Default.WriteTo(_writer);
			}
			if (schema.Disallow != null)
				WriteType(JsonSchemaConstants.DisallowPropertyName, _writer, schema.Disallow.Value);
			if (schema.Extends != null && schema.Extends.Count > 0)
			{
				_writer.WritePropertyName(JsonSchemaConstants.ExtendsPropertyName);
				if (schema.Extends.Count == 1)
				{
					ReferenceOrWriteSchema(schema.Extends[0]);
				}
				else
				{
					_writer.WriteStartArray();
					foreach (var jsonSchema in schema.Extends)
					{
						ReferenceOrWriteSchema(jsonSchema);
					}
					_writer.WriteEndArray();
				}
			}
			_writer.WriteEndObject();
		}
        public void AddProperty(IDictionary <string, JsonSchemaNode> target, string propertyName, JsonSchema schema)
        {
            JsonSchemaNode propertyNode;

            target.TryGetValue(propertyName, out propertyNode);

            target[propertyName] = AddSchema(propertyNode, schema);
        }