//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;

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')});	
			}
			else
			{
				oControl.blur(function(){self.validateItem($(this), oValidation, 'blur')});	
			}
			if (!oValidation['icon'] || oValidation['icon'] != 'hide')
			{
				$("#" + sFieldID + "Notification .PRValidationNotification > div").show();
			}
			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()
		{
			// The forms in this array will have the page move to top after client validation
			var aFormsToTop = ['signup'];
			posted++;			
			if( in_array($(this).name(), aFormsToTop) )
			{
				window.scroll(0,0);
			}
			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)
	{
		if(oItem.val() == '' && sEventType != 'submit')
		{
			$('#' + oValidation['field'] + "Notification").validatorNotification('notValidated');
			return;
		}
		
		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 && sEventType == 'submit') || sEventType != 'submit')*/)
		{
			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)
			{
				// Add param to nickname getnickname api
				if( sEventType == 'submit'  && oValidation['field'] == 'nickname')
				{
					oParams['showSuggestions'] = 0;
				}
				$.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
						}
						
						// Special fix for nickname suggestions.
						// Will add the nickname suggestions to the tooltipbox						
						if(oValidation['field'] == 'nickname')
						{
							$('#nicknameErrorMessage').empty();
							if( sResponse != '' )
							{
								$('#nicknameErrorMessage').append(sResponse + '<br />');
							}
							$('#nicknameErrorMessage').append(sDefaultMessage);
						}											
						self.report(oItem, oValidation, (sResponse.length <= 0), sEventType, (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)
		{
			var aFields = oValidationItem['field2'].split(",");
			var bIsEqual = true;
			for(var i = 0; i < aFields.length; i++)
			{
				bIsEqual = ($('#' + aFields[i]).val() == oControl.val());
				if( !bIsEqual )
				{
					break;
				}
			}
			return bIsEqual;		
		}, 
		'notEqual' : function(oControl, oValidationItem)
		{
			var aFields = oValidationItem['field2'].split(",");
			var bIsNotEqual = true;
			for(var i = 0; i < aFields.length; i++)
			{
				bIsNotEqual = ($('#' + aFields[i]).val() != oControl.val());
				if( !bIsNotEqual )
				{
					break;
				}
			}
			return bIsNotEqual;
		}, 
		'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})$/);
			var sControlValue = oControl.val();
			return (sControlValue.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;
		},
		'isPhone' : function(oControl)
		{
			var expression = new RegExp(/^[0-9\+ \(\)-]+$/);
			return (oControl.val().match(expression));
		},
		'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));
		},
		'isDependentOnNotEmpty' : function(oControl, oValidationItem)
		{
			return ( (self.rules['notEmpty'](oControl) && self.rules['isSafeString'](oControl)) || (!self.rules['notEmpty']($('#' + oValidationItem['field2']))) );
		},
		'isEmailAndDependentOnNotEmpty' : function(oControl, oValidationItem)
		{
			if(!self.rules['notEmpty']($('#' + oValidationItem['field2'])))
			{//field2 is empty
				return (!self.rules['notEmpty'](oControl) || self.rules['isEmail'](oControl));
			}
			else
			{
				return (self.rules['isEmail'](oControl));
			}	
		},
		'isDependentOnMulti' : function(oControl, oValidationItem)
		{
			var fieldArr = oValidationItem['field3'].split(",");
			var num = fieldArr.length;
			var x;
			var bRetValue = false;
			if(self.rules['notEmpty']($('#' + oValidationItem['field'])))
		    {
		    	bRetValue = true;
			}
			if(self.rules['notEmpty']($('#' + oValidationItem['field2'])))
		    {
		    	bRetValue = true;
			}
			for (x = 0; x < num; x++)
		   	{
		   		if(self.rules['notEmpty']($('#' + fieldArr[x])))
		   		{
		   			bRetValue = true;
		   		}
		   	}
			return bRetValue;
		},
		'isChecked' : function(oControl)
		{
			var sType = oControl.attr('type');
			var bChecked = oControl.attr('checked');
			var bValid = !(sType == ValidatorConst.CHECKBOX && !bChecked);
			return bValid;
		}
	};
	
	this.report = function(oFormItem, oValidationItem, bIsValid, sEventType, bIsNiceMessage)
	{
		if(!bIsNiceMessage)
		{
			bIsNiceMessage = false;	
		}
		
		/*if(sEventType == 'submit')
		{*/
			if ($("#PRValidatorErrorList").size() != 0 && $("#" + oValidationItem['field'] + "ErrorListRow").size() != 0)
			{
				$("#PRValidatorErrorList > li#"+ oValidationItem['field'] + "ErrorListRow").remove();
				if ($("#PRValidatorErrorList").html().length <= 0)
				{
					$("#formErrorDetails").empty();
				}
			}
		/*}*/
		
		if(bIsValid)
		{
			$('#' + oValidationItem['field'] + "Notification").validatorNotification('valid');
		}
		else
		{
			if(sEventType == 'submit' || $("#PRValidatorErrorList").size() != 0)
			{
				for(a = 0; oForm = document.forms[a]; a++)
				{
					if(this.forms[$(oForm).attr('name')])
					{
						this.forms[$(oForm).attr('name')] = false;
						break;
					}
				}
				
				var fieldName = $('#' + oValidationItem['field'] + 'AlertFrame .PREditLabel > label').html();
				
				if ($("#formErrorDetails .BoxCntInner").size() == 0)
				{
					$("#formErrorDetails").append($.DIV({Class : "PRWarning2Box"},$.DIV({Class : "BoxHeader warning2"},$.DIV({Class : 'BoxTopInner'})),$.DIV({Class : "BoxContent warning2"},$.DIV({Class : "BoxCntInner"})),$.DIV({Class : "BoxBtm", innerHTML : '&nbsp;'})));
				}
				
				if ($("#formErrorDetails .BoxCntInner #PRValidatorErrorList").size() == 0)
				{
					$("#formErrorDetails .BoxCntInner").append('<div class="copyRed"><b>Sorry! Your submitted form contained the following errors:</b></div><div class="spacer">&nbsp;</div>');
					$("#formErrorDetails .BoxCntInner").append('<ul id="PRValidatorErrorList"></ul>');
				}
				
				if ($("#" + oValidationItem['field'] + "ErrorListRow").size() == 0)
				{
					$("#formErrorDetails .BoxCntInner #PRValidatorErrorList").append('<li id="'+ oValidationItem['field'] + 'ErrorListRow"><b>' + fieldName + '</b> - ' + oValidationItem['message'] + '</li>');
				}
			}
			$('#' + oValidationItem['field'] + "Notification").validatorNotification('invalid');
		}
	}
	
	/*this.drawError = function(oElement, sMessage, bIsNiceMessage)
	{
		alert(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).hide();
			}
	        else
	        {
	        	$('.PRWarningBox', oElement).show();
				$('em', oElement).hide();
	        }
		}
		
	}*/

}

// in_array function which mimics the php version of in_array
this.in_array = function ( mNeedle, aHaystack ) 
{
	for ( var i = 0 ; i <= aHaystack.length ; i++ ) 
	{
		if ( aHaystack[i] ===  mNeedle) 
		{
			return true;
		}
	}
	return false;
}