<commit_before>﻿using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Runtime.Serialization;
using ExoGraph;
using System.ComponentModel.DataAnnotations;
using System.Collections;
using ExoRule;

namespace ExoWeb
{
	public enum ClientRuleType
	{
		unsupported,
		required,
		range,
		stringLength,
		allowedValues
	}

	#region Rule

	[DataContract]
	public abstract class Rule : ExoRule.Rule
	{
		protected Rule(GraphType type, string name)
			: base(name)
		{
			this.Type = type;
		}

		[DataMember(Name = "rootType")]
		public string RootType
		{
			get { return Type.Name; }
			set{}
		}

		public GraphType Type { get; private set; }
	}

	#endregion

	/// <summary>
	/// Abstract baseclass for <see cref="ExoRule.Rule"/> that is
	/// understood by client ExoWeb libraries.  Since behavior is well known,
	/// <see cref="Rule"/> and it's subclasses need not specify an <see cref="Action&lt;T&gt;"/>,
	/// merely any information required to perform the action.
	/// </summary>
	[DataContract]
	public abstract class PropertyRule : Rule
	{
		public PropertyRule(GraphProperty graphProperty, ConditionType conditionType, ClientRuleType clientRuleType)
			: base(graphProperty.DeclaringType, string.Format("{0}.{1}.{2}", graphProperty.DeclaringType.Name, graphProperty.Name, clientRuleType.ToString()))
		{
			this.ClientRuleType = clientRuleType;
			this.GraphProperty = graphProperty;
			this.ConditionType = conditionType;
			ConditionType.ConditionRule = this;
		}

		[DataMember(Name = "properties")]
		private string[] Properties 
		{
			get
			{
				return new string[] { GraphProperty.IsStatic ? GraphProperty.Name : "this." + GraphProperty.Name };
			}
			set { }
		}

		[DataMember(Name = "clientRuleType")]
		private string _ClientRuleType
		{
			get
			{
				return this.ClientRuleType.ToString();
			}
			set { }
		}

		public ClientRuleType ClientRuleType { get; protected set; }

		/// <summary>
		/// A <see cref="ConditionType"/> that will associated with a graph when
		/// CheckCondition returns true;
		/// </summary>
		public ConditionType ConditionType { get; set; }

		/// <summary>
		/// The <see cref="GraphProperty"/> representing the property that this rule
		/// will depend on and that any <see cref="ConditionTarget"/>s will target.
		/// </summary>
		public GraphProperty GraphProperty { get; set; }

		public override void Register()
		{
			Type.Init += (sender, e) =>
			{
				Invoke(e.Instance, e);
			};
		}

		protected override void Invoke(GraphInstance root, GraphEvent graphEvent)
		{
			ConditionType.When(root.Instance, () => ConditionApplies(root), GraphProperty.Name);
		}

		/// <summary>
		/// Overridden in subclasses to determine if the <see cref="ConditionType"/>
		/// applies.
		/// </summary>
		/// <returns>true if <paramref name="root"/> should be associated with the <see cref="ConditionType"/></returns>
		protected abstract bool ConditionApplies(GraphInstance root);
	}

	/// <summary>
	/// Applies conditions when the value of a <see cref="GraphProperty"/> is
	/// null or an empty list.
	/// </summary>
	[DataContract(Name = "required")]
	public class RequiredRule : PropertyRule
	{
		public RequiredRule(GraphProperty graphProperty, ConditionType conditionType)
			: base(graphProperty, conditionType, ClientRuleType.required)
		{ }
<commit_msg>Defer validation rules until property change.  Running them on init caused errors b/c some of the allowed values properties were unexpectedly invoked.<commit_after>﻿using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Runtime.Serialization;
using ExoGraph;
using System.ComponentModel.DataAnnotations;
using System.Collections;
using ExoRule;

namespace ExoWeb
{
	public enum ClientRuleType
	{
		unsupported,
		required,
		range,
		stringLength,
		allowedValues
	}

	#region Rule

	[DataContract]
	public abstract class Rule : ExoRule.Rule
	{
		protected Rule(GraphType type, string name)
			: base(name)
		{
			this.Type = type;
		}

		[DataMember(Name = "rootType")]
		public string RootType
		{
			get { return Type.Name; }
			set{}
		}

		public GraphType Type { get; private set; }
	}

	#endregion

	/// <summary>
	/// Abstract baseclass for <see cref="ExoRule.Rule"/> that is
	/// understood by client ExoWeb libraries.  Since behavior is well known,
	/// <see cref="Rule"/> and it's subclasses need not specify an <see cref="Action&lt;T&gt;"/>,
	/// merely any information required to perform the action.
	/// </summary>
	[DataContract]
	public abstract class PropertyRule : Rule
	{
		public PropertyRule(GraphProperty graphProperty, ConditionType conditionType, ClientRuleType clientRuleType)
			: base(graphProperty.DeclaringType, string.Format("{0}.{1}.{2}", graphProperty.DeclaringType.Name, graphProperty.Name, clientRuleType.ToString()))
		{
			this.ClientRuleType = clientRuleType;
			this.GraphProperty = graphProperty;
			this.ConditionType = conditionType;
			ConditionType.ConditionRule = this;
		}

		[DataMember(Name = "properties")]
		private string[] Properties 
		{
			get
			{
				return new string[] { GraphProperty.IsStatic ? GraphProperty.Name : "this." + GraphProperty.Name };
			}
			set { }
		}

		[DataMember(Name = "clientRuleType")]
		private string _ClientRuleType
		{
			get
			{
				return this.ClientRuleType.ToString();
			}
			set { }
		}

		public ClientRuleType ClientRuleType { get; protected set; }

		/// <summary>
		/// A <see cref="ConditionType"/> that will associated with a graph when
		/// CheckCondition returns true;
		/// </summary>
		public ConditionType ConditionType { get; set; }

		/// <summary>
		/// The <see cref="GraphProperty"/> representing the property that this rule
		/// will depend on and that any <see cref="ConditionTarget"/>s will target.
		/// </summary>
		public GraphProperty GraphProperty { get; set; }

		public override void Register()
		{
			if (GraphProperty is GraphReferenceProperty)
			{
				Type.ReferenceChange += (sender, e) =>
				{
					if (e.Property == this.GraphProperty)
						Invoke(e.Instance, e);
				};
			}
			else if (GraphProperty is GraphValueProperty)
			{
				Type.ValueChange += (sender, e) =>
				{
					if (e.Property == this.GraphProperty)
						Invoke(e.Instance, e);
				};
			}
		}

		protected override void Invoke(GraphInstance root, GraphEvent graphEvent)
		{
			ConditionType.When(root.Instance, () => ConditionApplies(root), GraphProperty.Name);
		}

		/// <summary>
		/// Overridden in subclasses to determine if the <see cref="ConditionType"/>
		/// applies.
		/// </summary>
		/// <returns>true if <paramref name="root"/> should be associated with the <see cref="ConditionType"/></returns>
		protected abstract bool ConditionApplies(GraphInstance root);
	}

	/// <summary>
	/// Applies conditions when the value of a <see cref="GraphProperty"/> is
	/// null or an empty list.
	/// </summary>
	[DataContract(Name = "required")]
	public class RequiredRule : PropertyRule
	{
		public RequiredRule(GraphProperty graphProperty, ConditionType conditionType)
			: base(graphProperty, conditionType, ClientRuleType.required)
		{ }

{'fraction_non_alphanumeric': 0.12023297739564553, 'fraction_numerical': 0.0008320621273055055, 'mean_word_length': 3.6499032882011604, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 52, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1820476', 'n_tokens_mistral': 2358, 'n_tokens_neox': 2087, 'n_words': 599}