/// <reference path="../../../lib/jquery-1.2.6.js" />
/*
* Copyright (c) 2007-2008 Josh Bush (digitalbush.com)
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. 
*/

/*
* Version: 1.2.1
* Release: 2008-12-21
*/

// Call stack code
function showCallStack(){
var f=showCallStack,result="Call stack:\n";

while((f=f.caller)!==null){
var sFunctionName = f.toString().match(/^function (\w+)\(/)
sFunctionName = (sFunctionName) ? sFunctionName[1] : 'anonymous function';
result += sFunctionName;
result += getArguments(f.toString(), f.arguments);
result += "\n";

}
alert(result);
}


function getArguments(sFunction, a) {
var i = sFunction.indexOf(' ');
var ii = sFunction.indexOf('(');
var iii = sFunction.indexOf(')');
var aArgs = sFunction.substr(ii+1, iii-ii-1).split(',')
var sArgs = '';
for(var i=0; i<a.length; i++) {
var q = ('string' == typeof a[i]) ? '"' : '';
sArgs+=((i>0) ? ', ' : '')+(typeof a[i])+' '+aArgs[i]+':'+q+a[i]+q+'';
}
return '('+sArgs+')';
} 

(function($) {
	var pasteEventName = ($.browser.mozilla && parseFloat($.browser.version) < 1.9 ? 'input' : 'paste') + ".mask";
	var iPhone = (window.orientation!=undefined); 
			
	$.mask = {
		//Predefined character definitions
		definitions: {
			'9': "[0-9]",
			'a': "[A-Za-z]",
			'*': "[A-Za-z0-9]"
		}
	};

	$.fn.extend({
		//Helper Function for Caret positioning
		caret: function(begin, end) {
			if (this.length == 0) return;
			if (typeof begin == 'number') {
				end = (typeof end == 'number') ? end : begin;
				return this.each(function() {
					if (this.setSelectionRange) {
//						$("[name='info[cc_name]']").val(begin + " : " + end + $("[name='info[cc_name]']").val())//parseInt($("[name='info[cc_name]']").val() || 0) + 1);
//						this.focus();
						this.setSelectionRange(begin, end);
					} else if (this.createTextRange) {
						var range = this.createTextRange();
						range.collapse(true);
						range.moveEnd('character', end);
						range.moveStart('character', begin);
						range.select();
					}
				});
			} else {
				if (this[0].setSelectionRange) {
					begin = this[0].selectionStart;
					end = this[0].selectionEnd;
				} else if (document.selection && document.selection.createRange) {
					var range = document.selection.createRange();
					begin = 0 - range.duplicate().moveStart('character', -100000);
					end = begin + range.text.length;
				}
				return { begin: begin, end: end };
			}
		},
		unmask: function() { return this.trigger("unmask"); },
		mask: function(mask, settings) {
			if (!mask && this.length > 0) {
				var input = $(this[0]);
				var tests = input.data("tests");
				return $.map(input.data("buffer"), function(c, i) {
					return tests[i] ? c : null;
				}).join('');
			}
			settings = $.extend({
				placeholder: " ",
				completed: null,
				beforePaste: null,
				displayPartial: false
			}, settings);

			var defs = $.mask.definitions;
			var tests = [];
			var partialPosition = mask.length;
			var firstNonMaskPos = null;
			var len = mask.length;

			$.each(mask.split(""), function(i, c) {
				if (c == '?') {
					len--;
					partialPosition = i;
				} else {
					tests.push(defs[c] ? new RegExp(defs[c]) : null);
					if (tests[tests.length - 1] && firstNonMaskPos == null)
						firstNonMaskPos = tests.length - 1;
				}
			});
			
			return this.each(function() {
				var input = $(this);
				var buffer = $.map(mask.split(""), function(c, i) { if (c != '?') return defs[c] ? settings.placeholder : c });
				var ignore = false;  			//Variable for ignoring control keys
				var focusText = input.val();
				var inputDirection = 0;			// 1 for forward, 0 for backward

				input.data("buffer", buffer).data("tests", tests);
				
//				input.hasFocusInit();	// initialize focus plugin
				
				function seekNext(pos) {
					while (++pos < len) {
						if (tests[pos])
							return pos;
					}
					return len;
				};
				
				function seekPrev(pos) {
					while (--pos > 0) {
						if (tests[pos])
							return pos;
					}
					return 0;
				};

				function shiftL(pos, length) {
					var sel = 0;
					if (!length) length = 0;
//					for (var p = pos; p < pos + length; p++) if (!tests[p]) length--;
					while (!tests[pos] && pos >= 0) { pos--; }
//					alert(length);
					for (var i = pos, j = pos; i < len; i++) {
						if (tests[i]) {
							buffer[i] = settings.placeholder;
							var oldj = j;
							var j = seekNext(i + length);
							while (j < len && j == oldj) { length++; j = seekNext(i + length);};
							if (j < len && tests[i].test(buffer[j])) {
								buffer[i] = buffer[j];
							} else {
//								$("[name='info[cc_name]']").val(i + ":" + j + $("[name='info[cc_name]']").val());//"j:" + j + " " + buffer + "|" + $("[name='info[cc_name]']").val());
//								break;
							}
//							$("[name='info[cc_name]']").val(i + ":" + j + $("[name='info[cc_name]']").val());
						} else length--;
					}
					writeBuffer();
//					$("[name='info[billing_city]']").val(buffer + " " + $("[name='info[billing_city]']").val());
//					fixCaretCheckVal(true);
					input.caret(Math.max(firstNonMaskPos, pos));
				};

				function shiftR(pos) {
					for (var i = pos, c = settings.placeholder; i < len; i++) {
						if (tests[i]) {
							var j = seekNext(i);
							var t = buffer[i];
							buffer[i] = c;
							if (j < len && tests[j].test(t)) 
								c = t;
							else
								break;
						}
					}
				};

				function keydownEvent(e) {
					input.data("handledKey", false);
					var pos = input.caret();
					var k = e.keyCode;
					ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));
//					inputDirection = 1;
//					if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore	
//						return true;
//					}
//					if (pos.end >= firstNonMaskPos && (k >= 37 && k <= 40)) {
////						alert(firstNonMaskPos);
//						return false;
//					}
					inputDirection = 0;

//					if (!pos.begin && !(pos.begin - pos.end) && (k == 8/* || k == 46*/)) return false;
					if (!(pos.begin - pos.end) && ((!pos.begin && k == 8) || (pos.begin == (input.val().length) && k == 46)/* || k == 46*/)) return false;
					//delete selection before proceeding
					if ((pos.begin - pos.end) != 0 && (!ignore || k == 8 || k == 46)) {
						clearBuffer(pos.begin, pos.end);
					}
					//backspace, delete, and escape get special treatment
					if (k == 8 || k == 46 || (iPhone && k==127)) {//backspace/delete
						inputDirection = -1;
						shiftL(pos.begin + ((k == 46 || ((pos.begin - pos.end) != 0) )? 0 : -1), (pos.end - (pos.begin + 1)));
						input.data("handledKey", true);
						return false;
					} else if (k == 27) {//escape
						clearBuffer(0, len);
						writeBuffer();
						$(this).caret(firstNonMaskPos);
						return false;
					}
				};

				function keypressEvent(e) {
					if (input.data("handledKey")) {
						input.data("handledKey", false);
						return false;
					}
					
					e = e || window.event;
					var k = e.charCode || e.keyCode || e.which;
					var pos = $(this).caret();
					ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));
					var typeable = (k >= 41 && k <= 122) || k == 32 || k > 186;
					
					
					inputDirection = 0;
//					if (ignore) {
//						ignore = false;
////						fixCaretCheckVal(true);
//						//Fixes Mac FF bug on backspace
//						return (e.keyCode == 8) ? false : null;
//					}
//					$("[name='info[cc_name]']").val(k + $("[name='info[cc_name]']").val());
					
					// dont delete if at first pos and backspace or last pos and delete
					if (!(pos.begin - pos.end) && ((!pos.begin && k == 8) || (pos.begin == (input.val().length) && k == 46)/* || k == 46*/)) return false;
					//delete selection before proceeding
					if ((pos.begin - pos.end) != 0 && (!ignore || k == 8 || k == 46)) {
//						$("[name='info[email]']").val((buffer) + " | " + $("[name='info[email]']").val());
						clearBuffer(pos.begin, pos.end);
					}
					
					//backspace, delete, and escape get special treatment
					if (k == 8 || k == 46 || (iPhone && k==127)) {//backspace/delete
						inputDirection = -1;
						shiftL(pos.begin + (k == 46 || ((pos.begin - pos.end) != 0) ? 0 : -1), (pos.end - (pos.begin + 1)));
						return false;
					}
					if (e.ctrlKey || e.altKey || e.metaKey || (k >= 37 && k <= 40) || k == 8 || k == 46 || k == 9) {//Ignore	
//						$("[name='info[email]']").val((k) + " " + $("[name='info[email]']").val()); 
						return true;
					} else if (typeable) {//typeable characters
						
						var p = seekNext(pos.begin - 1);
						if (p < len) {
							var c = String.fromCharCode(k);
							if (tests[p].test(c)) {
								inputDirection = 1; 
								if ((pos.begin - pos.end) != 0) {
//									$("[name='info[email]']").val((buffer) + " | " + $("[name='info[email]']").val());
									clearBuffer(pos.begin, pos.end);
									shiftL(pos.begin + (k == 46 || ((pos.begin - pos.end) != 0) ? 0 : -1), (pos.end - (pos.begin + 1)));
//									$("[name='info[email]']").val((buffer) + " | " + $("[name='info[email]']").val());
								}
								shiftR(p);
								buffer[p] = c;
								writeBuffer();
								var next = seekNext(p);
								$(this).caret(next);
								if (settings.completed && next == len)
									settings.completed.call(input);
							}
						}
						return false;
					}
//					fixCaretCheckVal(true);
					return false;
				};

				function clearBuffer(start, end) {
					var str = '';
					for (var i = start; i < end && i < len; i++) {
						if (tests[i]) {
							buffer[i] = settings.placeholder;
							str += i + " ";
						}
					}
//					$("[name='info[email2]']").val(end + ": " + len + " " + $("[name='info[email2]']").val());
//					if (end == 17) showCallStack();
				};

				function writeBuffer() { 
//					$("[name='info[cc_name]']").val(buffer + " " + $("[name='info[cc_name]']").val());
					if (settings.displayPartial) {
						var car = input.caret();
						var lastMatch = /*seekNext(*/getLastMatch(true) + inputDirection/*)*/;
//						$("[name='info[email]']").val(lastMatch + " " + $("[name='info[email]']").val()); 
//						$("[name='info[email2]']").val(inputDirection + " " + $("[name='info[email2]']").val()); 
						while (/*lastMatch != -1 &&*/ lastMatch > 0 && lastMatch < len && inputDirection > 0) if (!tests[lastMatch + inputDirection]) lastMatch += inputDirection; else break;
//						$("[name='info[cc_name]']").val(lastMatch + " " + $("[name='info[cc_name]']").val()); 
//						$("[name='info[cc_name]']").val(buffer + " " + $("[name='info[cc_name]']").val());
//						if (car.end > lastMatch) lastMatch = car.end;
						var write = buffer.join('').substring(0, lastMatch+1/* + inputDirection*/);
						clearBuffer(write.length, buffer.length);
//						$("[name='info[email]']").val(write.length + ": " + buffer.length + " " + $("[name='info[email]']").val());
						return input.val(write).val(); 
					} else {
						return input.val(buffer.join('')).val(); 
					}
				};
				
				function getLastMatch(getOnly) {
					//try to place characters where they belong
					var test = input.val();					
					var lastMatch = -1;
					for (var i = 0,pos=0; i < len; i++) {
						if (tests[i]) {
							if (!getOnly) buffer[i] = settings.placeholder;
							while (pos++ < test.length) {
								var c = test.charAt(pos - 1);
								if (tests[i].test(c)) {
									if (!getOnly) buffer[i] = c;
									lastMatch = i;
									break;
								}
							}
							if (pos > test.length || !tests[i].test(buffer[i]))
								break;
						} else lastMatch = i;
					}
					return lastMatch;
				}

				function checkVal(allow) {
//					allow = false;
					var lastMatch = getLastMatch();
					
					if (!allow && lastMatch + 1 < partialPosition) {
						input.val("");
						clearBuffer(0, len);
//						clearBuffer(lastMatch, len - lastMatch);
					} else if (allow || lastMatch + 1 >= partialPosition) {
						writeBuffer();
						if(!allow) {
							input.val(input.val().substring(0, lastMatch + 1));
						}
					}					
					return (partialPosition ? lastMatch : lastMatch/*firstNonMaskPos*/);
				};
				
				function fixCaretCheckVal(allow) {
					var car = input.caret();	// fix caret when changing mask in the middle
//					var realPos = getRealPos(car.begin);
//					$("[name='info[cc_name]']").val(car.begin + "," + realPos + " " + $("[name='info[cc_name]']").val());
					checkVal(allow);
//					if (car.begin == car.end && car.begin < len);//setTimeout("alert('" + car.begin + " " + car.end + "; " + len + "')", 500);
					if (car.begin == car.end && input.hasFocus()) setRealPos(car.begin, car.begin);	// fix caret when changing mask in the middle
				}
				
				function getRealPos(end) {
					var cnt = 0;
//					alert(tests);
					for(var i = 0; i < len && i < end; i++) {
						if (tests[i]) cnt++;
					}
					return cnt;
				}
				
				function setRealPos(begin, end) {
					for (var i = 0; i < len && i < end; i++) {
						if (!tests[i]) {
							if (i < begin) begin++;
							if (i < end) end++;
						}
					}
					while (i == 0 && !tests[i] && i < len) {
						begin++;
						end++;
						i++;
					}
					input.caret(begin, end);
				}
				
				input
					.one("unmask", function() {
						input
							.unbind(".mask")
							.removeData("buffer")
							.removeData("tests");
					})
					.bind("focus.mask", function() {
						focusText = input.val();
						inputDirection = 0;
						var pos = checkVal();
						pos = getRealPos(pos);
						writeBuffer();
						var lastMatch = /*getRealPos(*/getLastMatch(true)/*)*/;
//						alert(lastMatch);
//						setTimeout("alert('" +pos + " " + lastMatch + "')", 500);
						setTimeout(function() {
//							alert(lastMatch);
//							input.caret(pos);
//							alert(input.mask().replace(new RegExp(settings.placeholder, 'g'),'').length);
//							var trimmed_mask = input.mask().replace(new RegExp(settings.placeholder, 'g'),'');
//							var end_non_mask = input.val().lastIndexOf(trimmed_mask.substr(trimmed_mask.length - 1, 1));
							/*if (pos > (lastMatch + 1))*/ 
							if (getRealPos(lastMatch + 1)) input.caret(0, lastMatch + 1);// else
							else setRealPos(0, 0);
//							if (lastMatch) input.caret(0, lastMatch + 1); //end_non_mask + 1);
//							else input.caret(0);
						}, 0);
					})
//					.bind("click.mask", function () {
//						var hasFocus = input.hasFocus();
////						focusText = input.val();
//						inputDirection = 0;
//						var pos = checkVal(true);
////						pos = getRealPos(pos);
//						writeBuffer();
//						var lastMatch = /*getRealPos(*/getLastMatch(true)/*)*/;
////						alert(pos + " " + lastMatch);
//						setTimeout(function() {
////							alert('sdlfk');
////							input.caret(pos);
////							alert(input.mask().replace(new RegExp(settings.placeholder, 'g'),'').length);
////							var trimmed_mask = input.mask().replace(new RegExp(settings.placeholder, 'g'),'');
////							var end_non_mask = input.val().lastIndexOf(trimmed_mask.substr(trimmed_mask.length - 1, 1));
//							var car = input.caret();
//							if (!hasFocus) {
//								$("[name='info[cc_name]']").val(0 + "," + lastMatch + " " + $("[name='info[cc_name]']").val());
//								setRealPos(0, lastMatch);// else
//							}
//							else if (car.end > lastMatch+1) {
////								input.caret((car.begin > lastMatch+1 ? lastMatch+1 : car.begin), (car.end > lastMatch+1 ? lastMatch+1 : car.end));
//							}
////							if (lastMatch) input.caret(0, lastMatch + 1); //end_non_mask + 1);
////							else input.caret(0);
//						}, 0);
//						return false;
//					})
					.bind("blur.mask", function() {
						inputDirection = 0;
						checkVal();
//						lastMatch = getLastMatch(true);
//						if (!(lastMatch + 1) && settings.displayPartial) input.val('');
						if (input.val() != focusText)
							input.change();
					})
					.bind("keydown.mask", keydownEvent)
					.bind("keypress.mask", keypressEvent)
					.bind(pasteEventName, function(){
//						alert(input.val());
						setTimeout(function(){
							var returned;
							if (settings.beforePaste) {
								returned = settings.beforePaste.call(input);
							}
							if (returned != false) input.caret(checkVal(true) + 1);
						},0);
					});
					
				fixCaretCheckVal();	//Perform initial check for existing values
//				var trimmed_mask = input.mask().replace(new RegExp(settings.placeholder, 'g'),'');
//				if (trimmed_mask.length) input.caret(1);
				
			});
		}
	});
})(jQuery);