(function() {
// shorthand aliases
var L = YAHOO.lang, _GT = ZC.Util.GetText, sprintf = ZC.Util.sprintf;
// reused to hold new validator class, to cut down the amount of repetition, and to aid with minifying the file
var oValidator;

/**
 * Core CMS components
 * @module Core
 */

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class AlphaNumericNoSpace
 */
oValidator = ZC.Core.Validator.Create("AlphaNumericNoSpace");
oValidator.prototype.sDefaultValidationMessage = _GT("Only A-Z a-z 0-9 _ and - are valid (no spaces)");
oValidator.prototype.oValidationRegex = /^([A-Za-z0-9_-])*$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class AlphaNumericSpace
 */
oValidator = ZC.Core.Validator.Create("AlphaNumericSpace");
oValidator.prototype.sDefaultValidationMessage = _GT("Only A-Z a-z 0-9 _ - and spaces are valid");
oValidator.prototype.oValidationRegex = /^([A-Za-z0-9_ -])*$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class ArrayElementCount
 */
oValidator = ZC.Core.Validator.Create("ArrayElementCount");
oValidator.prototype.sDefaultValidationMessage = _GT("Please select the appropriate number of elements.");
oValidator.prototype.Validate = function (Value, oWidget)
{
	var iMin = oWidget.aDef.MinArrayElements || 0;
	var iMax = oWidget.aDef.MaxArrayElements || 0;
	var iCount;
	
	if (L.isArray(Value))
	{
		iCount = Value.length;
	}
	else if (L.isString(Value) && Value.length)
	{
		iCount = 1;
	}
	else
	{
		iCount = 0; 	// zero length string
	}
	
	if (iCount == 0) return true;
	
	return (!((iMin && iCount < iMin) || (iMax && iCount > iMax)));
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class CompareTo
 */
oValidator = ZC.Core.Validator.Create("CompareTo");
oValidator.prototype.sDefaultValidationMessage = _GT("The selection in this field must be greater than the value of the other field.");
oValidator.prototype.Validate = function(Value, oWidget)
{
	if (L.isUndefined(oWidget.aDef.GreaterThanField) && L.isUndefined(oWidget.aDef.LessThanField))
		return true;

	var aMessages = [];
	var bValid = true;
	if (oWidget.aDef.GreaterThanField)
	{
		var aWidgets = oWidget.aDef.GreaterThanField;
		if (L.isString(aWidgets))
			aWidgets = [aWidgets];

		ZC.Util.ForEach(aWidgets, function(sGreaterThanWidgetName)
		{
			var oGreaterThanWidget = ZC.JSManager.GetWidget(sGreaterThanWidgetName);

			bValid = bValid && (Value > oGreaterThanWidget.GetValue());
			aMessages.push(sprintf(_GT("greater than the value in %s"), oGreaterThanWidget.GetCaption()));
		});
	}

	if (oWidget.aDef.LessThanField)
	{
		var aWidgets = oWidget.aDef.LessThanField;
		if (L.isString(aWidgets))
			aWidgets = [aWidgets];

		ZC.Util.ForEach(aWidgets, function(sLessThanWidgetName)
		{
			var oLessThanWidget = ZC.JSManager.GetWidget(sLessThanWidgetName);

			bValid = bValid && (Value < oLessThanWidget.GetValue());
			aMessages.push(sprintf(_GT("less than the value in %s"), oGreaterThanWidget.GetCaption()));
		});
	}

	this.sDefaultValidationMessage = sprintf(_GT("The selection must be %s"), aMessages.join(_GT(" and ")));
	return bValid;
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class DomainName
 */
oValidator = ZC.Core.Validator.Create("DomainName");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a valid domain name; e.g. www.google.com:%");
oValidator.prototype.oValidationRegex = /^[0-9a-zA-Z._-]*$/;

var sDisplayNameRegex = "[a-zA-Z\\d!#$%&'*+\\\\/=?^_`{|}~\\s-]+",
	sAddressRegex = "['A-Za-z0-9_.-]+@(['A-Za-z0-9_-]+\\.['A-Za-z0-9_.-]+)",
	sEmailRegex = "((" + sDisplayNameRegex + ")?\\s*<" + sAddressRegex + ">|" + sAddressRegex + ")?";

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class EmailAddress
 */
oValidator = ZC.Core.Validator.Create("EmailAddress");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a valid e-mail address");
oValidator.prototype.oValidationRegex = new RegExp("^(" + sEmailRegex + ")?$");

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class EmailAddresses
 */
oValidator = ZC.Core.Validator.Create("EmailAddresses");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a valid e-mail address[es] (separated with commas)");
oValidator.prototype.oValidationRegex = new RegExp("^((" + sEmailRegex + "\\s*,\\s*)*" + sEmailRegex + ")?$", "m");

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class EmailAddressesNewLineSeperated
 */
oValidator = ZC.Core.Validator.Create("EmailAddressesNewLineSeperated");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a valid e-mail address[es] (one per line)");
oValidator.prototype.oValidationRegex = new RegExp("^((" + sEmailRegex + "\\s*\\n\\s*)*" + sEmailRegex + ")?$", "m");

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class HTMLColour
 */
oValidator = ZC.Core.Validator.Create("HTMLColour");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a valid HTML colour");
oValidator.prototype.oValidationRegex = /^(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow|#[0-9A-F]{6})?$/i;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class Hex6Digits
 */
oValidator = ZC.Core.Validator.Create("Hex6Digits");
oValidator.prototype.sDefaultValidationMessage = _GT("Please ensure the data is of the format ff00aa (6 digits from 0-9 plus a,b,c,d,e and f)");
oValidator.prototype.oValidationRegex = /^([0-9A-F]{6})?$/i;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class HexHTMLColour
 */
oValidator = ZC.Core.Validator.Create("HexHTMLColour");
oValidator.prototype.sDefaultValidationMessage = _GT("Please ensure the data is of the format #ff00aa (a hash followed by 6 digits from 0-9 plus a,b,c,d,e and f)");
oValidator.prototype.oValidationRegex = /^(#[0-9A-F]{6})?$/i;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsFutureDate
 */
oValidator = ZC.Core.Validator.Create("IsFutureDate");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a date in the future.");
oValidator.prototype.Validate = function(Value, oWidget)
{
	if (!Value) return true;

	var oToday = new Date();
	if(oWidget.aDef.AllowToday)
	{
		oToday.setHours(0);
		oToday.setMinutes(0);
		oToday.setSeconds(0);
	}
	else
	{
		oToday.setHours(23);
		oToday.setMinutes(59);
		oToday.setSeconds(59);
	}

	return Value > oToday;
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsHumanAge
 */
oValidator = ZC.Core.Validator.Create("IsHumanAge");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a whole number less than 100.");
oValidator.prototype.oValidationRegex = /^\d{0,2}$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsInteger
 */
oValidator = ZC.Core.Validator.Create("IsInteger");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a whole number.");
oValidator.prototype.oValidationRegex = /^-?\d*$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsNaturalNumber
 */
oValidator = ZC.Core.Validator.Create("IsNaturalNumber");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a whole number greater than zero.");
oValidator.prototype.oValidationRegex = /^(\d*[1-9]\d*)*$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsNonNegativeInteger
 */
oValidator = ZC.Core.Validator.Create("IsNonNegativeInteger");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a whole non-negative number.");
oValidator.prototype.oValidationRegex = /^\d*$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsPositive
 */
oValidator = ZC.Core.Validator.Create("IsPositive");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a positive number.");
oValidator.prototype.oValidationRegex = /^\d*([,.]\d+)?$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class IsYear
 */
oValidator = ZC.Core.Validator.Create("IsYear");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a 4 digit year.");
oValidator.prototype.Validate = function(Value, oWidget)
{
	if(Value == '')
		return true;

	var bValid = Value.match(/^\d{4}$/);
	var iMaxYear = oWidget.aDef.MaxYear;
	var iMinYear = oWidget.aDef.MinYear;
	if (iMinYear && iMaxYear)
	{
		this.sDefaultValidationMessage = sprintf(_GT('Please enter a 4 digit year between %d and %d.'), iMinYear, iMaxYear);
		bValid = bValid && (Value >= iMinYear && Value <= iMaxYear);
	}
	else if (iMaxYear)
	{
		this.sDefaultValidationMessage = sprintf(_GT('Please enter a 4 digit year before %d.'), iMaxYear);
		bValid = bValid && (Value <= iMaxYear);

	}
	else if (iMinYear)
	{
		this.sDefaultValidationMessage = sprintf(_GT('Please enter a 4 digit year after %d.'), iMinYear);
		bValid = bValid && (Value >= iMinYear);
	}

	return bValid;
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class MassMail_AutomaticRecipients
 */
oValidator = ZC.Core.Validator.Create("MassMail_AutomaticRecipients");
oValidator.prototype.sDefaultValidationMessage = _GT('The option you have selected is invalid');
oValidator.prototype.Validate = function (Value, oWidget)
{
	var oMaxRecipientsWidget = oWidget.oForm.GetWidget('MaxRecipients');
	var oRoleWidget = oWidget.oForm.GetWidget('Role');
	var oPresetEmailsWidget = oWidget.oForm.GetWidget('PresetEmailAddresses');
	
	switch(Value)
	{
		case 1:
			if (oMaxRecipientsWidget.GetValue() == -1)
			{
				this.sDefaultValidationMessage = _GT('This option is not valid when there are no manual recipients');
				return false;
			}	
			break;
				
		case 2:
			if (oRoleWidget.GetValue() == '')
			{
				oRoleWidget.SetValid(false, _GT('You must specify a role'));
				this.sDefaultValidationMessage = _GT('You must specify a role below');
				return false;
			}	
			break;
		case 3:			
			if (oPresetEmailsWidget.GetValue() == '')
			{
				oMaxRecipientsWidget.SetValid(false, _GT('You must specify at least one email address'));
				this.sDefaultValidationMessage = _GT('You must specify at least one preset email address below');
				return false;
			}	
			break;
	}		
	return true;
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class MaxDecimalPlaces
 */
oValidator = ZC.Core.Validator.Create("MaxDecimalPlaces");
oValidator.prototype.Validate = function (Value, oWidget)
{
	this.sDefaultValidationMessage = sprintf(_GT('Please specify this value using no more than %d decimal places.'), oWidget.aDef.MaxDP);
	
	var oDPRegex = new RegExp("^\\d*([,.]\\d{1," + oWidget.aDef.MaxDP + "})?$");
	return oDPRegex.test(Value);
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class MaxLength
 */
oValidator = ZC.Core.Validator.Create("MaxLength");
oValidator.prototype.Validate = function (Value, oWidget)
{
	var iMaxLength = oWidget.aDef.MaxLength;
	this.sDefaultValidationMessage = sprintf(_GT('Please reduce this to %d  characters, it is currently at %d.'), iMaxLength, Value.length);
	
	return (Value.length <= iMaxLength);
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class NotBlank
 */
oValidator = ZC.Core.Validator.Create("NotBlank");
oValidator.prototype.sDefaultValidationMessage = _GT("Please complete this.");
oValidator.prototype.Validate = function (Value, oWidget)
{
	if (L.isUndefined(Value))
		return false;

	// if there's a length property (Strings, Arrays) then use that
	if (!L.isUndefined(Value.length))
		return Value.length > 0;

	// otherwise see if we have a toString method
	return (Value.toString) && (Value.toString().length > 0);
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class PositiveCurrency
 */
oValidator = ZC.Core.Validator.Create("PositiveCurrency");
oValidator.prototype.sDefaultValidationMessage = _GT('Please enter a number with no more than two decimal places.');
oValidator.prototype.oValidationRegex = /^\d*([.,]\d{1,2})?$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class RegEx
 */
oValidator = ZC.Core.Validator.Create("RegEx");
oValidator.prototype.sDefaultValidationMessage = _GT("Please enter a valid value");
oValidator.prototype.Validate = function(Value, oWidget)
{
	var oRE, aREMatch;

	if (Value && Value.length)
	{
		// convert to a RegExp object
		aREMatch = oWidget.GetAttrib('ValidationRegEx').match(/^(.)(.*)\1([imsxeADSUXJu]*)$/);
		if (aREMatch)
		{
			// check flags
			if (aREMatch[3].match(/[^gim]/))
			{
				YAHOO.log("Warning: ValidationRegEx on " + oWidget.sName + " contains flags not supported by Javascript; not performing client-side validation", "warn", "Core_Validator_RegEx");
				return true;
			}

			oRE = new RegExp(aREMatch[2], aREMatch[3]);
			if (oRE)
			{
				return oRE.test(Value);
			}
			else
			{
				YAHOO.log("Error instantiating regexp object", "error", "Core_Validator_RegEx");
				return true;
			}
		}
		else
		{
			YAHOO.log("Warning: Could not parse ValidationRegEx on " + oWidget.sName + "; not performing client-side validation", "warn", "Core_Validator_RegEx");
			return true;
		}
	}

	return true;
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class Regex_Multiline
 */
oValidator = ZC.Core.Validator.Create("Regex_Multiline");
oValidator.prototype.sDefaultValidationMessage = _GT("One or more lines are in an invalid format");
oValidator.prototype.Validate = function (Value, oWidget)
{
	var sRegex = oWidget.aDef.Validator_Regex_Multiline;
	if (!sRegex)
		return true;
	var oRegex = new RegExp(sRegex);

	var aLines = Value.split(/\n/);
	return !ZC.Util.Some(aLines, function(sLine)
	{
		sLine = sLine.replace(/(^\s*|\s$)/g, '');
		return (sLine.length && !oRegex.test(sLine));
	});
}

var sSMSNumberRegexp = "[1-9]\\d{8,15}";
/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class SMSNumber
 */
oValidator = ZC.Core.Validator.Create("SMSNumber");
oValidator.prototype.sDefaultValidationMessage = _GT('Please enter a valid international number including the country code.  UK mobile numbers start with 44 and omit the first 0.');
oValidator.prototype.oValidationRegex = new RegExp('^(' + sSMSNumberRegexp + ')?$');

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class SMSNumbers
 */
oValidator = ZC.Core.Validator.Create("SMSNumbers");
oValidator.prototype.sDefaultValidationMessage = _GT('Please enter valid international numbers including the country code, separated by commas or newlines.');
oValidator.prototype.oValidationRegex = new RegExp('^(' + sSMSNumberRegexp + "([,\\n]" + sSMSNumberRegexp + ")*)?$");

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class SelectMinMax
 */
oValidator = ZC.Core.Validator.Create("SelectMinMax");
oValidator.prototype.sDefaultValidationMessage = _GT('You must select at least 1 and no more than 3 counties');
oValidator.prototype.Validate = function (Value, oWidget)
{
	if (Value instanceof Array)
	{
		var iMin = oWidget.aDef.SelectMin || 0;
		var iMax = oWidget.aDef.SelectMax || 0;
		
		if (iMax > 0)
			this.sDefaultValidationMessage = sprintf(_GT("You must select at least %d and no more than %d."), iMin, iMax);
		else
			this.sDefaultValidationMessage = sprintf(_GT("You must select at least %d."), iMin);
	
		if (Value.length >= iMin && (iMax == 0 || Value.length <= iMax))
			return true;
	}
	return false;	
}

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class TelephoneNumber
 */
oValidator = ZC.Core.Validator.Create("TelephoneNumber");
oValidator.prototype.sDefaultValidationMessage = _GT('Please enter a valid telephone number excluding the country code.');
oValidator.prototype.oValidationRegex = /^[^a-zA-Z]*$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class TwoTokensValidator
 */
oValidator = ZC.Core.Validator.Create("TwoTokensValidator");
oValidator.prototype.sDefaultValidationMessage = _GT('A maximum of two words is allowed');
oValidator.prototype.oValidationRegex = /^(\S+( \S+)?)?$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class URL
 */
oValidator = ZC.Core.Validator.Create("URL");
oValidator.prototype.sDefaultValidationMessage = _GT('Please enter a valid URL beginning http://');
oValidator.prototype.oValidationRegex = /^(https?:\/\/\S+)?$/;

/**
 * @namespace ZC.Core.Validator
 * @extends ZC.Core.Validator
 * @class WhiteSpaceSeparatedIntegers
 */
oValidator = ZC.Core.Validator.Create("WhiteSpaceSeparatedIntegers");
oValidator.prototype.sDefaultValidationMessage = _GT('Please enter one or more whole numbers separated by a space e.g. "1 2 3".');
oValidator.prototype.oValidationRegex = /^(\d+\s+)*$/;

})();

