var numeric = "0123456789";
var numericDate = "0123456789/";
var lowercase = "abcdefghijklmnopqrstuvwxyz";
var uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var alphabetic = lowercase + uppercase;
var alphanumeric = numeric + alphabetic;
var avoid_01 = "\~\`\!\@\$\%\^\&\*\(\)\_\+\=\{\[\}\]\|\\\:\;\"\<\>\?\/";

// same as above but includes the apostrophe
var avoid_02 = "\~\`\!\@\$\%\^\&\*\(\)\_\+\=\{\[\}\]\|\\\:\;\"\'\<\>\?\/";

// ------------------------------------------------------------
// left trim
// ------------------------------------------------------------
function ltrim(str) {
    while (str.substring(0, 1) == ' ') {
        str = str.substring(1, str.length);
    }
    return str;
}

// ------------------------------------------------------------
// right trim
// ------------------------------------------------------------
function rtrim(str) {
    while (str.substring(str.length - 1, str.length) == ' ') {
        str = str.substring(0, str.length - 1);
    }
    return str;
}

// ------------------------------------------------------------
// combined left and right trim
// ------------------------------------------------------------
function trim(str) {
    return ltrim(rtrim(str));
}

// ------------------------------------------------------------
// check if the given character is in the bag of characters
// ------------------------------------------------------------
function isInBag(c, bag) {
    return (bag.indexOf(c) != -1);
}

// ------------------------------------------------------------
// strip out characters that are not in the given bag
// ------------------------------------------------------------
function stripNotInBag(s, bag) {
	    var str = "";
	    for (var i = 0; i < s.length; i++) {
        	if (isInBag(s.charAt(i), bag)) {
	            str += s.charAt(i);
        	}
	    }
	    return trim(str);
}

// ------------------------------------------------------------
// strip out characters that are in the given bag
// ------------------------------------------------------------
function stripInBag(s, bag) {
    var str = "";
    for (var i = 0; i < s.length; i++) {
        if (!isInBag(s.charAt(i),bag)) {
            str += s.charAt(i);
        }
    }
    return trim(str);
}

// ------------------------------------------------------------
// check if the given string has mixed character cases
// ------------------------------------------------------------
function isMixedCase(str) {
    var seenLower = false;
    var seenUpper = false;
    for (var i = 0; i < str.length && !(seenLower && seenUpper); i++) {
        seenLower = (seenLower || isInBag(str.charAt(i), lowercase));
        seenUpper = (seenUpper || isInBag(str.charAt(i), uppercase));
    }
    return (seenLower && seenUpper);
}

// ------------------------------------------------------------
// assert that the string is of pad length or pad the string
// ------------------------------------------------------------
function padLeft(str, pad) {
    str = str.substr(0, pad.length);
    str = pad.substr(0, pad.length - str.length) + str;
    return str;
}

// ------------------------------------------------------------
// join the non-empty strings in the array
// ------------------------------------------------------------
function joinWords(words, delim) {
    var str = "";
    for (var i = 0; i < words.length; i++) {
        if (words[i].length > 0) {
            str += ((i > 0) ? delim : "") + words[i];
        }
    }
    return str;
}

// ------------------------------------------------------------
// convert all the characters to uppercase
// ------------------------------------------------------------
function capitalize(str) {
    return str.toUpperCase();
}

// ------------------------------------------------------------
// convert the given string to a proper name
// ------------------------------------------------------------
function properName(str) {

    if (str.length == 1 || str.toUpperCase() == "GM" || 
                           str.toUpperCase() == "GMAC" || 
                           str.toUpperCase() == "GMACM" || 
                           str.toUpperCase() == "GMACR" || 
                           str.toUpperCase() == "LLC") {
        return str.toUpperCase();
    }

    if (isMixedCase(str)) {
        return (str.charAt(0).toUpperCase() + str.substring(1));
    }
    //else if (str.substring(0, 2).toUpperCase() == "MC" && str.length >= 4) {
    //    var s01 = str.substring(0, 2).toUpperCase();
    //    var s02 = str.substring(2).toUpperCase();
    //    s01 = s01.charAt(0).toUpperCase() + s01.substring(1).toLowerCase();
    //    s02 = s02.charAt(0).toUpperCase() + s02.substring(1).toLowerCase();
    //    return (s01 + s02);
    //} else if (str.substring(0, 3).toUpperCase() == "MAC" && str.length >= 5) {
    //    var s01 = str.substring(0, 3).toUpperCase();
    //    var s02 = str.substring(3).toUpperCase();
    //    s01 = s01.charAt(0).toUpperCase() + s01.substring(1).toLowerCase();
    //    s02 = s02.charAt(0).toUpperCase() + s02.substring(1).toLowerCase();
    //    return (s01 + s02);
    else {
        return (str.charAt(0).toUpperCase() + str.substring(1).toLowerCase());
    }
}

// ------------------------------------------------------------
// convert the given string to proper names
// ------------------------------------------------------------
function properNames(str) {
    var names = str.split(" ");
    for (var i = 0; i < names.length; i++) {
        names[i] = initcapName(names[i]);
    } 
    str = joinWords(names, " ");
    return ((str.charAt(0) == ' ') ? str.substring(1) : str);
}

// ------------------------------------------------------------
// convert the given hyphenated string as a proper name
// ------------------------------------------------------------
function initcapName(str) {
    if (str.indexOf("-") > 0) {
        var names = str.split("-");
        for (var i = 0; i < names.length; i++) {
            names[i] = properName(names[i]);
        }
        return joinWords(names, "-");
    // added logic to handle apostrophes
    } else if (str.indexOf("'") > 0) {
        var names = str.split("'");
        for (var i = 0; i < names.length; i++) {
            names[i] = properName(names[i]);
        }
        return joinWords(names, "'");
    } else {
        return properName(str);
    }
}

// ------------------------------------------------------------
// Reformat the given string according to the arguments.
// The arguments are always given in pair with the first arg
// indicating the format string to append and the second arg
// indicating the number of strings to add to the result.
//
// Example: reformat("1234567890", "(", 3, ") ", 3, "-", 4)
// would result in "(123) 456-7890"
//
// Above example means, first add the "(" followed by 3 chars
// from the string followed by ") ", followed by 3 additional
// characters.
// ------------------------------------------------------------
function reformat(s) {
    var arg;
    var pos = 0;
    var str = "";
    for (var i = 1; i < reformat.arguments.length; i++) {
        if (pos >= s.length) {
            i = reformat.arguments.length;
            break;
        } else {
            arg = reformat.arguments[i];
            if (i % 2 == 1) {
                str += arg;
            } else {
                str += s.substring(pos, pos + arg);
                pos += arg;
            }
        }
    }
    return str;
}

// ------------------------------------------------------------
// Similar to the reformat() function except the strings
// are prepended and worked from back to the front.
//
// Example: reverse_reformat("123456", 2, ".", 3, ",") would
// result in "1,234.56"
// ------------------------------------------------------------
function reverseReformat(s) {
    var arg;
    var pos = s.length;
    var str = "";
    for (var i = 1; i < reverseReformat.arguments.length; i++) {
        if (pos < 0) {
            i = reverseReformat.arguments.length;
            break;
        } else {
            arg = reverseReformat.arguments[i];
            if (i % 2 == 0) {
                str = arg + str;
            } else {
                str = s.substring(pos - arg, pos) + str;
                pos -= arg;
            }
        }
    }
    return str;
}

// ------------------------------------------------------------
// formats a string as all capital letters
// ------------------------------------------------------------
function formatAllCaps(node) {
    node.value = capitalize(stripInBag(node.value, avoid_02));
}

// ------------------------------------------------------------
// formats a string as a proper name with each words having
// the first letter as uppercase and the rest as lowercase
// ------------------------------------------------------------
function formatProper(node) {
    node.value = properNames(stripInBag(node.value, avoid_01));
}

// ------------------------------------------------------------
// formats a string as all capital letters
// ------------------------------------------------------------
function formatUpper(node) {
    //node.value = capitalize(stripInBag(node.value, avoid_01));
    node.value = properNames(stripInBag(node.value, avoid_01));
}

// ------------------------------------------------------------
// formats a string as an email address
// ------------------------------------------------------------
function formatEmail(node) {
    //node.value = capitalize(stripNotInBag(node.value, alphanumeric + "\@\_\-\."));
    node.value = stripNotInBag(node.value, alphanumeric + "\@\_\-\.");
}

// ------------------------------------------------------------
// special handling for landlord
// ------------------------------------------------------------
function formatLandlord(node) {
    //node.value = capitalize(stripInBag(node.value, avoid_02));
    node.value = properNames(stripInBag(node.value, avoid_02));
}

// ------------------------------------------------------------
// formats a string as a phone number
// ------------------------------------------------------------
function formatPhone(node) {
    var str = stripNotInBag(node.value, numeric);
    if (str.length == 11 && str.charAt(0) == "1") {
        str = str.substring(1);
    }
    if (str.length == 10) {
        str = reformat(str, "(", 3, ") ", 3, "-", 4);
    }
    node.value = str;
}

// ------------------------------------------------------------
// formats a string as a zip code
// ------------------------------------------------------------
function formatZipCode(node) {
    var str = stripNotInBag(node.value, numeric);
    // accept only 5-digit zip codes
    //if (str.length == 5 || str.length == 9) {
    //    str = reformat(str, "", 5, "-", 4);
    //}
    node.value = str;
}

// ------------------------------------------------------------
// formats a string as a social security number
// ------------------------------------------------------------
function formatSSN(node) {
    var str = stripNotInBag(node.value, numeric);
    if (str.length == 9) {
        str = reformat(str, "", 3, "-", 2, "-", 4);
    } else {
        str = "";
    }
    node.value = str;
}


// ------------------------------------------------------------
// formats a string as a date
// ------------------------------------------------------------
function formatDateAssist(node) {

	    var nodeVal = stripNotInBag(node.value, numericDate);
	    var retVal = nodeVal;
	    if(nodeVal.indexOf("/") != -1) {
		var thisDate = nodeVal.split("/");
	        var thisMonth = thisDate[0];
        	var thisDay = thisDate[1];
	        var thisYear = thisDate[2];
        	if(thisMonth.length < 2){
			thisMonth = "0"+thisMonth;
		}
		if(thisDay.length < 2){
			thisDay = "0"+thisDay;
		}
		if(thisYear.length < 3){
			thisYear = "20"+thisYear;
		}

		retVal = thisMonth+"/"+thisDay+"/"+thisYear;
    	}
    	else{
    		if (nodeVal.length == 8) {
        		str = reformat(nodeVal, "", 2, "/", 2, "/", 4);
			retVal = str;
    		}
    	}
	if(retVal.length==10){
	    	node.value = retVal;
	}
}

// ------------------------------------------------------------
// formats a string as mm/yyyy
// ------------------------------------------------------------
function formatCCExpDate(node) {
    var str = stripNotInBag(node.value, numeric);
    if (str.length == 6) {
        str = reformat(str, "", 2, "/", 4);
    }
    node.value = str;
}

// ------------------------------------------------------------
// formats a string as a year
// ------------------------------------------------------------
function formatYear(node) {
    var str = stripNotInBag(node.value, numeric);
    while (str.charAt(0) == "0") {
        str = str.substring(1);
    }
    node.value = str;
}

// ------------------------------------------------------------
// formats a string as a positive integer
// ------------------------------------------------------------
function formatInteger(node) {
    var str = node.value;
    while (str.charAt(0) == "0" && str.length > 1) {
        str = str.substring(1);
    }
    //if (str.indexOf(".") != -1) {
    //    str = str.substring(0, str.indexOf("."));
    //}
    node.value = stripNotInBag(str, numeric);
}

// ------------------------------------------------------------
// formats a string as a percentage
// ------------------------------------------------------------
function formatPercent(node) {
    var str = stripNotInBag(node.value, numeric + ".");
    while (str.charAt(0) == "0") {
        str = str.substring(1);
    }
    if (str.indexOf(".") == -1) {
        str = str + ".0";
    }
    if (str.charAt(0) == ".") {
        str = "0" + str;
    }
    if (str.charAt(str.length - 1) == ".") {
        str = str + "0";
    }
    if (str == "0.0") {
        str = "";
    }
    node.value = str;
}

// ------------------------------------------------------------
// formats a string as a dollar amount
// ------------------------------------------------------------
function formatMoney(node) {
    var str = stripNotInBag(node.value, numeric + ".") + "00";
    while (str.charAt(0) == "0") {
        str = str.substring(1);
    }
    if (str.indexOf(".") != -1) {
        str = stripNotInBag(str.substring(0, str.indexOf(".") + 3), numeric);
    }
    str = reverseReformat(str, 2, ".", 3, ",", 3, ",", 3, ",", 3, ",", 3, ",", 3, ",");
    if (str.charAt(0) == ",") {
        str = str.substring(1);
    } else if (str.charAt(0) == ".") {
        str = "0" + str;
    }
    if (str == "0") {
        str = "";
    }
    if (str != "") {
        str = "$" + str;
    }
    node.value = str;
}

// ------------------------------------------------------------
// formats a string as a dollar amount
// (this version supports zero dollars)
// ------------------------------------------------------------
function formatMoney2(node) {
    var str = stripNotInBag(node.value, numeric + ".") + "00";
    while (str.charAt(0) == "0") {
        str = str.substring(1);
    }
    if (str == "") {
        str = "$0.00";
        node.value = str;
        return;
    }
    if (str.indexOf(".") != -1) {
        str = stripNotInBag(str.substring(0, str.indexOf(".") + 3), numeric);
    }
    str = reverseReformat(str, 2, ".", 3, ",", 3, ",", 3, ",", 3, ",", 3, ",", 3, ",");
    if (str.charAt(0) == ",") {
        str = str.substring(1);
    } else if (str.charAt(0) == ".") {
        str = "0" + str;
    }
    if (str == "0") {
        str = "";
    }
    if (str != "") {
        str = "$" + str;
    }
    node.value = str;
}
