/*

Mask	| Explanation
----------------------------------------------------------------------------------------------------
#		| allow numbers with '.' , ',' and '-'  $######## -1,234.5 $-1,234 
9		| allow numbers only  Feb 99 2099 1202 Feb 12 2002 
A		| allow alpha only (insluding space)  AAAAAA male9 male 
?		| allow numbers/letters and space  ???????????? 1. Street 11-a 1 Street 11a 
>		| converts alphanumeric to lower case  A>>A> PANAM PanAm 
<		| converts alphanumeric to upper case  <AA<A panam PanAm 
\		| treat reserved character that follows as text  Number: \#99999 12345 Number: #12345 
----------------------------------------------------------------------------------------------------
Special mask modifiers (first character of the mask) 
----------------------------------------------------------------------------------------------------
*		| applies the rule that follows to all input  *9 12 Feb 2002 122002 
@		| adds leading zeroes to the numeric (0-9) input; number that follows is total number of places  @12 123456 000000123456 
^		| replaces all input with the character that follows  ^* this is masked text ******************* 
~		| reverse masking; after entering characters, any existing characters are shifted to the left ~999999-99-9 12345 12-34-5 
----------------------------------------------------------------------------------------------------

  phone number:
    <input type="text" name="test" mask="999-999-9999">
*/

(function($) {

function maskInput(strInput, strMask) {
// Syntax Example:	maskInput( '1203', 'Feb 99 2099' )
//         Output:	'Feb 12 2003'
	var strMasked, strTmp, LenStr, LenMsk, blnReverse;

	strMasked = '';
	LenStr = strInput.length;
	LenMsk = strMask.length;

	if (LenStr==0) return('');
	if (LenMsk==0) return(strInput);

	if (LenMsk>1) {
		if ((strMask.charAt(LenMsk)=='\\') && (strMask.charAt(LenMsk-1)!='\\')) strMask = strMask.substring(0, LenMsk-1);
	}

	blnReverse = false;
	if (strMask.charAt(0) == '~') {							// Reverse masking from right to left instead of from left to right
		if (LenMsk==1) return(strInput);
		strMask = strMask.substring(1, LenMsk);
		LenMsk = strMask.length;
		if (LenStr > LenMsk) return(strInput.substring(0, LenMsk));
		strMask = reverseString(strMask);
		strInput = reverseString(strInput);
		blnReverse = true;
	} else if (strMask.charAt(0) == '^') {					// Replace all characters in input string with
		if (LenMsk==1) return(strInput);					// the second character (real mask)
		strMasked = '';
		for (i=0; i<LenStr; i++) {
			strMasked = strMasked + strMask.charAt(1);
		}
		return(strMasked);
	} else if (strMask.charAt(0) == '*') {					// Treat all characters in input string by the rule
		if (LenMsk==1) return(strInput);					// of the second character (mask)
		var multiChar, i;
		multiChar = strMask.charAt(1);
		if (!isMaskChar(multiChar)) return(strInput);
		strMask = ''
		for (i=0; i<=LenStr; i++) {
			strMask = strMask + multiChar;
		}
		LenMsk = strMask.length;
	} else if (strMask.charAt(0) == '@') {					// Fill all empty place holders to the left with zeroes
		if (LenMsk==1) return(strInput);					// ('leading zeroes'); Second character is number of place holders
		var zeroNum, i;
		zeroNum = strMask.substring(1, LenMsk);
		if (isNaN(zeroNum)) return(strInput);
		strMask = '';
		var i;
		for (i=0; i<zeroNum; i++) {
			strMask = strMask + '9';
		}
		for (i=0; i<LenStr; i++) {
			if (isNumberChar(strInput.charAt(i))) strMasked = strMasked + strInput.charAt(i);
		}
		i=0;
		while (strMasked.charAt(i)=='0') i++;
		if (i>0) strMasked = strMasked.substring(i, LenStr);
		strMasked = strMasked.substring(0, zeroNum);
		LenStr = strMasked.length;
		if (LenStr<zeroNum) {
			for (i=LenStr; i<zeroNum; i++) strMasked = '0' + strMasked;
		}
		return(strMasked);
	}
	var MskOffset, Count, SubStr, Mask, newChar, newCharLen;
	MskOffset = 0;
	for (Count=0; Count<LenStr; Count++) {
		SubStr = strInput.charAt(Count);
		if (MskOffset<LenMsk) {
			newChar = '';
			Mask = strMask.substring(MskOffset, LenMsk);
			newChar = checkMask(Mask, SubStr);
			newCharLen = newChar.length;
			if (newCharLen!=0) strMasked = strMasked + newChar;
			if (Mask.charAt(0)=='\\') MskOffset++;
			MskOffset = MskOffset + newCharLen;
		}
	}
	if (blnReverse) return(reverseString(strMasked));
	return(strMasked);
}

function checkMask(strCheckMask, strInpChar) {
	var strOut;
	strOut = strCheckMask.charAt(0);
	switch (strOut) {
		case '\\':
			strOut = strCheckMask.charAt(1);
			if (strOut!='\\') {
				if ((strCheckMask.length>2) && (strOut!=strInpChar)) {
					strOut = strOut + checkMask(strCheckMask.substring(2, strCheckMask.length), strInpChar);
				}
			} else {
				if ((strCheckMask.length>3) && (strOut!=strInpChar)) {
					strOut = '\\' + checkMask(strCheckMask.substring(3, strCheckMask.length), strInpChar);
				}
			}
			return(strOut);
			brake;
		case '#':		// Numeric: ".,-1234567890"
			if (isNumericChar(strInpChar)) return(strInpChar);
			return('');
			brake;
		case '9':		// Number: "1234567890"
			if (isNumberChar(strInpChar)) return(strInpChar);
			return('');
			brake;
		case '>':		// ToLoverCase: A -> a
			if (isAlphabeticChar(strInpChar)) return(strInpChar.toLowerCase());
			return(strInpChar);
			brake;
		case '<':		// ToUpperCase: a -> A
			if (isAlphabeticChar(strInpChar)) return(strInpChar.toUpperCase());
			return(strInpChar);
			brake;
		case 'A':		// Alphabetic: "abcdefghijklmnopqrstuvwxyz"
			if (isAlphabeticChar(strInpChar)) return(strInpChar);
			return('');
			brake;
		case '?':		// AlphaNumeric: "1234567890abcdefghijklmnopqrstuvwxyz"
			if (isNumOrChar(strInpChar)) return(strInpChar);
			return('');
			brake;
		default :		// Enything else
			if ((strCheckMask.length>1) && (strOut!=strInpChar)) {
				strOut = strOut + checkMask(strCheckMask.substring(1, strCheckMask.length), strInpChar);
			} 
			return(strOut);
			brake;
	}
}

function isMaskChar(value) {
	if (value.length==1) return value.match(/[\#\9\>\<\A\?]/);
}

function isAlphabeticChar(value) {
  if (value.length==1) return !(value.match(/[^A-Za-z]/));
}

function isNumberChar(value) {
	if (value.length==1) return !(value.match(/[^0-9]/));
}

function isNumericChar(value) {
	if (value.length==1) return !value.match(/[^0-9\-\.\,]/);
}

function isNumOrChar(value) {
	if (value.length==1) return !value.match(/[^-\,\)\(\sA-Za-z0-9]/);
}

function reverseString(v) {
	if (v == '') return(v);
	var str_value='';
	for (i=v.length; i>=0; i--) str_value += v.charAt(i-1);
	return str_value;
}


  $.fn.mask = function(mask) {	
	  return this.each(function(){
	    var m = mask || $(this).attr('mask');
	    $(this).bind('keyup', function(e){
		    var f = (e.target || e.srcElement);
            f.value = maskInput(f.value, m);
	    });
	  });
  }
  $(document).ready(function(){
    $(':text[mask]').mask();
  });
})(jQuery);