/**
* This is a javascript form validation library.
* Called clerk for purely comical reasons
*/

function Clerk()
{
	var fields = {};
    var rules = {};
	var count = 0;
	var isValid = false;
	var errMsgs = {};
	
	/*
	 * Its expected that for each field, there will be a span/div with the
	 * id of the field and a string appended to the end. E.g:
	 * email_msg
	 * title_msg
	 * category_msg
	 *
	 * The success/error messages will be inserted into this div/span.
	 * The following variables are for customizing these fields.
	 */
	 
	 
	/*
	 * This is the suffix appended each 'message' div. E.g if you set it to
	 * '_msg', it will look for a div called {field_id}_msg. E.g:
	 * title_msg
	 * email_msg, etc
	 */
	var msg_suffix = "_msg";
	
	var success = new Array();
	/* 'class' is the class assigned to the 'message div/span' 
	 * if validation for that field successed, and 'msg' is the
	 * string/HTML code inserted in that div. Can be set to blank
	 */
	success['class'] = ''; //Keep them hidden for now to make fadeIn work
	success['msg'] = '<img src="/images/checkbox.png">';
	
	var error = new Array();
	/*
	 * Same as 'success', however the message can't be set here as each rule
	 * will have its own error message. See the errMsgs object below for
	 * changing the error messages.
	 */
	error['class'] = "error";
	
	/* List of errr messages used*/
	errMsgs['required']='This field is required.';
	errMsgs['numeric']='Please enter Numbers only.';
	errMsgs['email']='This must be a valid Email.';	
	errMsgs['cbox_on']='You must agree to the Terms of Service';

    errMsgs['valid_email']=errMsgs['email'];
    errMsgs['is_numeric']=errMsgs['numeric'];
	

    this.setSuccessMsg = function(newMsg)
    {
        success['msg']=newMsg;
    }
	
	
	this.addField = function(field,rule)
	{
		fields[count] = field;
        rules[field] = rule;
		count=count+1;

        var msgId = field + msg_suffix;
        if (document.getElementById(msgId)==undefined)
        {
            //If the field + _msg span doesn't exist for holding the error / success msg,
            //create it here.'
            $("#" + field).after("<span id='" + msgId +"'></span>");
        }
        
        
        return this;
	}
	
	/**
	After all fields have been set, call this function to set all the
	jquery events for the click/keypress/change events of all the fields
	that have been set. Pass on the clerk object itself to this function. E.g:
	
	var clerk=new Clerk();
	clerk.addField('','');
	......
	clerk.setEvents(clerk);
	*/
	this.setEvents = function(obj)
	{
		var func=function()
		{
			obj.validateField(this.id);
		}
		
		var count=this.getCount();
		var field;
	
		for (x=0; x< count; x++)
		{
			field=this.getField(x);
			if (typeof(rules[field]) !='function')
			{
				$("#" + field).blur(func);
				$("#" + field).change(func);
			}
			else
			{
				$("#" + field).blur(rules[field]);
				$("#" + field).change(rules[field]);

			}
			
		}
	}

	this.getField= function(index)
	{
		return fields[index];
	}
	
	this.getCount=function()
	{
		return count;
	}
	
	this.getError=function(rule)
	{
		return errMsgs[rule];
	}
	
	this.setErrorMsg=function(rule,err)
	{
		errMsgs[rule]=err;
	}
	
	this.validate = function()
	{
		var isValid = true;
		var rulesArr;
		var x = 0;
		var field;
		for (x=0; x < count; x++)
		{
			field=this.getField(x);
			if (!this.validateField(field))
			{				
				//console.log(field + 'is invalid');
				isValid = false;
			}
				
		}
		
		return isValid;
	}
	
	
	this.validateField = function(field)
	{                
		if (rules[field]=="")
		{
			this.addOkMsg(field);
			return true;
		}
		
		
		$("#" + field).val(this.trim($("#" + field).val()));
		
		var temp=rules[field];
		
		//If the rule is a function, call that function and dont go through the
		//switch statement.
		
		//Note that if the rule is a function, then any of the other rules
		//such as 'required' cannot be applied. Also, the
		//process of OK messages/error messages are to be done from within the
		//calling function
		
		if (typeof temp=='function')
		{
			return temp(field);
		}
		
		//If not required, and the field wasnt filled in, skip it.
		if (temp.indexOf('required')==-1 && $("#" + field).val()=="")
		{
			this.addOkMsg(field);
			return true;
		}
		
		
		var myRules =temp.split("|");
		var rule;
		var valid = false;
		for (x = 0; x < myRules.length; x++)
		{
			rule = myRules[x];
			valid = false;
			switch (rule) {
				case 'required':
					valid = this.validate_required(field);
					break;
					
				case 'numeric':
                case 'is_numeric':
					valid = this.validate_numeric(field);
					break;
					
				case 'email':
                case 'valid_email':
					valid = this.validate_email(field);
					break;
					
				case 'cbox_on':
					valid = this.validate_checkbox(field);
					break;

                case "":
                   valid = true;
                break;

				default:
					//alert("Rule not found: " + rule);
				break;
					
			}
			if (! valid)
			{
				this.addError(field, "<br>" + this.getError(rule));
				return false;
			}
		}
		
		if(valid==true)
		{
			this.addOkMsg(field);
			return true;
		}
	}
	
	/*
	 * Creates jquery events so on the onblur event of every field which is
	 * added to the object, the validateField function will be called which
	 * would validate the field and show an error/success message
	 * Commented for now, uncomment if using it
	
	this.assignEvents=function()
	{
		for (x=0; x< fields.length; x++)
		{
			$("#" + fields[x]).blur(function(){ this.validateField() })
		}
	}
	 */
	
	this.addOkMsg=function(field)
	{
		var id=field + msg_suffix;

		if 	($("#" + id).html() !=success['msg'])
			$("#" + id).hide(); //Only fade-in again if the success msg isnt already being displayed
		
		//document.getElementById(id).className=success['class'];
		$("#"  + id).html(success['msg']);
		$("#" + id).fadeIn('slow');
	}
	
	this.addError=function(field,error)
	{
		var id=field + msg_suffix;

        if 	($("#" + id).html() !=error)
			$("#" + id).hide();				
		//Hack
		document.getElementById(id).style.color="red";
		//End hack
        $("#" + id).html(error);
		$("#" + id).fadeIn('slow');
	}
	
	this.trim=function(str)
	{
		return str.replace(/^\s+|\s+$/g,"");
	}
	
	/*
	 * Validation functions
	 */
	
	this.validate_required=function(field)
	{
		var el=document.getElementById(field);
		switch(el.type)
		{
			default:
				var val=$("#" + field).val();
				var valid=(val !='');
				return valid;
			break;
			case 'checkbox':
				return el.checked;
			break;
		}
		
	}
	
	this.validate_numeric=function(field)
	{
		var val=$("#" + field).val();
		var valid=(! isNaN(val));	
		return valid;

	}
	
	this.validate_email = function(field)
	{
		var val=$("#" + field).val();
		var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
		if (reg.test(val) == false) 
			return false;
		else
			return true;
	}
	
	this.validate_checkbox = function(field)
	{	
		return (document.getElementById(field).checked);
	}
	
}
