using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Windows.Forms;

namespace EnterpriseDesktop.Common.WinForm
{
	/// <summary>
    /// Author:  Keith Elder, keith@dotnetpimps.net
	/// This class assists in validating a Control.ControlCollection.  Most Windows.Forms have controls placed on them. 
	/// Simply pass in the this.Controls object to the constructor.   Any control on the form
    /// that has error providers, even nested controls will be found.  Should be
    /// called before saving a form to make sure all errors have been addressed.
	/// </summary>
	/// <example>
	/// FormValidation valContactForm = new FormValidation(this.Controls, _errorProvider);
	/// if (valContactForm.FoundError)
	/// {
	/// valContactForm.ShowErrors();
	/// } else
	/// {
	///   SaveForm(); // abstract method to save your form or something
	/// }
	/// </example>
	public class FormValidation
	{
		/// <summary>
		/// Arraylist of errors that were found.
		/// </summary>
		private ArrayList _errors = new ArrayList();
		public ArrayList Errors
		{
			get
			{
				return this._errors;
			}
		}

		private ErrorProvider _errorProvider = null;
		public ErrorProvider ErrorProvider
		{
			get
			{
				if (this._errorProvider == null)
				{
					throw new NullReferenceException("ErrorProvider is null.");
				}
				return this._errorProvider;
			}
			set
			{
				this._errorProvider = value;
			}
		}

		/// <summary>
		/// Current error of the control being checked.
		/// </summary>
		private string _currentError = "";

		/// <summary>
		/// The control collection that is being checked for errors.
		/// All control collections are checked to see if any sub controls
		/// contain any errors.
		/// </summary>
		private Control.ControlCollection _controlCollection = null;
		public Control.ControlCollection ControlCollection
		{
			get
			{
				if (this._controlCollection == null)
				{
					throw new NullReferenceException("ControlCollection is null.");
				}
				return this._controlCollection;
			}
			set
			{
				this._controlCollection = value;
			}
		}

		/// <summary>
		/// Returns true if any errors are found.
		/// </summary>
		private bool _foundError = false;
		public bool FoundError
		{
			get
			{
				if (this._errors.Count > 0)
				{
					return true;
				}
				return false;
			}
			set
			{
				this._foundError = value;
			}
		}

		/// <summary>
		/// Constructor used if you don't want to pass params in at instantiation.
		/// </summary>
		public FormValidation()
		{

		}

		/// <summary>
		/// Contructor
		/// </summary>
		/// <param name="controls">Control.ControlCollection</param>
		/// <param name="provider">ErroProvider</param>
		public FormValidation(Control.ControlCollection controls, ErrorProvider provider)
		{
			this._controlCollection = controls;
			this._errorProvider = provider;
			this.GetErrors();
		}

		/// <summary>
		/// Used to process errors.  If one of the override methods is used
		/// where nothing is passed to the constructor then this has to be called to 
		/// process the errors.  You should use FoundError to determine if there were any errors after 
		/// running GetErrors.
		/// </summary>
		/// <returns></returns>
		public ArrayList GetErrors()
		{
			if (this._controlCollection != null)
			{
				ErrorCheckControls(this._controlCollection);
			}
			else
			{
				throw new NullReferenceException("No control collection found.");
			}
			return Errors;
		}

		/// <summary>
		/// Loops through the controls collection and finds the controls that have 
		/// an error assigned to them and adds them to _errors (arraylist).
		/// </summary>
		/// <param name="controls"></param>
		/// <returns></returns>
		private void ErrorCheckControls(Control.ControlCollection controls)
		{
			foreach (Control ctl in controls)
			{
				if (ctl.HasChildren)
				{
					ErrorCheckControls(ctl.Controls);
				}
				if (ctl is TextBox || ctl is MaskedTextBox || ctl is ComboBox || ctl is RichTextBox)
				{
					if (_errorProvider.GetError(ctl).ToString().Length > 0)
					{
						this._currentError = _errorProvider.GetError(ctl).ToString();
						if (!_errors.Contains(_currentError))
						{
							_errors.Add(_currentError);
						}
					}
				}
			}
		}

		/// <summary>
		/// Takes all of the errors that have been added to the _errors array list
		/// and dipslays them in a messagebox.
		/// </summary>
		public void ShowErrors()
		{
			string completeError = "";
			foreach (string error in this._errors)
			{
                ///Added replace to strip out extra &s -- for tooltip that says "= or & not allowed"
				completeError += error.Replace("&&&","&") + "\n";
			}

			MessageBox.Show(completeError, "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}

        public bool ErrorInControlCollection(Control.ControlCollection cc)
        {            
            foreach (Control ctl in cc)
            {
                if (ctl.HasChildren)
                {
                    if (ErrorInControlCollection(ctl.Controls))
                    {
                        return true;
                    }
                }
                if (ctl is TextBox || ctl is MaskedTextBox || ctl is ComboBox || ctl is RichTextBox)
                {
                    if (_errorProvider.GetError(ctl).ToString().Length > 0)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
	}
}