using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using Telerik.Data.Expressions;
using Telerik.WinControls;
using Telerik.WinControls.Data;
using Telerik.WinControls.Design;
using Telerik.WinControls.UI;

namespace Pilz.UI.Telerik.Controls.RadValidationProvider;

/// <summary>
/// Provides a validation management for RadControl descendant editors.
/// </summary>
[ToolboxItem(true)]
[TelerikToolboxCategory(ToolboxGroupStrings.EditorsGroup)]
[Designer(DesignerConsts.RadValidationProviderDesignerString)]
[ProvideProperty("ValidationRule", typeof(RadControl))]
[ProvideProperty("IconAlignment", typeof(RadControl))]
[ProvideProperty("IconPadding", typeof(RadControl))]
public class RadValidationProviderEx : Component, ISupportInitialize, IExtenderProvider
{
    #region Externs     

    [DllImport("user32.dll", EntryPoint = "GetClassLong")]
    private static extern int GetClassLong(nint hWnd, int nIndex);
    [DllImport("user32.dll", EntryPoint = "SetClassLong")]
    private static extern int SetClassLong(nint hWnd, int nIndex, int dwNewLong);
    #endregion

    #region  Fields        

    private FilterDescriptorCollection validationRules = [];
    private ValidationMode validationMode = ValidationMode.OnValidating;
    private Dictionary<RadControl, ErrorIconAlignment> errorIconAlignments = [];
    private Dictionary<RadControl, Padding> errorIconPadding = [];
    private Dictionary<RadControl, ToolTip> controlsToToolTips = [];

    #endregion

    #region Properties

    /// <summary>
    /// Occurs before a RadControl is being validated.
    /// </summary>
    public event RadValidationEventHandlerEx ControlValidation;

    /// <summary>
    /// Occurs when the ValidionMode property changed.
    /// </summary>
    public event EventHandler ValidationModeChanged;

    /// <summary>
    /// Gets or Sets the ValidationMode.
    /// </summary>
    [DefaultValue(typeof(ValidationMode), "OnValidating")]
    public ValidationMode ValidationMode
    {
        get { return validationMode; }
        set
        {
            if (validationMode != value)
            {
                validationMode = value;
                CallOnValidationChanged();
            }
        }
    }

    /// <summary>
    /// Gets or Sets the collection of ValidationRules that belongs to this RadValidationProvider.
    /// </summary>
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    Editor(DesignerConsts.RadValidationProviderItemCollectionDesignerString, typeof(UITypeEditor)),
    Category(RadDesignCategory.DataCategory)]
    [Description("Gets a collection representing the Conditions in this ValidationProvider.")]
    public FilterDescriptorCollection ValidationRules
    {
        get
        {
            return validationRules;
        }
        set
        {
            validationRules = value;
        }
    }
    #endregion

    #region Cstor

    /// <summary>
    ///   Initializes a new instance of the RadValidationProvider class.
    /// </summary>
    public RadValidationProviderEx()
    {
        validationRules.PropertyChanged += ValidationRules_PropertyChanged;
    }

    /// <summary>
    ///   <para>Initializes a new instance of the RadValidationProvider class with the specified container control.</para>
    /// </summary>
    /// <param name="container">An object that implements the <see cref="T:System.ComponentModel.IContainer" /> interface, and owns the created object.</param>
    public RadValidationProviderEx(IContainer container) : this()
    {
        container.Add(this);
    }

    #endregion

    #region Public methods

    /// <summary>
    /// Remove a specific RadControl from the validation rules.
    /// </summary>
    /// <param name="editorControl">A RadControl descendant.</param>
    public void RemoveControlFromRules(RadControl editorControl)
    {
        foreach (IRadValidationRuleEx rule in ValidationRules)
        {
            RemoveValidationRule(editorControl, rule);
        }
    }

    /// <summary>
    /// Remove a validation rule associated with the specified RadControl descendant.
    /// </summary>
    /// <param name="editorControl">A RadControl descendant.</param>
    /// <param name="ruleToRemove">Rule to remove.</param>
    public void RemoveValidationRule(RadControl editorControl, IRadValidationRuleEx ruleToRemove)
    {
        ruleToRemove.RemoveControl(editorControl);
    }

    public void BeginInit()
    {
    }

    public void EndInit()
    {
        EnsureEventSubscribe();
    }

    /// <summary>
    /// Validates all editors associated with the RadControl.
    /// </summary>
    /// <returns>true if all editors has been successfully validated; otherwise false.</returns>
    public bool ValidateAll()
    {
        var valid = true;

        AssociatedControls.ForEach(control =>
        {
            if (!Validate(control))
                valid = false;
        });

        return valid;
    }

    /// <summary>
    /// Validates the specified editor associated with the RadControl.
    /// </summary>
    /// <param name="control">A RadControl or descendant that represents the editor to be validated.</param>
    /// <returns>true if the editor has been successfully validated; otherwise false.</returns>
    public bool Validate(RadControl control)
    {
        return ValidateCore(control, EventArgs.Empty);
    }

    /// <summary>
    ///   <para>Sets the alignment of an error icon for the specified control.</para>
    /// </summary>
    /// <param name="control">A target RadControl.</param>
    /// <param name="errorIconAlignment">An <see cref="T:System.Windows.Forms.ErrorIconAlignment" /> value that specifies the alignment to be set for the RadControl.</param>

    public void SetIconAlignment(RadControl control, ErrorIconAlignment errorIconAlignment)
    {
        if (!errorIconAlignments.ContainsKey(control))
            errorIconAlignments.Add(control, errorIconAlignment);
        else
        {
            errorIconAlignments[control] = errorIconAlignment;
        }
    }

    /// <summary>
    ///   <para>Get the alignment of an error icon for the specified RadControl.</para>
    /// </summary>
    /// <param name="control">A target control.</param>
    /// <returns>An <see cref="T:System.Windows.Forms.ErrorIconAlignment" /> value.</returns>
    [DefaultValue(ErrorIconAlignment.MiddleRight)]
    public ErrorIconAlignment GetIconAlignment(RadControl control)
    {
        if (errorIconAlignments.ContainsKey(control))
            return errorIconAlignments[control];

        return ErrorIconAlignment.MiddleRight;
    }

    /// <summary>Sets the amount of extra space to leave between the specified control and the error icon.</summary>
    /// <param name="control">The <paramref name="control" /> to set the padding for. </param>
    /// <param name="errorIconPadding">The padding to add between the icon and the <paramref name="control" />. </param>
    public void SetIconPadding(RadControl control, Padding errorIconPadding)
    {
        if (!this.errorIconPadding.ContainsKey(control))
            this.errorIconPadding.Add(control, errorIconPadding);
        else
        {
            this.errorIconPadding[control] = errorIconPadding;
        }
    }

    /// <summary>Returns the amount of extra space to leave next to the error icon.</summary>
    /// <returns>The padding to leave between the icon and the control. </returns>
    /// <param name="control">The control to get the padding for. </param>
    [DefaultValue(typeof(Padding), "1, 1, 1, 1")]
    public Padding GetIconPadding(RadControl control)
    {
        if (errorIconPadding.ContainsKey(control))
            return errorIconPadding[control];

        return new Padding(1);
    }
    protected virtual void OnControlValidation(RadValidationEventArgsEx e)
    {
        if (ControlValidation != null)
            ControlValidation(this, e);
    }

    private void ValidationRules_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Item[]")
            EnsureEventSubscribe();
    }

    /// <summary>
    /// Removes a rules associated with the control.
    /// </summary>
    /// <param name="control">A RadControl descendant</param>
    public void RemoveRules(RadControl control)
    {
        for (var i = validationRules.Count - 1; i >= 0; i--)
        {
            if (((IRadValidationRuleEx)validationRules[i]).Controls.Contains(control))
                validationRules.RemoveAt(i);
        }
    }

    /// <summary>
    /// Gets the collection of the controls whose values are validated.
    /// </summary>
    [Browsable(false)]
    public List<RadControl> AssociatedControls
    {
        get => [.. ValidationRules.OfType<IRadValidationRuleEx>().SelectMany(n => n.Controls).OfType<RadControl>()];
    }

    /// <summary>
    /// Clear the visual indication for the validation error.
    /// </summary>
    public virtual void ClearErrorStatus()
    {
        var controls = AssociatedControls;
        for (var i = 0; i < controls.Count; i++)
        {
            ClearErrorStatus(controls[i]);
        }
    }

    /// <summary>
    /// Clear the visual indication for the validation error.
    /// </summary>
    /// <param name="associatedControl">A RadControl descendant</param>
    public virtual void ClearErrorStatus(RadControl associatedControl)
    {
        var children = associatedControl.RootElement.Children;
        if (children.Count == 0)
            return;

        var editorControl = associatedControl;
        var controlElement = TryFindControlElement(children);//first non ValidationIconElement is a Main Element for the Control.
        if (controlElement == null)
            return;

        var border = ValidationHelperElement.GetBorder(children);

        ValidationHelperElement.RestoreBorderColor(border);
        associatedControl.ElementTree.ApplyThemeToElementTree();
        for (var i = children.Count - 1; i >= 0; --i)
        {
            if (associatedControl.RootElement.Children[i] is ValidationHelperElement)
                associatedControl.RootElement.Children.RemoveAt(i);
        }

        controlElement.PositionOffset = new SizeF();
        controlElement.MaxSize = new Size();
        associatedControl.RootElement.InvalidateMeasure(true);
        associatedControl.RootElement.UpdateLayout();
    }


    #endregion

    #region Private methods

    private void AssociatedControl_TextChanged(object sender, EventArgs e)
    {
        if (ValidationMode == ValidationMode.OnTextChange)
            ValidateCore(sender, e);
    }

    private void AssociatedControl_Validating(object sender, CancelEventArgs e)
    {
        if (ValidationMode == ValidationMode.OnValidating)
            ValidateCore(sender, e);
    }

    internal static object GetSubPropertyValue(object control, string fieldName)
    {
        var names = fieldName.Split('.');
        if (names.Length < 2)
            return control.GetType().GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(control, null);

        var innerValue = control.GetType().GetProperty(names[0], BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(control, null);
        var index = 1;
        while (index < names.Length && innerValue != null)
        {
            innerValue = innerValue.GetType().GetProperty(names[index], BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(innerValue, null);
            index++;
        }

        return innerValue;
    }

    private bool ValidateCore(object sender, EventArgs e)
    {
        var control = sender as Control;

        foreach (IRadValidationRuleEx ruleToEvaluete in ValidationRules)
        {
            if (!ruleToEvaluete.Controls.Contains(control))
                continue;

            var context = new ExpressionContext();
            context.Clear();
            var value = GetSubPropertyValue(control, ruleToEvaluete.PropertyName);//control.GetType().GetProperty(ruleToEvaluete.PropertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(control, null);
            if (value != null && ruleToEvaluete.Value != null)
            {
                try
                {
                    // Fix for 441010
                    // Try to retrieve Culture from the control
                    var cultureInfo = RetrieveCulture(control);
                    value = Convert.ChangeType(value, ruleToEvaluete.Value.GetType(), cultureInfo);
                }
                catch
                { }
            }

            context.Add(ruleToEvaluete.PropertyName, value);

            if (string.IsNullOrEmpty(ruleToEvaluete.Expression))
                continue;

            var node = DataUtils.Parse(ruleToEvaluete.Expression, ruleToEvaluete.CaseSensitive);
            var result = node.Eval(null, context);

            if (result is bool)
            {
                var boolResult = (bool)result;
                var validationEventArgs = FireValidationEvent(!boolResult, (RadControl)sender, ruleToEvaluete);
                if (validationEventArgs.DisplayIconAndToolTip)
                    boolResult = AddOrRemoveImage(validationEventArgs, (RadControl)sender, ruleToEvaluete);
                else
                {
                    boolResult = validationEventArgs.IsValid;
                }

                var cancelEventArgs = e as CancelEventArgs;
                if (cancelEventArgs != null)
                    cancelEventArgs.Cancel = !boolResult;

                if (!boolResult)
                    return false;
            }
        }

        return true;
    }

    private bool AddOrRemoveImage(RadValidationEventArgsEx validationEventArgs, RadControl associatedControl, IRadValidationRuleEx rule)
    {
        var children = associatedControl.RootElement.Children;
        if (children.Count == 0)
            return true;

        var editorControl = associatedControl;
        var controlElement = TryFindControlElement(children);//first non ValidationIconElement is a Main Element for the Control.
        if (controlElement == null)
            return true;

        var element = validationEventArgs.ValidationHelperElement;
        var border = ValidationHelperElement.GetBorder(children);

        var truncateSize = false;
        if (!validationEventArgs.IsValid)
        {
            element ??= new ValidationHelperElement();

            if (!children.Contains(element))
                truncateSize = true;//size of the control should be truncate

            element.ToolTipText = validationEventArgs.ErrorText;
            element.AutoToolTip = true;
            element.StretchHorizontally =
            element.StretchVertically = false;
            element.Image = validationEventArgs.ErrorImage;
            element.SvgImage = validationEventArgs.ErrorSvgImage;
            element.Alignment = ToContentAligment(GetIconAlignment(editorControl));
            element.Padding = GetIconPadding(editorControl);
            if (truncateSize)
            {
                var elementSize = TelerikDpiHelper.ScaleSizeF(MeasurementControl.ThreadInstance.GetDesiredSize(element, new SizeF(float.MaxValue, float.MaxValue)), controlElement.DpiScaleFactor);
                var width = (controlElement.Size.Width - elementSize.Width) / controlElement.DpiScaleFactor.Width;
                controlElement.MaxSize = new Size((int)width, controlElement.MaxSize.Height);

                associatedControl.RootElement.ResetValue(VisualElement.BackColorProperty, ValueResetFlags.Style);
                if (element.IsRightLocated)
                    children.Add(element);
                else
                {
                    controlElement.PositionOffset = new SizeF(elementSize.Width, 0);
                    children.Insert(0, element);
                }
            }

            ValidationHelperElement.SetBorderColor(border);
            if (rule.AutoToolTip)
            {
                var toolTipX = validationEventArgs.ToolTipX.HasValue ? validationEventArgs.ToolTipX.Value : 0;
                var toolTipY = validationEventArgs.ToolTipY.HasValue ? validationEventArgs.ToolTipY.Value : associatedControl.Height + 1;
                var toolTipDuration = validationEventArgs.ToolTipDuration.HasValue ? validationEventArgs.ToolTipDuration.Value : 2000;

                if (validationEventArgs.ToolTip != null)
                {
                    associatedControl.Disposed -= AssociatedControl_Disposed;
                    associatedControl.Disposed += AssociatedControl_Disposed;
                    if (controlsToToolTips.ContainsKey(associatedControl))
                        controlsToToolTips[associatedControl] = validationEventArgs.ToolTip;
                    else
                    {
                        controlsToToolTips.Add(associatedControl, validationEventArgs.ToolTip);
                    }

                    if (!validationEventArgs.EnableToolTipShadow)
                        ToolTipRemoveShadow(validationEventArgs.ToolTip);
                    validationEventArgs.ToolTip.Show(element.ToolTipText, associatedControl, toolTipX, toolTipY, toolTipDuration);
                }
                else
                {
                    ShowToolTip(associatedControl, element.ToolTipText, validationEventArgs.ErrorTitle, toolTipX, toolTipY, toolTipDuration, validationEventArgs.EnableToolTipShadow);
                }
            }
        }
        else
        {
            ValidationHelperElement.RestoreBorderColor(border);
            associatedControl.ElementTree.ApplyThemeToElementTree();
            for (var i = children.Count - 1; i >= 0; --i)
            {
                if (associatedControl.RootElement.Children[i] is ValidationHelperElement)
                    associatedControl.RootElement.Children.RemoveAt(i);
            }

            controlElement.PositionOffset = new SizeF();
            controlElement.MaxSize = new Size();
        }

        associatedControl.RootElement.InvalidateMeasure(true);
        associatedControl.RootElement.UpdateLayout();
        associatedControl.Refresh();
        return validationEventArgs.IsValid;
    }

    private void ToolTipRemoveShadow(ToolTip toolTip)
    {
        var hwnd = (nint)typeof(ToolTip).GetProperty("Handle",
            BindingFlags.NonPublic |
            BindingFlags.Instance).GetValue(toolTip, null);
        var cs = GetClassLong(hwnd, NativeMethods.GCL_STYLE);
        if ((cs & NativeMethods.CS_DROPSHADOW) == NativeMethods.CS_DROPSHADOW)
        {
            cs &= ~NativeMethods.CS_DROPSHADOW;
            SetClassLong(hwnd, NativeMethods.GCL_STYLE, cs);
        }
    }

    private void AssociatedControl_Disposed(object sender, EventArgs e)
    {
        var radControl = sender as RadControl;
        radControl.Disposed -= AssociatedControl_Disposed;
        if (radControl != null && controlsToToolTips.ContainsKey(radControl))
        {
            var toolTip = controlsToToolTips[radControl];
            if (toolTip != null)
            {
                controlsToToolTips.Remove(radControl);
                toolTip.Dispose();
                toolTip = null;
            }
        }
    }

    protected virtual void ShowToolTip(RadControl associatedControl, string toolTipText, string toolTipTitle, int toolTipX, int toolTipY, int toolTipDuration, bool enableToolTipShadow)
    {
        var toolTip = new ToolTip
        {
            ToolTipTitle = toolTipTitle,

            BackColor = Color.Red,
            ForeColor = Color.White,
            OwnerDraw = true,
            InitialDelay = 0,
            AutoPopDelay = toolTipDuration
        };
        if (!enableToolTipShadow)
            ToolTipRemoveShadow(toolTip);

        toolTip.Draw += delegate (object sender, DrawToolTipEventArgs e)
        {
            e.DrawBackground();
            e.DrawBorder();
            using (var brush = new SolidBrush(Color.White))
            using (var titleFont = new Font("Segoe UI", 8f, FontStyle.Bold))
            using (var textFont = new Font("Segoe UI", 8f, FontStyle.Regular))
            {
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                if (!string.IsNullOrEmpty(toolTipTitle))
                {
                    e.Graphics.DrawString(toolTipTitle, titleFont, brush, new Point(2, 2));
                    e.Graphics.DrawString(toolTipText, textFont, brush, new Point(2, 19));
                }
                else
                {
                    e.Graphics.DrawString(toolTipText, textFont, brush, new Point(2, 2));
                }
            }
        };

        if (controlsToToolTips.ContainsKey(associatedControl))
            controlsToToolTips[associatedControl] = toolTip;
        else
        {
            controlsToToolTips.Add(associatedControl, toolTip);
        }

        associatedControl.Disposed -= AssociatedControl_Disposed;
        associatedControl.Disposed += AssociatedControl_Disposed;

        toolTip.Show(toolTipText, associatedControl, toolTipX, toolTipY, toolTipDuration);
    }

    private ContentAlignment ToContentAligment(ErrorIconAlignment errorIconAlignment)
    {
        switch (errorIconAlignment)
        {
            case ErrorIconAlignment.TopLeft:
                return ContentAlignment.TopLeft;
            case ErrorIconAlignment.TopRight:
                return ContentAlignment.TopRight;
            case ErrorIconAlignment.MiddleLeft:
                return ContentAlignment.MiddleLeft;
            case ErrorIconAlignment.MiddleRight:
                return ContentAlignment.MiddleRight;
            case ErrorIconAlignment.BottomLeft:
                return ContentAlignment.BottomLeft;
            case ErrorIconAlignment.BottomRight:
                return ContentAlignment.BottomRight;
            default:
                return ContentAlignment.MiddleRight;
        }
    }

    private static RadElement TryFindControlElement(RadElementCollection children)
    {
        RadElement controlElement = null;
        foreach (var child in children)
        {
            if (child is not ValidationHelperElement)
            {
                controlElement = child;
                break;
            }
        }

        return controlElement;
    }

    protected virtual RadValidationEventArgsEx FireValidationEvent(bool isNotValid, RadControl associatedControl, IRadValidationRuleEx rule)
    {
        Image image = ResourceHelper.ImageFromResource(typeof(global::Telerik.WinControls.UI.RadValidationProvider), "Telerik.WinControls.UI.Resources.error-icon.png");
        var errorText = string.IsNullOrEmpty(rule.ToolTipText) ? rule.Expression : rule.ToolTipText;
        var validationEventArgs = new RadValidationEventArgsEx(associatedControl, image, errorText, rule.ToolTipTitle, rule, isNotValid)
        {
            ValidationHelperElement = ValidationHelperElement.GetValidationElement(associatedControl.RootElement.Children)
        };
        validationEventArgs.ValidationHelperElement ??= new ValidationHelperElement();

        OnControlValidation(validationEventArgs);
        return validationEventArgs;
    }

    private void EnsureEventSubscribe()
    {
        foreach (IRadValidationRuleEx rule in ValidationRules)
        {
            var controls = rule.Controls;
            foreach (var control in controls)
            {
                if (control != null)
                {
                    control.Validating -= AssociatedControl_Validating;
                    control.Validating += AssociatedControl_Validating;
                    control.TextChanged -= AssociatedControl_TextChanged;
                    control.TextChanged += AssociatedControl_TextChanged;
                }
            }
        }
    }

    private void CallOnValidationChanged()
    {
        if (ValidationModeChanged != null)
            ValidationModeChanged(this, EventArgs.Empty);
    }

    private CultureInfo RetrieveCulture(Control control)
    {
        var cultureProperty = control.GetType().GetProperty("Culture", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        if (cultureProperty != null)
        {
            var cultureObject = cultureProperty.GetValue(control, null);
            if (cultureObject != null && cultureObject is CultureInfo)
                return cultureObject as CultureInfo;
        }

        return CultureInfo.CurrentCulture;
    }

    #endregion

    #region ExtenderProvider Interface implementation

    /// <summary>
    ///   <para>Indicates whether a control can be extended.</para>
    /// </summary>
    /// <param name="extendee">The control to be extended.</param>
    /// <returns>true if the control can be extended otherwise false.</returns>
    public bool CanExtend(object extendee)
    {
        return extendee is RadControl;
    }

    /// <summary>
    ///   <para>Associates a validation rule with the specified RadControl descendant.</para>
    /// </summary>
    /// <param name="control">A RadControl descendant that represents the editor.</param>
    /// <param name="rule">A RadValidationRule descendant that represents the validation rule.</param>
    [Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
    public void SetValidationRule(RadControl control, FilterDescriptor rule)
    {
        if (rule is not IRadValidationRuleEx radValidationRule)
            RemoveControlFromRules(control);
        else
        {
            radValidationRule.AddControl(control);
            if (!validationRules.Contains(rule))
                validationRules.Add(rule);
        }
    }

    /// <summary>
    ///   <para>Associates a validation rule with the specified RadControls descendant.</para>
    /// </summary>
    /// <param name="controls">A RadControl collection descendant that represents the editors.</param>
    /// <param name="rule">A RadValidationRule descendant that represents the validation rule.</param>
    [Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
    public void SetValidationRule(IEnumerable controls, FilterDescriptor rule)
    {
        SetValidationRule(controls.OfType<RadControl>(), rule);
    }

    /// <summary>
    ///   <para>Associates a validation rule with the specified RadControls descendant.</para>
    /// </summary>
    /// <param name="controls">A RadControl collection descendant that represents the editors.</param>
    /// <param name="rule">A RadValidationRule descendant that represents the validation rule.</param>
    [Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
    public void SetValidationRule(IEnumerable<RadControl> controls, FilterDescriptor rule)
    {
        foreach (var control in controls)
            SetValidationRule(control, rule);
    }

    /// <summary>
    ///   <para>Returns a validation rule associated with the specified RadControl descendant.</para>
    /// </summary>
    /// <param name="control">A RadControl descendant.</param>
    /// <returns>A RadValidationRule descendant that represents the validation rule associated with the editor. Null if no validation rule is associated with the specified control.</returns>

    [Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
    public FilterDescriptor GetValidationRule(RadControl control)
    {
        IRadValidationRuleEx ruleToEvaluete = null;
        foreach (IRadValidationRuleEx rule in ValidationRules)
        {
            if (rule.Controls.Contains(control))
            {
                ruleToEvaluete = rule;
                break;
            }
        }

        return ruleToEvaluete as FilterDescriptor;
    }
    #endregion
}
