//Makes use of jquery-library

var ValidatorConst = {
	TEXT : 'text',
	PASSWORD : 'password',
	SELECT_ONE : 'select-one',
	SELECT_MULTIPLE : 'select-multiple',
	CHECKBOX : 'checkbox',
	RADIO : 'radio'
};

var posted = 0;
//TEST
var globalValidations;

function Validator(aValidations)
{
	globalValidations = aValidations;
	
	this.fields = [];
	this.forms = [];
	var self = this;
	this.buttonClicked = null;
	
	
	this.registerFieldValidation = function(sFieldID, oValidation)
	{
		oControl = $("#" + sFieldID);
		var oDomControl = document.getElementById(sFieldID);
		
		if(oDomControl) //TODO: Need to check for [] in names
		{
			if(oDomControl.type == ValidatorConst.SELECT_ONE || oDomControl.type == ValidatorConst.CHECKBOX || oDomControl.type == ValidatorConst.RADIO)
			{
				oControl.change(function(){self.validateItem($(this), oValidation, 'change')});	
			}
			
			oControl.blur(function(){self.validateItem($(this), oValidation, 'blur')});	
			this.fields.push({control : oControl, validation : oValidation});
		}
	}
	
	
	for(var i = 0; oValidation = aValidations[i]; i++)
	{
		this.registerFieldValidation(oValidation.field, oValidation);
	}
	
	$("form.client-validation input[@type=image], form.client-validation input[@type=submit], form.client-validation button").click(
		function()
		{
			self.buttonClicked = $(this);
		}
	);
	
	$("form.client-validation").submit(
		function()
		{
			posted++;
			return self.doSubmit($(this));
		}
	);
	
	this.doSubmit = function(oForm)
	{
		if(typeof(validatorSubmitCallback) == 'function')
		{
			return validatorSubmitCallback(this, oForm, this.buttonClicked);
		}
		
		this.forms[oForm.attr('name')] = true;
		for(var x = 0; oField = this.fields[x]; x++)
		{
			this.validateItem(oField.control, oField.validation, 'submit');
		}
		return this.forms[oForm.attr('name')];
		//return false;
	}
	
	//Check if the user has error showing, if so hide descriptions
	$('.PRValidationMessage').each(
		function()
		{
			if($('.PRWarningBox', this).size() > 0)
			{
				$('em', this).hide();	
			}
		}
	);
	
	this.validateItem = function(oItem, oValidation, sEventType)
	{

		
		var bPassedClientCriterias = true;
		if(oValidation['criteria'])
		{
			//Handle multiple criterias by splitting the string
			aCriterias = oValidation['criteria'].split("|");
			
			//Validate a criteria at a time, break if fails...
			for(var j = 0; j < aCriterias.length; j++)
			{
				sCriteria = aCriterias[j];
				
				//Check if there is a client side implementation of criteria function
				if(this.rules[sCriteria] && typeof(this.rules[sCriteria]) == 'function')
				{
					//Call criteria implementation defined in this.rules
					bIsValid = this.rules[sCriteria](oItem, oValidation);
					this.report(oItem, oValidation, bIsValid, sEventType);
					
					//If multiple criterias: break if one fails.. no need to validate other criterias
					if(!bIsValid)
					{
						bPassedClientCriterias = false;
						break;
					}

				}
			}
		}
		
		if(bPassedClientCriterias && oValidation['server'] && ($('#' + oValidation['field']).val().length > 0))
		{
			var oParams = {
				value : $('#' + oValidation['field']).val(),
				method : oValidation['server']
			};
			
			if(oValidation['serverParams'])
			{
				aParams = oValidation['serverParams'].split("&");
				for(var i = 0; i < aParams.length; i++)
				{
					if(m = aParams[i].match(/\{([a-zA-Z0-9\.-\_]+)\}/))
					{
						oDependentControl = $("#" + m[1]);
						if(!this.rules['notEmpty'](oDependentControl))
						{
							bPassedClientCriterias = false;
							this.report(oItem, oValidation, false, 'dependant_control');
						}
						aParams[i] = aParams[i].replace(/\{([a-zA-Z0-9\.-\_]+)\}/, oDependentControl.val());
					}
					
					aParam = aParams[i].split("=");
					oParams[aParam[0]] = aParam[1];
				}

			}
			
			if(bPassedClientCriterias)
			{
				$.post('/api/', oParams, 
					function(sResponse)
					{
						// This prevents the default message from being overwritten.	
						var sDefaultMessage = oValidation['message'];
						oValidation['message'] = sResponse;
	
						if(sResponse.indexOf('class="nice"') != -1)
						{
							//TODO:Show 'Nice' message
						}
						self.report(oItem, oValidation, (sResponse.length == 0), 'server', (sResponse.indexOf('class="nice"') != -1));
						oValidation['message'] = sDefaultMessage;
					}
				);
			}
			
		}
	}
	
	this.rules = {
		'notEmpty' : function(oControl)
		{
			var sValue = oControl.val();
			var bValid = !(sValue.length == 0 || sValue == 'none' || sValue == '-1' || sValue == 'null');
			return bValid;
		} ,
		'isEqual' : function(oControl, oValidationItem)
		{
			return ($('#' + oValidationItem['field2']).val() == oControl.val());
		}, 
		'notEqual' : function(oControl, oValidationItem)
		{
			return ($('#' + oValidationItem['field2']).val() != oControl.val());
		}, 
		'xor' : function(oControl, oValidationItem)
		{
			return (self.rules['notEmpty']($('#' + oValidationItem['field2'])) || self.rules['notEmpty'](oControl));
		},
		'isEmail' : function(oControl)
		{
			var expression = new RegExp(/^[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9-]+\.)+([A-Za-z]{2,6}|[0-9]{0,3})$/);
			return (oControl.val().match(expression));
		}, 
		'isURL' : function()
		{
			return true;
		}, 
		'isInt' : function(oControl)
		{
			var oControlVal = oControl.val().trimLeadingZeros();
			var number = parseInt(oControlVal); 
			
			if (isNaN(number)) 
			{
				return false; 
			}
			
			return (oControlVal==number); 
		}, 
		'isSafeString' : function()
		{
			return true;
		},
		'isDependent' : function()
		{
			return true;
		},
		'isLength' : function(oControl, oValidationItem)
		{
			return (oControl.val().length >= oValidationItem['min'] && oControl.val().length <= oValidationItem['max']);
		},
		'isRange' : function(oControl, oValidationItem)
		{
			bValid = true;

			var iUserInput = parseInt(oControl.val().trimLeadingZeros());
			var iHighLimit = parseInt(oValidationItem['high'].trimLeadingZeros());
			var iLowLimit = parseInt(oValidationItem['low'].trimLeadingZeros()) || 0;
			var bDoHighCheck = (oValidationItem['checkHighLimit'] && oValidationItem['checkHighLimit'] == '1') || (typeof(oValidationItem['checkHighLimit']) == 'undefined');
			var bDoLowCheck = ((oValidationItem['checkLowLimit'] && oValidationItem['checkLowLimit'] == '1') || typeof(oValidationItem['checkLowLimit']) == 'undefined');
			
			if(bDoHighCheck)
			{
				bValid =  iUserInput <= iHighLimit;
			}
			
			if(bValid && bDoLowCheck)
			{
				bValid  = iUserInput >= iLowLimit;
			}
			
			if (oControl.val().length == 0)
			{
				bValid = true;
			}
			return bValid;
			
		},
		'isRangeOrEmpty' : function(oControl, oValidationItem)
		{
			return ((!self.rules['notEmpty'](oControl)) || self.rules['isRange'](oControl, oValidationItem));
		},
	
		'isValidPassword' : function(oControl, oValidationItem)
		{
			bValidPassword = true;
			if(!self.rules['notEmpty'](oControl))
			{
				bValidPassword = false;	
			}
			
			var numberOfDigits = 0;
			var numberOfLetters = 0;
			var numberOfGarbageChars = 0;
			s = oControl.val();
			
			for (i = 0; i < s.length; i++)
			{   
				var c = s.charAt(i);
				if ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) )
				{
					numberOfLetters++;
				}
				else if ((c >= "0") && (c <= "9"))
				{
					numberOfDigits++;
				}
				else
				{
					numberOfGarbageChars++;
				}
			}

			if((numberOfDigits == 0) || (numberOfLetters == 0))
			{
				bValidPassword = false;	
			}
			
			if(numberOfGarbageChars > 0)
			{
				bValidPassword = false;	
			}
			
			if(s.trim().length < 8 || s.trim().length > 12)
			{
				bValidPassword = false;	
			}
			
			return bValidPassword;
		},
		'isDigits' : function(oControl)
		{
			var expression = new RegExp(/^\d+$/);
			return (oControl.val().match(expression));
		},
		'isWmPurse' : function(oControl)
		{
			var expression = new RegExp(/^Z\d+$/);
			return (oControl.val().match(expression));
		}
	};
	
	this.report = function(oFormItem, oValidationItem, bIsValid, sEventType, bIsNiceMessage)
	{
		if(!bIsNiceMessage)
		{
			bIsNiceMessage = false;	
		}
		
		if(sEventType == 'server' && $('#' + oValidationItem['field'] + "Message .PRWarningBox:visible"))
		{
			//TODO: Append server message to existing messagebox
		}
		
		if(bIsValid)
		{
			$('#' + oValidationItem['field'] + "Message .PRWarningBox").hide();
			$('#' + oValidationItem['field'] + "Message em").show();
		}
		else
		{
			if(sEventType == 'submit')
			{
				
				for(a = 0; oForm = document.forms[a]; a++)
				{
					if(this.forms[$(oForm).attr('name')])
					{
						
						this.forms[$(oForm).attr('name')] = false;
						break;
					}
				}
			}
			this.drawError($('#' + oValidationItem['field'] + "Message"), oValidationItem['message'], bIsNiceMessage);
		}
	}
	
	this.drawError = function(oElement, sMessage, bIsNiceMessage)
	{
		//TODO: handle bIsNiceMessage
		var bEmptyMessage = (sMessage.trim().length == 0)
		
		//Check if we have a Yellow box showing already...
		if($('.PRWarningBox', oElement).size() == 0) //Nope, create one
		{
			if(!bEmptyMessage)
			{
				oElement.response(oElement.attr('id') + 'WarningBox', sMessage.trim(), "info", false);	
				$('em', oElement).hide();
			}
		}
		else
		{
			sMessage = sMessage.trim();
			
			var bIsTheSameMessage = true;
			
			$('.PRWarningBox .BoxCntInner', oElement).each(
				function()
				{
					bIsTheSameMessage = ($(this).html() == sMessage);
				}
			);
			
			if(!bIsTheSameMessage && !bEmptyMessage) //Got a response from a ajax-call?
			{
				if($.browser.msie)
				{
					$('.PRWarningBox', oElement).remove();
					$(oElement).response('IEUglyFix', sMessage);
				}
				else
				{
					$('.PRWarningBox .BoxCntInner', oElement).html(sMessage);
				}
			}
			
			if(bEmptyMessage)
			{
				
				$('.PRWarningBox', oElement).hide();
				$('em', oElement).show();
			}
	        else
	        {
	        	$('.PRWarningBox', oElement).show();
				$('em', oElement).hide();
	        }
		}
		
	}

}
