/*************************************************************************

	Name:	validate.js
	Desc:	validation for input fields
			email address, password strength, greather than, less than, etc
			
	TODO:
			CLEAN
		
*************************************************************************/


//validates given inputs
function ValidateJS(config) {
	this.items =	config['items'];
	this.target =	config['target'];
	this.func =		config['func'];
	this.interval = null;
	
	this.init();
	this.validate();
	this.blur();
};

//init elements
ValidateJS.prototype.init = function() {
	var parent = this;
	
	//go thru all items
	for (var i=0; i<this.items.length; i++) {
		var the_item =	this.items[i];
		var element =	the_item['element'];
		var type =		the_item['type'];
		var arg =		the_item['args'];
		element.parent = this;
		
		switch (String(type).toUpperCase()) {
			case 'V_HUMAN':
				break;
			case 'V_CHECKED':
				element.old_click = element.onclick;
				EventListener.add(	element,
									'onclick',
									function() {
										parent.validate();
										if (this.old_click != null) {
											this.old_click();
										}
									}
								);
				break;
				
				
			case 'V_EMAIL':	
			case 'V_MATCH':
			case 'V_NOTMATCH':
			case 'V_PASSWORD':
			case 'V_LONGER':
			case 'V_SHORTER':
			case 'V_LENGTH':
			case 'V_NOTLENGTH':
			case 'V_GREATER':
			case 'V_LESS':
			case 'V_EQUAL':
			case 'V_NOTEQUAL':
			case 'V_INTEGER':
			case 'V_STRING':
				element.old_keyup = element.onkeyup;
				EventListener.add(	element,
									'onkeyup',
									function() {
										parent.delayedValidate();
										if (this.old_keyup != null) {this.old_keyup();}
									}
								);
								
				element.old_mouseup = element.onmouseup;
				EventListener.add(	element,
									'onmouseup',
									function() {
										parent.delayedValidate();
										if (this.old_mouseup != null) {this.old_mouseup();}
									}
								);
				
				element.old_blur = element.onblur;
				EventListener.add(	element,
									'onblur',
									function() {
										parent.validate();
										parent.blur();
										if (this.old_blur != null) {this.old_blur();}
									}
								);
				
				element.old_focus = element.onfocus;
				EventListener.add(	element,
									'onfocus',
									function() {
										parent.focus(this);
										if (this.old_focus != null) {this.old_focus();}
									}
								);
				break;
		}
	}
};


ValidateJS.prototype.clearValidate = function(target) {
	if (this.interval != null) {
		clearInterval(this.interval);
		this.interval = null;
	}
}

ValidateJS.prototype.delayedValidate = function() {
	var parent = this;
	this.clearValidate();
	this.interval = setInterval(function() {parent.validate()}, 500);
}


//replaces all empty elements with placeholders
ValidateJS.prototype.blur = function() {
	
	//go thru all items
	for (var i=0; i<this.items.length; i++) {
		//get args
		var the_item =		this.items[i];
		var element =		the_item['element'];
		var placeholder =	the_item['placeholder'];
		//var type =			the_item['type'];
		//var arg =			the_item['args'];
		
		if (placeholder != '') {
			if ((element.value == '') || (element.value == placeholder)) {
				element.value = placeholder;
				setStateSuffix(element, {disabled:true});
			}
		}
	}/**/
}


//
ValidateJS.prototype.focus = function(target) {
	
	//go thru all items
	for (var i=0; i<this.items.length; i++) {
		//get args
		var the_item =	this.items[i];
		var element =		the_item['element'];
		
		if (element == target) {
			var placeholder =	the_item['placeholder'];			
			if (placeholder != '') {
				if (element.value == placeholder) {
					element.value = '';
					setStateSuffix(element);
				}
			}
		}
	}
}


//validate all elements
ValidateJS.prototype.validate = function() {
	this.clearValidate();

	this.valid = new Array();
	this.invalid = new Array();
	
	var total_valid = true;
	
	//go thru all items
	for (var i=0; i<this.items.length; i++) {
		//get args
		var the_item =	this.items[i];
		
		//check if item valid
		item_valid = validateInput(the_item);
		//item_valid = true;
		
		//push onto relevent array
		if (item_valid) {
			this.valid.push(the_item);
		} else {
			this.invalid.push(the_item);
		}
		
		//track total validity
		total_valid = total_valid && item_valid;
	}
	
	//send results to function
	callFunc(this.target, this.func, [this.valid, this.invalid]);

	
	//return total validity
	return total_valid;
};





function validateStyleSuffix(element, valid) {
	//dont show INVALID if (checkbox, or empty)
	valid = ((valid) || (element.type.toUpperCase() == 'CHECKBOX') || (element.value == ''))
	setStateSuffix(element, {invalid:!valid});
};

//adds or remove '_invalid' to classname as necessary
function validateStyle(valid, invalid) {
	//refresh styles of items
	for (var i=0; i<valid.length; i++) {	validateStyleSuffix(valid[i]['element'], true);		}
	for (var i=0; i<invalid.length; i++) {	validateStyleSuffix(invalid[i]['element'], false);	}
};




//input validator
// type	-type of validation
// id	-id of input element
// arg	-optional argument required for some validation routines
function validateInput(config) {
	var element =		config['element'];
	var type =			config['type'];
	var arg =			config['args'];
	var placeholder =	config['placeholder'];
	
	if ((placeholder != '') && (element.value == placeholder)) {
		return false;
	}
	
	//switch to type of validation
	switch (String(type).toUpperCase()) {
		case 'V_HUMAN':
			return true;
			break;
			
		case 'V_CHECKED':
			//true if checkbox checked
			return element.checked;
			break;
			
		case 'V_EMAIL':
			//true if email valid format
			var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
			return (filter.test(element.value));
			break;
			
		case 'V_MATCH':
			//true if element matches elementB value
			return (element.value == arg.value);
			break;
			
		case 'V_NOTMATCH':
			//true if element DOES NOT matche elementB value
			return (element.value != arg.value);
			break;
			
		case 'V_PASSWORD':
			//true if element is viable password (strength > 0)
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return getPasswordStrength(element.value, arg);
			break;
			
		case 'V_LONGER':
			//true if element length GREATER than given string length
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return String(element.value).length > Number(arg);
			break;
		
		case 'V_SHORTER':
			//true if element length LESS than given string length
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return String(element.value).length < Number(arg);
			break;
		
		case 'V_LENGTH':
			//true if element length EQUAL given string length
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return String(element.value).length == Number(arg);
			break;
			
		case 'V_NOTLENGTH':
			//true if element length NOT EQUAL given string length
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return String(element.value).length != Number(arg);
			break;
			
		case 'V_GREATER':
			//true if element value > than given value
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return Number(element.value) > Number(arg);
			break;
		
		case 'V_LESS':
			//true if element value < than given value
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return Number(element.value) < Number(arg);
			break;
		
		case 'V_EQUAL':
			//true if element value == given value
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return Number(element.value) == Number(arg);
			break;
			
		case 'V_NOTEQUAL':
			//true if element value == than given length
			if (arg.value != null) {arg = arg.value;}	//arg MAY be element
			return Number(element.value) != Number(arg);
			break;
			
		case 'V_INTEGER':
			//true if integer
			//45(-) 48(0)...57(9)
			var val = String(element.value).replace(/[\d\-]*/g, '');
			return (val.length == 0);
			break;
			
		case 'V_STRING':
			//true if not numeric
			return (!is_numeric(element.value));
			break;
	}
};















//calcs password strength (0.0 - 1.0)
function getPasswordStrength(password, username) {
	var score = 0;
	var symbols = '!,@,#,$,%,^,&,*,?,_,~';
	
	//password < 4
	if (password.length < 4) { return 0;}
	//password == username
	if (password.toLowerCase() == username.toLowerCase()) {return 0;}
	
	//password length
	score += password.length * 4;
	score += (removeRep(1, password).length - password.length) * 1;
	score += (removeRep(2, password).length - password.length) * 1;
	score += (removeRep(3, password).length - password.length) * 1;
	score += (removeRep(4, password).length - password.length) * 1;
	
	//password has 3 numbers
	if (password.match('(.*[0-9].*[0-9].*[0-9])')) {score += 5;}
	//password has 2 sybols
	if (password.match('(.*['+symbols+'].*['+symbols+'])')) {score += 5;}
	//password has Upper and Lower chars
	if (password.match('([a-z].*[A-Z])|([A-Z].*[a-z])')) {score += 10;}
	//password has number and chars
	if (password.match('([a-zA-Z])') && password.match('([0-9])')) {score += 15;}
	//password has number and symbol
	if (password.match('(['+symbols+'])') && password.match('([0-9])')) {score += 15;}
	//password has char and symbol
	if (password.match('(['+symbols+'])') && password.match('([a-zA-Z])')) {score += 15;}
	//password is only numbers or only chars
	if (password.match('^\w+$') || password.match('^\d+$')) {score -= 10;}
	
	//make sure score between 0.0 and 1.0
	if (score < 0) {score = 0;}
	if (score > 100) {score = 100;}
	score /= 100;
	
	//return score
	return score;
};


//removes repeated characters from string - used by passwordStrength
function removeRep(pLen, str) {
	var output = "";
	var repeated = false;
	
	for (var i=0; i<str.length; i++) {
		repeated = true;
		for (j=0; ((j < pLen) && (j + i + pLen) < (str.length)); j++) {
			repeated = repeated && (str.charAt(j+i) == str.charAt(j+i+pLen));
		}
		if (j < pLen) {repeated = false;}
		if (repeated) {
			i += pLen-1;
			repeated = false;
		} else {
			output += str.charAt(i);
		}
	}
	return output;
};