/**
 * Rock, Paper, Scissors llc.
 *
 * myvalidation.js
 *
 * Javascript form validation routines.
 *
 * Simple routines to quickly pick up obvious typos. All validation routines return true if 
 * executed by an older browser: in this case validation must be left to the server.
 *
 * LICENSE: This source file is subject to version 1.0 of the 
 * Rock, Paper, Scissors llc. license that is available through 
 * the world-wide-web at the following URI:
 * http://www.123shoot.com/license/1_0.txt.  If you did not receive 
 * a copy of the Rock, Paper, Scissors llc. License and are unable 
 * to obtain it through the web, please send a note to 
 * support@123shoot.com so we can mail you a copy immediately.
 *
 * @category   js
 * @author     Scott Lively <scott@123shoot.com>
 * @copyright  2009 Rock, Paper, Scissors llc.
 * @license    http://www.123shoot.com/license/1_0.txt  RPS License 1.0
 */

var nbsp = 160;				//non-breaking space char
var node_text = 3;			//DOM text node-type
var emptyString = /^\s*$/ ;
var global_valfield;		//retain valfield for timer thread
var proceed = 2;

/**
 * function trim
 *
 * Trim leading/trailing whitespace off string.
 */
function trim (str)
{
    return str.replace(/^\s+|\s+$/g, '');
}

/**
 * function setfocus
 *
 * Sets focus to appropriate field.
 */
function setfocus (valfield)
{
    // save valfield in global variable so value retained when routine exits
    global_valfield = valfield;
    setTimeout( 'setFocusDelayed()', 100 );
}

/**
 * function setFocusDelayed
 *
 * Delayed focus setting to get around IE bug. Discovered that reason IE wasn't setting focus was 
 * due to an IE timing bug. Added 0.1 sec delay to fix.
 */
function setFocusDelayed ()
{
    global_valfield.focus();
}

/**
 * function msg
 *
 * Display warn/error message in HTML element. commonCheck routine must have previously been called
 * Parameters:
 * fld = id of element to display message in
 * msgtype = class to give element ("warn" or "error")
 * message = string to display
 */
function msg (fld, msgtype, message)
{
    // setting an empty string can give problems if later set to a 
    // non-empty string, so ensure a space present. (For Mozilla and Opera one could 
    // simply use a space, but IE demands something more, like a non-breaking space.)
    var dispmessage;
    if (emptyString.test(message)) {
        dispmessage = String.fromCharCode(nbsp);
    } else {
        dispmessage = message;
    }
    
    var elem = document.getElementById(fld);
    elem.firstChild.nodeValue = dispmessage;
    
    elem.className = msgtype;   // set the CSS class to adjust appearance of message
}

/**
 * function commonCheck
 *
 * Common code for all validation routines to:
 * (a) check for older / less-equipped browsers
 * (b) check if empty fields are required
 * Returns true (validation passed), false (validation failed), or proceed (don't know yet).
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/erro msg
 * required = true if require
 */
function commonCheck (valfield, infofield, required)
{
    if (!document.getElementById) {
        return true;  // not available on this browser - leave validation to the server
    }
    
    var elem = document.getElementById(infofield);
    
    if (!elem.firstChild) {
        return true;  // not available on this browser
    }
    
    if (elem.firstChild.nodeType != node_text) {
        return true;  // infofield is wrong type of node
    }
    
    if (emptyString.test(valfield.value)) {
        if (required) {
            msg (infofield, "error", "* required");
            setfocus(valfield);
            return false;
        } else {
            msg (infofield, "warn", "");   // OK
            return true;
        }
    }
    
    return proceed;
}

/**
 * function validatePresent
 *
 * Validate if something has been entered. Returns true if so.
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 */
function validatePresent (valfield, infofield ) 
{
    var stat = commonCheck (valfield, infofield, true);
    if (stat != proceed) {
        return stat;
    }
    
    msg (infofield, "warn", "");
    
    return true;
}

/**
 * function validateEmail
 *
 * Validate if e-mail address
 * Returns true if so (and also if could not be executed because of old browser)
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 * required = true if require
 */
function validateEmail (valfield, infofield, required)
{
    var stat = commonCheck (valfield, infofield, required);
    if (stat != proceed) {
        return stat;
    }
    
    var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
    var email = /^[^@]+@[^@.]+\.[^@]*\w\w$/ ;
    if (!email.test(tfld)) {
        msg (infofield, "error", "* not a valid e-mail");
        setfocus(valfield);
        return false;
    }
    
    var email2 = /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/  ;
    if (!email2.test(tfld)) {
        msg (infofield, "warn", "* unusual e-mail address");
    } else {
        msg (infofield, "warn", "");
    }
    
    return true;
}

/**
 * function validateConfirmEmail
 *
 * Validate if e-mail address is same entered twice
 * Returns true if so (and also if could not be executed because of old browser)
 * Parameters:
 * valfield = element to be validated
 * comparefield = element to be compared to
 * infofield = id of element to receive info/error msg
 * required = true if required
 */
function validateConfirmEmail (valfield, comparefield, infofield, required)
{
    var stat = commonCheck (valfield, infofield, required);
    if (stat != proceed) {
        return stat;
    }
    
    var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
    
    var email = /^[^@]+@[^@.]+\.[^@]*\w\w$/  ;
    if (!email.test(tfld)) {
        msg (infofield, "error", "* not a valid e-mail address");
        setfocus(valfield);
        return false;
    }
    
    if (valfield.value != comparefield.value) {
        msg (infofield, "error", "* e-mails do not match");
        setfocus(valfield);
        return false;
    } else {
        msg (infofield, "warn", "");
        return true;
    }
    
    return true;
}

/**
 * function validatePhone
 *
 * Validate telephone number
 * Returns true if so (and also if could not be executed because of old browser)
 * Permits telephone number in format xxx-xxx-xxxx only!
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 * required = true if required
 */
function validatePhone (valfield, infofield, required)
{
    var stat = commonCheck (valfield, infofield, required);
    if (stat != proceed) {
        return stat;
    }
    
    var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
    var telnr = /^[1-9]\d{2}-\d{3}-\d{4}$/  ;
    if (!telnr.test(tfld)) {
        msg (infofield, "error", "* use format xxx-xxx-xxxx");
        setfocus(valfield);
        return false;
    }
    
    //I really don't need the code below until return true...
    //but for some reason this javascript won't work without it???
    var numdigits = 0;
    for (var j=0; j<tfld.length; j++) {
        if (tfld.charAt(j)>='0' && tfld.charAt(j)<='9') {
            numdigits++;
        }
    }
    
    if (numdigits<6) {
        msg (infofield, "error", "ERROR: " + numdigits + " digits - too short");
        setfocus(valfield);
        return false;
    }
    
    if (numdigits>14) {
        msg (infofield, "warn", numdigits + " digits - check if correct");
    } else {
        if (numdigits<10) {
            msg (infofield, "warn", "Only " + numdigits + " digits - check if correct");
        } else {
            msg (infofield, "warn", "");
        }
    }
    
    return true;
}

/**
 * function validateDropDown
 *
 * Validate if something has been entered other than default. Returns true if so.
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 */
function validateDropDown (valfield, infofield )
{
    if (!document.getElementById) {
        return true;  // not available on this browser - leave validation to the server
    }
    
    var elem = document.getElementById(infofield);
    
    if (!elem.firstChild) {
        return true;  // not available on this browser
    }
    
    if (elem.firstChild.nodeType != node_text) {
        return true;  // infofield is wrong type of node
    }
    
    if (valfield.value == '0') {
        msg (infofield, "error", "* required");
        setfocus(valfield);
        return false;
    } else {
        msg (infofield, "warn", "");   // OK
        return true;
    }
    
    return proceed;
}

/**
 * function validateEssay
 * 
 * Returns true if so (and also if could not be executed because of old browser)
 * Requires essay to be completed and checks word count
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 * required = true if required
 */
function validateEssay (valfield, infofield, required)
{
    var stat = commonCheck (valfield, infofield, required);
    if (stat != proceed) {
        return stat;
    }
    
    var fullStr = valfield.value + " ";
    var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
    var left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "");
    var non_alphanumerics_rExp = rExp = /[^A-Za-z0-9]+/gi;
    var cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
    var splitString = cleanedStr.split(" ");
    
    var word_count = 0;
    for (z=0; z<splitString.length; z++) {
        if (splitString[z].length >= 1) {
            word_count++;
        }
    }
    
    if (word_count > 500) {
        msg (infofield, "error", "* essay exceeds 500 words");
        setfocus(valfield);
        return false;
    }
    
    if (word_count < 250) {
        msg (infofield, "error", "* essay < 250 words");
        setfocus(valfield);
        return false;
    }
    
    return true;
}

/**
 * function validateCheckBox
 *
 * Returns true if so (and also if could not be executed because of old browser)
 * Requires check box to be checked
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 * required = true if required
 */
function validateCheckBox (valfield, infofield)
{
    if (valfield.checked == true) {
        msg (infofield, "warn", ""); //OK
        return true;
    } else {
        msg (infofield, "error", "* required");
    }
}

/**
 * function validateFloat
 *
 * Validate floating point number
 * Returns true if so (and also if could not be executed because of old browser)
 * Parameters:
 * valfield = element to be validated
 * infofield = id of element to receive info/error msg
 * required = true if required
 */
function validateFloat (valfield, infofield, required)
{
    var stat = commonCheck (valfield, infofield, required);
    
    if (stat != proceed) {
        return stat;
    }
    
    var tfld = trim(valfield.value);
    
    var floatRE = /^((\d+(\.\d*)?)|((\d*\.)?\d+))$/
    if (!floatRE.test(tfld)) {
        msg (infofield, "error", "* not a valid number");
        setfocus(valfield);
        return false;
    }
    msg (infofield, "warn", "");
    
    return true;
}
