/*	(c) 2008-2009 Real Estate Data X-Change, Inc.
*	@author Everett Morse
*	
*	JS functions for validating field elements for specific formats.
*	Some of these restrict the input and format on the fly.  Others
*	have an isValidXXX function to use, which will select the text in
*	the element and return false on failure, with an optional parameter
*	to show an alert too (otherwise you must display the alert yourself).
*	
*	Depends on the Prototype.js library.
*	
*	Phone Number:
*	Restricts the field input to a phone number format.  Highlights red if the number is incomplete.
*	- attachPhoneValidator('id_of_element')
*	- isValidPhone(element)
*	- requireValid('id_of_element', isValidPhone, "Error message")
*	
*	Email:
*	Highlights red if the email is invalid
*	- attachEmailValidator('id_of_element')
*	- isValidEmail(element)
*	- requireValid('id_of_element', isValidEmail, "Error message")
*	
*	Numbers:
*	Restricts input to only numbers.  Allows a negative sign and decimal places.
*	- attachNumbersValidator('id_of_element')
*	- require('id_of_element', "Error message")
*/

/**
 * Checks that a required input is not empty.
 * 
 * @param string id - the id of the element to check (or the element itself)
 * @param string msg - message to display if the element's value is empty
 * @return boolean - true if ok, false if not
 */
function require(id, msg) {
	if( $(id).value == '' ) {
		alert(msg);
		$(id).focus();
		return false; 
	} else
		return true;
}

/**
 * Checks that a required input is not empty and that it is valid according to a validation function
 * 
 * @param string id - the id of the element to check (or the element itself)
 * @param function validator - the function (from this file, or in the same format) to use
 * @param string msg - message to display if the element's value is empty
 * @return boolean - true if ok, false if not
 */
function requireValid(id, validator, msg) {
	var elem = $(id);
	if( elem.value == '' || !validator(elem) ) {
		alert(msg);
		elem.focus();
		return false; 
	} else
		return true;
}

/**
 * Checks that an input is valid, but allow for it to be empty
 * 
 * @param string id - the id of the element to check (or the element itself)
 * @param function validator - the function (from this file, or in the same format) to use
 * @param string msg - message to display if the element's value is empty
 * @return boolean - true if ok, false if not
 */
function validate(id, validator, msg) {
	var elem = $(id);
	if( elem.value != '' && !validator(elem) ) {
		alert(msg);
		elem.focus();
		return false; 
	} else
		return true;
}

/********************* PHONE NUMBER ************************/

/**
 * Attach a phone validator to the given text field element
 */
function attachPhoneValidator(element) {
	$(element).observe('keyup', phoneKey);
	$(element).observe('keypress', phoneRestrict);
	
	if( navigator.appName == "Microsoft Internet Explorer" )
		$(element).observe('blur', phoneCheck);	//since we manually set the value, IE doesn't trigger change events
	else
		$(element).observe('change', phoneCheck);
}

function phoneCheck(e) {
	var field = e.element();
	var value = field.value.replace(/[^0-9]/gi,'');	//numbers only
	
	if( value != '' && value.length < 10 ) {	//must be the right length or blank
		field.style.backgroundColor = '#f66';
	} else
		field.style.backgroundColor = '';	//default
}

/**
 * Attach this to the onKeyUp event of the text area.
 * This will format the field after every key press
 */
function phoneKey(e) {
	var phoneF = e.element();
	
	var value = phoneF.value;
	var pos = 0;
	if( value.replace(/[^0-9]/gi,'').length > 0 ) {	//has at least one number
		var data = format(value);
		value = data[0];
		pos = data[1];
	} else
		value = "";	//no numb ers, so clear field
	
	phoneF.value = value;
	setCursor(phoneF, pos);
}

/**
 * Attach this to the onKeyPress event of the text area.
 * This restricts input to just numbers, keeping the right format.
 * It allows for backspace and tab.  It also will take an "x" or "e"
 * to mean that an extension will be entered.
 */
function phoneRestrict(e) {
	var phoneF = e.element();
	//if( !e ) var e = window.event;	//IE
	var code = e.keyCode || e.which;
	var character = String.fromCharCode(code);
	var value = phoneF.value.replace(/[^0-9x]/gi,'');	//numbers only, and ext.
	
	//$('debug2').innerHTML = "key code=\""+code+"\" char=\""+character+"\"";
	
	if( code == 9 ) return true;	//tab
	
	if( code == 8 ) { //delete/backspace
		value = value.substring(0,value.length - 1);
		
		var data = format(value);
		phoneF.value = data[0];
		setCursor(phoneF, data[1]);
		
		phoneCheck(e);	//we're stopping the event, so call this ourselves
		e.stop();
	}
	
	if( value.indexOf('x') > 0 ) {
		//Has extension, length must be 10 for number + 1 for x + 1-4 for the ext.
		if( character.replace(/[^0-9]/gi,'') != '' && value.length < 15 )
			return true;	//numeric and there is space left
		else
			e.stop();		//field full or invalid char
	} else {
		//Does not have extension, so max length is 10 (Or 11 if first char is a one, that gets stripped later)
		
		if( value.length >= 10 && (character == 'x' || character == 'e') ) {
			var data = format(value);
			phoneF.value = data[0] + ' ext. ';
			setCursor(phoneF, data[1]+6);
			e.stop();
		} else if( character.replace(/[^0-9]/gi,'') != '' ) {
			if( value.length < 10 || (value.charAt(0) == '1' && value.length < 11) )
				return true;
		}
	}
	e.stop();
}

/**
 * Take an input string and format it to be a phone number like
 * Returns the formatted string and the cursor position to enter the next number.
 * 
 * This uses the national phone number format (vs international) which formats
 * a number like "(800) 555-1234 ext. 123".  The input may start with 1, as in 
 * "1-800-..." and the 1 will be stripped off, but only if there are enough digits.
 * 
 * The first thing format does is to reduce the input to just numbers and the
 * letter 'x'.  So you may use 'x' to separate the extension in input.  Output
 * will use ' ext. ' to separate the extension if there is one.
 * 
 * @param string input - the value from the text field
 * @return [value, where the cursor should be]
 */
function format(input) {
	
	//if there is an extension, pull it off first
	var ext = input.replace(/[^0-9x]/gi,'').split('x');
	if( ext.length == 2 ) {
		input = ext[0];
		ext = ext[1];
	} else {
		input = ext[0];
		ext = null;
	}
	
	if( input.length > 11 )
		input = input.substring(0,11);	//take only 11 chars max
	input = input.split('');	//go thru each character
	var output = '';
	var i = 0;
	var formattingSpaces = 0;
	
	if( input.length == 0 )
		return ['',0];//['(   )    -    ',1];
	
	//Styles:
	//A. (123) 456-7890  (force an area code)
	//B. 1 (234) 567-8900 --> No, let's strip off the 1
	
	if( input.length == 11 && input[0] == '1' ) {	//style B
		//output = '1 ';
		i++;
		//formattingSpaces = 1;	//the space after the one
	}
	output += '(';
	formattingSpaces++;
	
	//Area Code
	if( i < input.length )
		output += input[i++];
	else
		return [output+'   )    -    ', i + formattingSpaces];
	
	if( i < input.length )
		output += input[i++];
	else
		return [output+'  )    -    ', i + formattingSpaces];
		
	if( i < input.length )
		output += input[i++];
	else
		return [output+' )    -    ', i + formattingSpaces];
		
	//First Three
	formattingSpaces += 2;	//paren + space
	if( i < input.length )
		output += ') '+input[i++];
	else
		return [output+')    -    ', i + formattingSpaces];
		
	if( i < input.length )
		output += input[i++];
	else
		return [output+'  -    ', i + formattingSpaces];
		
	if( i < input.length )
		output += input[i++];
	else
		return [output+' -    ', i + formattingSpaces];
	
	//Last Four
	formattingSpaces++;	//dash
	if( i < input.length )
		output += '-'+input[i++];
	else
		return [output+'-    ', i + formattingSpaces];
		
	if( i < input.length )
		output += input[i++];
	else
		return [output+'   ', i + formattingSpaces];
		
	if( i < input.length )
		output += input[i++];
	else
		return [output+'  ', i + formattingSpaces];
		
	if( i < input.length )
		output += input[i++];
	else
		return [output+' ', i + formattingSpaces];
	
	//Ext
	if( ext != null ) {
		output += ' ext. ' + ext;
		i += ext.length;
		formattingSpaces += 6;
	}
	
	return [output, i + formattingSpaces];
}

/**
 * Set the cursor position of an element. Works with IE and FF.
 */
function setCursor(elem, pos) {
	if( document.selection ) {	//IE
		var sel = elem.createTextRange();
		sel.collapse(true);
		sel.moveStart("character", pos);
		sel.moveEnd("character", 0);
		sel.select();
	} else {	//FF
		elem.selectionStart = pos;
		elem.selectionEnd = pos;
	}
}

/*
Getting caret position in IE
From: http://www.bazon.net/mishoo/articles.epl?art_id=1292

var range = document.selection.createRange();
var bookmark = range.getBookmark();
var caret_pos = bookmark.charCodeAt(2) - 2;	//for a textarea you subtract a diff number.  Sorta a bad hack.

OR

var start = Math.abs(document.selection.createRange().moveStart("character", -1000000));
var end = Math.abs(document.selection.createRange().moveEnd("character", -1000000)); 
*/

/**
 * On failure highlight the element and return false.  Optionally show a message.
 * @param element - the text field to validate
 * @param boolean showAlert (Optional) - if true, shows an alert message too
 * @return boolean
 */
function isValidPhone(element, showAlert) {
	var value = element.value.replace(/[^0-9x]/gi,'');
	if( value.indexOf('x') > 0 ) {
		if( value.length >= 12 )	//10 digits and at least 1 extension digit (plus the x)
			return true;
	} else if( value.length >= 10 ) {
		return true;
	}
	
	element.focus();
	if( showAlert )
		alert("Invalid phone number format.  Please correct it and submit again.");
	return false;
}

/*********************** EMAIL ***********************/


/**
 * Attach an email validator to the given text field element.
 * This only checks after the field is changed, and gives an alert if it fails
 */
function attachEmailValidator(element) {
	$(element).observe('change', emailCheck);
}

function emailCheck(e) {
	var field = e.element();
	if( field.value != '' && !isValidEmail(field,false) ) {
		field.style.backgroundColor = '#f66';
	} else
		field.style.backgroundColor = '';	//default
}

/**
 * On failure highlight the element and return false.  Optionally show a message.
 * @param element - the text field to validate
 * @param boolean showAlert (Optional) - if true, shows an alert message too
 * @return boolean
 */
function isValidEmail(element, showAlert) {
	if( element.value.match(/^([-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+)@([-!#$%&\'*+\\\/0-9=?A-Z^_`a-z{|}~]+\.)[-!#$%&\'*+\\.\/0-9=?A-Z^_`a-z{|}~]+$/)) {
		return true;
	} else {
		element.focus();
		if( showAlert )
			alert("Invalid email address.  Please correct it and submit again.");
		return false;
	}
}


/******************** NUMBERS *************************/

/**
 * Attach a phone validator to the given text field element
 */
function attachNumbersValidator(element) {
	$(element).observe('keypress', numbersRestrict);
	$(element).observe('blur', numbersCheckValid);
}

/**
 * Attach this to the onKeyPress event of the text area.
 */
function numbersRestrict(e) {
	var field = e.element();
	var code = e.which != null? e.which : e.keyCode;
	if( code == 0 ) return;	//ignore special chars
	var character = String.fromCharCode(code);
	//var value = field.value.replace(/[^0-9-.+]/gi,'');	//numbers only, and +/-/.
	
	if( code == 8 ) return;	//allow backspace
	
	//For +/-/. allow only one of +/- and one . in the string
	if( character == '+' || character == '-' ) {
		if( field.value.indexOf('+') != -1 || field.value.indexOf('-') != -1 )
			e.stop();	//already has one
	}
	if( character == '.' && field.value.indexOf('.') != -1 )
		e.stop();	//already has ones
	
	if( character.replace(/[^0-9-+.]/gi,'') == "" )	//was not numeric
		e.stop();//return false;
}

/**
 * Attach to the onBlur event to make sure the +/-/. chars still give a valid number
 * If not, take the result of parseFloat which chops off the invalid char and anything after.
 */
function numbersCheckValid(e) {
	var field = e.element();
	var value = parseFloat(field.value);
	
	if( field.value && value != field.value )
		field.value = value;	//take the good one, drop other chars (shouldn't get NaN b/c of keypress validator)
}