/**
 * Autotab - jQuery plugin 1.1b
 * http://www.lousyllama.com/sandbox/jquery-autotab
 * 
 * Copyright (c) 2008 Matthew Miller
 * 
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 * 
 * Revised: 2008-09-10 16:55:08
 */

(function($) {
	// Look for an element based on ID or name
	var check_element = function(name) {
		var obj = null;
		var check_id = $('#' + name);
		var check_name = $('input[name=' + name + ']');

		if (check_id != undefined)
			obj = check_id;
		else if (check_name != undefined)
			obj = check_name;

		return obj;
	};

	/**
	* autotab_magic automatically establishes autotabbing with the
	* next and previous elements as provided by :input.
	* 
	* autotab_magic should called after applying filters, if used.
	* If any filters are applied after calling autotab_magic, then
	* Autotab may not protect against brute force typing.
	* 
	* @name	autotab_magic
	* @param	focus	Applies focus on the specified element
	* @example	$(':input').autotab_magic();
	*/
	$.fn.autotab_magic = function(focus) {
		for (var i = 0; i < this.length; i++) {
			var n = i + 1;
			var p = i - 1;

			if (i > 0 && n < this.length)
				$(this[i]).autotab({ target: $(this[n]), previous: $(this[p]) });
			else if (i > 0)
				$(this[i]).autotab({ previous: $(this[p]) });
			else
				$(this[i]).autotab({ target: $(this[n]) });

			// Set the focus on the specified element
			if (focus != null && (isNaN(focus) && focus == $(this[i]).attr('id')) || (!isNaN(focus) && focus == i))
				$(this[i]).focus();
		}
	};

	/**
	* This will take any of the text that is typed and
	* format it according to the options specified.
	* 
	* Option values:
	*	format		text|number|alphanumeric|all|custom
	*	- Text			Allows all characters except numbers
	*	- Number		Allows only numbers
	*	- Alphanumeric	Allows only letters and numbers
	*	- All			Allows any and all characters
	*	- Custom		Allows developer to provide their own filter
	*
	*	uppercase	true|false
	*	- Converts a string to UPPERCASE
	* 
	*	lowercase	true|false
	*	- Converts a string to lowecase
	* 
	*	nospace		true|false
	*	- Remove spaces in the user input
	* 
	*	pattern		null|(regular expression)
	*	- Custom regular expression for the filter
	* 
	* @name	autotab_filter
	* @param	options		Can be a string, function or a list of options. If a string or
	*						function is passed, it will be assumed to be a format option.
	* @example	$('#number1, #number2, #number3').autotab_filter('number');
	* @example	$('#product_key').autotab_filter({ format: 'alphanumeric', nospace: true });
	* @example	$('#unique_id').autotab_filter({ format: 'custom', pattern: '[^0-9\.]' });
	*/
	$.fn.autotab_filter = function(options) {
		var defaults = {
			format: 'all',
			uppercase: false,
			lowercase: false,
			nospace: false,
			pattern: null
		};

		if (typeof options == 'string' || typeof options == 'function')
			defaults.format = options;
		else
			$.extend(defaults, options);

		for (var i = 0; i < this.length; i++) {
			$(this[i]).bind('keyup', function(e) {
				var val = this.value;

				switch (defaults.format) {
					case 'text':
						var pattern = new RegExp('[0-9]+', 'g');
						val = val.replace(pattern, '');
						break;

					case 'alpha':
						var pattern = new RegExp('[^a-zA-Z]+', 'g');
						val = val.replace(pattern, '');
						break;

					case 'number':
					case 'numeric':
						var pattern = new RegExp('[^0-9]+', 'g');
						val = val.replace(pattern, '');
						break;

					case 'alphanumeric':
						var pattern = new RegExp('[^0-9a-zA-Z]+', 'g');
						val = val.replace(pattern, '');
						break;

					case 'custom':
						var pattern = new RegExp(defaults.pattern, 'g');
						var val = val.replace(pattern, '');
						break;

					case 'all':
					default:
						if (typeof defaults.format == 'function')
							var val = defaults.format(val);

						break;
				}

				if (defaults.nospace) {
					var pattern = new RegExp('[ ]+', 'g');
					val = val.replace(pattern, '');
				}

				if (defaults.uppercase)
					val = val.toUpperCase();

				if (defaults.lowercase)
					val = val.toLowerCase();

				if (val != this.value)
					this.value = val;
			});
		}
	};

	/**
	* Provides the autotabbing mechanism for the supplied element and passes
	* any formatting options to autotab_filter.
	* 
	* Refer to autotab_filter's description for a detailed explanation of
	* the options available.
	* 
	* @name	autotab
	* @param	options
	* @example	$('#phone').autotab({ format: 'number' });
	* @example	$('#username').autotab({ format: 'alphanumeric', target: 'password' });
	* @example	$('#password').autotab({ previous: 'username', target: 'confirm' });
	*/
	$.fn.autotab = function(options) {
		var defaults = {
			format: 'Number',
			maxlength: 2147483647,
			uppercase: false,
			lowercase: false,
			nospace: false,
			target: null,
			previous: null,
			pattern: null
		};

		$.extend(defaults, options);

		// Sets targets to element based on the name or ID
		// passed if they are not currently objects
		if (typeof defaults.target == 'string')
			defaults.target = check_element(defaults.target);

		if (typeof defaults.previous == 'string')
			defaults.previous = check_element(defaults.previous);

		var maxlength = $(this).attr('maxlength');

		// defaults.maxlength has not changed and maxlength was specified
		if (defaults.maxlength == 2147483647 && maxlength != 2147483647)
			defaults.maxlength = maxlength;
		// defaults.maxlength overrides maxlength
		else if (defaults.maxlength > 0)
			$(this).attr('maxlength', defaults.maxlength)
		// defaults.maxlength and maxlength have not been specified
		// A target cannot be used since there is no defined maxlength
		else
			defaults.target = null;

		if (defaults.format != 'all')
			$(this).autotab_filter(defaults);

		// Go to the previous element when backspace
		// is pressed in an empty input field
		return $(this).bind('keydown', function(e) {
			if (e.which == 8 && this.value.length == 0 && defaults.previous)
				defaults.previous.focus().val(defaults.previous.val());
		}).bind('keyup', function(e) {
			/**
			* Do not auto tab when the following keys are pressed
			* 8:	Backspace
			* 9:	Tab
			* 16:	Shift
			* 17:	Ctrl
			* 18:	Alt
			* 19:	Pause Break
			* 20:	Caps Lock
			* 27:	Esc
			* 33:	Page Up
			* 34:	Page Down
			* 35:	End
			* 36:	Home
			* 37:	Left Arrow
			* 38:	Up Arrow
			* 39:	Right Arrow
			* 40:	Down Arrow
			* 45:	Insert
			* 46:	Delete
			* 144:	Num Lock
			* 145:	Scroll Lock
			*/
			var keys = [8, 9, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 144, 145];

			if (e.which != 8) {
				var val = $(this).val();

				if ($.inArray(e.which, keys) == -1 && val.length == defaults.maxlength && defaults.target) {

					if (defaults.target.val() != '') {
						if (defaults.target[0].type != "submit") {
							defaults.target[0].value = '';
						}
					}
					defaults.target.focus();
				}
			}
		});
	};

})(jQuery);