/**
 * Cancels an event, if possible
 */
function cancel_event(evt) {
    // Cancel the event
    if (evt.preventDefault)
        evt.preventDefault();
    else evt.returnValue = false;
}

function enforce_regex(obj, regex, example)
{    
    if (obj.value.length == 0)
        return;
    if (!regex.test(obj.value))
    {
        alert("The value you entered was incorrect. " + ((typeof(example) != "undefined") ? "\nThe value should look similar to this: " + example + ".\n" : "") + "Please try again.");
        obj.focus();        
    }
}

/**
 * Enforces an object's value to fit into a specific template.
 * The template is provided in the 'template' variable, and
 * items in the template which match the replace_char will be
 * replaced by each character in the object's value.  The regex_filter
 * is used to filter out values that will be transposed into
 * the template.
 */
function enforce_template(obj, template, replace_char, regex_filter)
{      
    if (obj.value.length == 0)
        return;
        
    if (typeof(regex_filter) != "undefined")
        obj.value = obj.value.replace(regex_filter, "");    
        
    while (obj.value.length > 0)
    {
        eval("template = template.replace(/" + replace_char + "/, obj.value.charAt(0));");
        obj.value = obj.value.substr(1, obj.value.length - 1);
    }
    obj.value = template; 
}

/**
 * Enforces valid phone numbers in the United States
 * Call using something like this:
 * <input type="text" onblur="enforce_phone(this);" />
 */
function enforce_phone(obj, fmt) {
    if (typeof(fmt) == "undefined")
        fmt = "(###) ###-####";
        
    enforce_template(obj, fmt, "#", /\D/g);    
}

/**
 * Enforces numeric characters in a text input field.
 * Call using something like this:
 * <input type="text" onkeydown="enforce_numeric(event, this);" />
 */
function enforce_numeric(e, obj) {
    var evt = document.all ? window.event : e;
    if (!evt) return;

    // Allow numeric keys and control keys
    if ((evt.keyCode <= 57) || (evt.keyCode >= 96 && evt.keyCode <= 105)) {
        bad_keypresses = 0;
        return true;
    }

    cancel_event(evt);

    // Otherwise, strip the string
    if (obj && obj.value)
        obj.value = obj.value.replace(/\D/g,"");

    return false;
}

/**
 * Enforces only a maximum number of characters in an input field.
 * Useful when using hidden fields or other fields which do
 * not use/support the 'maxlength' attribute.  It can also be
 * useful if you want to be able to cut & paste data that's
 * larger than your desired 'maxlength' of your text input,
 * but you'll be processing it before it gets that far
 * (i.e. removing whitespace, non-numerical characters, etc.)
 * Call using something like this:
 * <input type="text" onkeyup="enforce_max(event, this, 16);" />
 */
function enforce_max(e, obj, max) {
    var evt = document.all ? window.event : e;
    if (!evt) return;

    if (obj.value.length >= max && evt.keyCode >= 48) {
        obj.value = obj.value.substr(0,max);
        cancel_event(evt);
        return false;
    }
    return true;
}

/**
 * Enforces having no whitespace in an input field.
 * Call using something like this:
 * <input type="text" onkeyup="enforce_no_whitespace(event, this);" />
 */
function enforce_no_whitespace(e, obj) {
    var evt = document.all ? window.event : e;
    if (!evt) return;

    if (evt.keyCode >= 48) {
        if (obj && obj.value)
            obj.value = obj.value.replace(/\s/g,"");
    }

    if (evt.keyCode == 32)
        return false;
    return true;
}

/**
 * Enforces the case of text entry.  For uppercase, set
 * 'upper' to true, for lowercase, false.
 * Call using something like this:
 * <input type="text" onblur="enforce_case(this, 'upper');" />
 */
function enforce_case(obj, caseStr)
{
    switch(caseStr.toLowerCase())
    {
        case 'upper': obj.value = obj.value.toUpperCase(); break;
        case 'lower': obj.value = obj.value.toLowerCase(); break;
        case 'title': obj.value = obj.value.substr(0,1).toUpperCase() + obj.value.substr(1, obj.value.length-1).toLowerCase(); break;
        default: break;
    }
}

/**
 * Enforces a date string in an input field
 * Call using something like this:
 * <input type="text" onblur="enforce_date(this, format);" />
 * format can be any "mm/dd/yyyy", "mm-dd-yyyy", "yyyy/mm/dd" or any
 * variant thereof, with valid separators being "/" and "-".
 */
function enforce_date(obj, fmt)
{
    if (typeof(fmt) == "undefined")
        fmt = "mm/dd/yyyy";
    
    obj.value = obj.value.replace(/\D/g, "");    
    if (obj.value.length < fmt.replace(/\W/g,"").length)
        fmt = fmt.replace(/(mm)/gi, "X");
    if (obj.value.length < fmt.replace(/\W/g,"").length)    
        fmt = fmt.replace(/(dd)/gi, "X");
    fmt = fmt.replace(/(m|d|y)/gi, "X");    
    
    enforce_template(obj, fmt, "X", /\D/g);    
}

/**
 * Ensures a given date is actually a real date
 * in an input field.
 * Call using something like this:
 * onblur="enforce_valid_date(obj, fmt);"
 */
function enforce_valid_date(obj, fmt, showFmt)
{
    if (typeof(fmt) == "undefined")
        fmt = "mm/dd/yyyy";
        
    if (obj.value.replace(/\s/g,"").length == 0)
        return true;
        
    var separator = fmt.match(/\W/);    
    var val = obj.value.split(separator);    
    
    // Passes the test, make sure date is actually a valid date!
    var elms = fmt.match(/(dd|mm|yyyy|yy)/gi);
    // You don't need all items to work (i.e. "mm/dd" is valid)
    var day = true,
        month = true,
        year = true;
    for (var i = 0; i < elms.length; i++) {
        var chr = elms[i].toLowerCase().charAt(0);

        if (chr == 'd') day = parseInt(val[i], 10);
        else if (chr == 'm') month = parseInt(val[i], 10);
        else if (chr == 'y')
        {                
            year = parseInt(val[i], 10);
            if (year < 100)
            {
                if (year > 80)
                    year += 1900;
                else year += 2000;                
            }
        }
    }    
    
    // We found each of the three elements
    if (day && month && year) {
        // Make sure the entered date is valid!
        var d = new Date(year, month-1, day);

        var days = new Array(31, ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        if (typeof(day) == "string" && d.getDate() != day) day = null;
        else if (typeof(month) == "string" && d.getMonth() != month-1) month = null;
        else if (typeof(year) == "string" && d.getFullYear() != year) year = null;        
        if (day && month && year && day <= days[month-1])
            return true;
    }

    obj.value = showFmt ? fmt.toUpperCase() : "";
    alert("The date was not entered correctly. Please enter it again (" + fmt + ")");
    obj.focus();
}

function enforce_enter_key_click(e, obj)
{
    var evt = document.all ? window.event : e;
    if (!evt) return;
    
    if (evt.keyCode == 13)
    {
        var elm = obj;
        if (typeof(elm) == "string")
            elm = document.getElementById(elm);
        elm.click();    
        
        cancel_event(evt);
        return false;
    }
    return true;    
}