/**
* Validation controls
*
* @import Web/UI/HtmlControl.js
*/

/** Base class for validators */
with(Web_UI_Validator_Base = NewClass()) 
{
	inherits(Web_UI_HtmlControl);

	// Focus on a validator means focus on target	
	prototype.focus = function() 
	{
		if (Page.findControl(this.targetId)) Page.findControl(this.targetId).focus();
	}

	// If shown on server, show now
	prototype.load = function()
	{
		if (parent.load) parent.load.call(this);
		if (this.formId) this.form = Page.findControl(this.formId);
		if (this.form) this.form.validators.add(this);
	}

	// If shown on server, show now
	prototype.render = function()
	{
		if (parent.render) parent.render.call(this);
		if (!this.isValid) this.setError();
	}
	
	// Validate the form field
	prototype.validate = function() 
	{
		if (!this.enabled) return true;
        var target = Page.findControl(this.targetId);
        if (target) {
            if (target.tag && target.tag.readOnly) return true;
            if (target.tag && target.tag.disabled) return true;
        }
		if (this.evaluateIsValid()) return true;
		if (this.errorMessage) {
			this.form.errors.add(this.errorMessage);
			if (!this.form.controlErrors[this.targetId]) this.form.controlErrors[this.targetId] = [];
			this.form.controlErrors[this.targetId].add(this.errorMessage);
		}
		this.setError();
		return false;
	}
	
	// Perform the evaluation
	prototype.evaluateIsValid = function () { return true; };
	
	// Show the error
	prototype.setError = function()
	{
        var target = Page.findControl(this.targetId);
        if (target) {
        	target.setError();
        	if (target.events.onChange) target.events.onChange.add(this.targetChange.bind(this));
        	if (target.events.onKeyPress) target.events.onKeyPress.add(this.targetChange.bind(this));
        }
	};

	// Hide the error
	prototype.clearError = function()
	{
        var target = Page.findControl(this.targetId);
        if (target) {
        	target.clearError();
        	if (target.events.onChange) target.events.onChange.remove(this.targetChange.bind(this));
        	if (target.events.onKeyPress) target.events.onKeyPress.remove(this.targetChange.bind(this));
        }
	};
	
	// Hide if the target control has changed
	prototype.targetChange = function() { this.clearError(); return true; }	
}

/** Required field validator */
with (Web_UI_Validator_Required = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Value exists
	prototype.valueExists = function()
	{	
		var target = Page.findControl(this.targetId);
		if (!target) return true;
		if (!target.exists() || !target.getValidationValue) return true;
		var value = target.getValidationValue();
		if (isNumber(value)) return true;
		return !isEmpty(value);
	}
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var group = (this.groupId) ? Page.findControl(this.groupId) : null;
		if (group && !group.valueExists()) return true;
		return this.valueExists();
	};
}

/** Required field validator */
with (Web_UI_Validator_RequiredGroup = NewClass()) 
{
	inherits(Web_UI_Control);	
	
	// Value exists
	prototype.valueExists = function()
	{
		if (!this.validators) return false;
		var control = null;
		for (var i = 0; i < this.validators.length; i++) {
			control = Page.findControl(this.validators[i]);
			if (control.valueExists()) return true;
		}
		return false;
	}
}

/** Required field validator */
with (Web_UI_Validator_Length = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var target = Page.findControl(this.targetId);
		if (!target) return true;
		if (!target.exists() || !target.getValidationValue) return true;
		var value = target.getValidationValue();
		if (!isString(value) && !isArray(value)) return false;
		if (value.length == 0) return true;
		if (this.minLength && value.length < this.minLength) return false;
		if (this.maxLength && value.length > this.maxLength) return false;
		return true;
	};
}

/** Required field validator */
with (Web_UI_Validator_RegExp = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var target = Page.findControl(this.targetId);
		if (!target) return true;
		if (!target.exists() || !target.getValidationValue) return true;
		var value = target.getValidationValue();
		if (!isString(value)) return false;
		if (value.length == 0) return true;
		if (this.regExp) {
			var reg = new RegExp('^'+this.regExp+'$');
			if (!reg.test(value)) return false;
		}
		return true;
	};
}

/** Required field validator */
with (Web_UI_Validator_Number = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var target = Page.findControl(this.targetId);
		if (!target) return true;
		if (!target.exists() || !target.getValidationValue) return true;		
		var value = target.getValidationValue();
		if (isArray(value) || value === '' || value === null) return true;
		if (this.integer) value = parseInt(value);
		else value = parseFloat(value);
		if (isNaN(value)) return false;
		if (isNumber(this.low) && value < this.low) return false;
		if (isNumber(this.high) && value > this.high) return false;
		return true;
	};
}

/** Compare field validator */
with (Web_UI_Validator_Compare = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var target = Page.findControl(this.targetId)
		if (!target) return true;
		if (!target.exists() || !target.getValidationValue) return true;
		var value1 = target.getValidationValue();
		var value2;
		if (this.sourceId) {
			var source = Page.findControl(this.sourceId)
			if (!source) return true;
			value2 = source.getValidationValue();
		} else value2 = this.value;
		switch (this.condition) {
			case '==': return (value1 == value2);
			case '!=': return (value1 != value2);
			case '>': return (value1 > value2);
			case '>=': return (value1 >= value2);
			case '<': return (value1 < value2);
			case '<=': return (value1 <= value2);			
		}
		return true;
	};
}

/** Required field validator */
with (Web_UI_Validator_RequiredIf = NewClass()) 
{
	inherits(Web_UI_Validator_Required);

	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var source = Page.findControl(this.sourceId)
		if (!source) return true;
        var value1 = source.getValidationValue();
        var value2 = this.value;
		switch (this.condition) {
			case '==': if (value1 == value2) return parent.evaluateIsValid.call(this); break;
			case '!=': if (value1 != value2) return parent.evaluateIsValid.call(this); break;
			case '>': if (value1 > value2) return parent.evaluateIsValid.call(this); break;
			case '>=': if (value1 >= value2) return parent.evaluateIsValid.call(this); break;
			case '<': if (value1 < value2) return parent.evaluateIsValid.call(this); break;
			case '<=': if (value1 <= value2) return parent.evaluateIsValid.call(this); break;
		}
		return true;
	};
}

/** Compare field validator */
with (Web_UI_Validator_CreditCard = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		// Get the value
		var target = Page.findControl(this.targetId);
		if (!target) return true;
		if (!target.exists() || !target.getValidationValue) return true;		
		var value = target.getValidationValue();
		if (value == '') return true;
		if (!target.changed) return true;
		
		// Not in valid format
		if ((/[^\d ]/).test(value)) return false;
		value = value.replace(/ /g, '');

		// Get the type
		var type = null;
		if (this.typeSelectorId) {
			var typeSelector = Page.findControl(this.typeSelectorId)
			if (!typeSelector) return true;
			if (!typeSelector.exists() || !typeSelector.getValidationValue) return true;
			type = typeSelector.getValidationValue();
		} else type = this.type;

		// Validate the 3 supported credit card types
		switch (type) {
		case '0':
			if (value.length != 16 && value.length != 13) return false;
			if (!(/^4/).test(value)) return false;
			break;
		case '1':
			if (value.length != 16) return false;
			if (!(/^5[1-5]/).test(value)) return false;
			break;
		case '2':		
			if (value.length != 15) return false;
			if (!(/^3(4|7)/).test(value)) return false;
			break;
		default:
			// Unsupported
			return true;
		}

		// Validate the checksum
	    var numberProduct;
    	var numberProductDigitIndex;
    	var checkSumTotal = 0;
    	for (digitCounter = value.length - 1; digitCounter >= 0; digitCounter--) {
      		checkSumTotal += parseInt(value.charAt(digitCounter));
      		digitCounter--;
      		numberProduct = String((value.charAt(digitCounter) * 2));
      		for (var productDigitCounter = 0; productDigitCounter < numberProduct.length; productDigitCounter++) {
        		checkSumTotal += parseInt(numberProduct.charAt(productDigitCounter));
      		}
    	}    	
    	return (checkSumTotal % 10 == 0);
	}
}

/** Required field validator */
with (Web_UI_Validator_Static = NewClass()) 
{
	inherits(Web_UI_Validator_Base);
	
	// Validate the form field
	prototype.evaluateIsValid = function()
	{
		var target = Page.findControl(this.targetId);
		if (!target) return true;
		if (!target.exists()) return true;
		return false;
	};
}