// Validation code written by Computer Magic and Software Design
// Copyright � 2006
// rayp@cmagic.biz
// www.cmagic.biz
// Part of the Computer Magic Tool Kit (CMTK) at http://cmtk.cmagic.biz/

/* STEP 1:  To use this script, include it by adding the following line to your HEAD tag (note: adjust paths appropriatly)
<SCRIPT language="Javascript" src="http://cmtk.cmagic.biz/cmtk/js/cmtk_validator.js"></SCRIPT>
*/

/* STEP 2:  On your form tag, after action="??" add the onsubmit handler
<FORM method="Post" action="test" name="MyForm" onsubmit="return cmtk_Validate(this);">
....
</FORM>
*/

/* STEP 3:  Once your script is ready, you can add attributes to your inputs that will
			tell the script how to deal with them. For example, required will mean the script wont submit
			until the field has something entered in it.

*****NOTE: ThIs Is CaSe SeNsItIvE!!!

required="yes"	- This attribute makes the input a required field
		yes or true

errorMessage="Please fill this out.."  - This attribute allows you to enter a custom error message if this
		field isn't filled out. This will be in addition to the name of the input showing up.

displayName="Client Age"  - This attribute allows you to display a different name than the real name for
		the input. Input names are often ugly (e.g. a_full_name) and it would be nice for the error message
		to just say (Full Name).  This allows you to leave the real name of the input alone and still have the
		message look presentable to the user.

validationType="phone"  - This allows you to specify how to validate the input. The default is a simple check
		to make sure a value was entered (notempty). By changing this, you can validate email addresses, phone
		numbers, etc. This only works on text boxes and text areas.
			phone - Validate a phone number
			email - Validate an email address
                        dateYMD - Date in Year Month Day format
                        dateDMY - Date in Day Month Year format
                        dateMDY - Date in Month Day Year format                        
                        username - appropriate characters and lenght for a username (3-14 chars)
                        number - A valid integer number, 1 . and a - are ok
                        zip - A zip code (zip or zip+4)
                        url - A well formed URL - http(s):// required
			notempty - Just make sure they filled something in (default if left blank)
                        custom - Custom validation, not handled here, only on server side via event

                        EXPERIMENTAL VALIDATORS
                        * May not be implemented yet, not tested for production use
                        time - Various Time Formats - Experimental
                        regexp - enter your own reg exp pattern (verify that pattern
                            works with both javascript and PCRE pattern at: http://www.rexv.org/
                        ccard_number - Verify Visa,Master,Disc,Amex number
                        ccard_exp   - Verify CCard Expiration Date
                        ccard_cvv   - Verify the CVV code
                        

*/

// ===========================================================================================================
// Code section, do not change.
// ===========================================================================================================
// Used by the Confirm Password input
var cmtk_LastPassword = "";

function cmtk_Validate(frm) {
    inputs = frm.elements;
    for (i=0; i<inputs.length; i++ )
    {
        var input = inputs[i];
        // input.type == "checkbox"
        //alert(input.getAttribute("required"));
        if (!cmtk_isUndefined(input.getAttribute("required")) && (input.getAttribute("required").toLowerCase() == "yes" || input.getAttribute("required").toLowerCase() == "true" || input.getAttribute("required") == true ))
        {
            // If we find an input that has problems, lets flag it
            if (!cmtk_ValidateInput(input))
            {
                var msg = "Please fill out the required field: ";
                if (!cmtk_isUndefined(input.getAttribute("displayName")))
                {
                    msg += input.getAttribute("displayName");
                } else {
                    msg += input.getAttribute("name");
                }

                if (!cmtk_isUndefined(input.getAttribute("errorMessage")) && input.getAttribute("errorMessage") != null)
                {msg += "\n" + input.getAttribute("errorMessage");}

                alert(msg);
                input.focus();
                return false;
            }
        }
    }

    // Everything is ok, return true.
    return true;
}


function cmtk_ValidateInput(input) {
    //alert(input.name + ":" + input.type);
    if (input.type=="text" || input.type=="textarea")	{
        if (input.value == "") {
                return false;
        }
        // Use a pattern to check where needed
        if (!cmtk_isUndefined(input.getAttribute("validationType")))
        {
            var pattern = "";
            switch(input.getAttribute("validationType")) {
                case "phone": // phone num w or w out area code and dashes                    
                    pattern = "^(\(?\+?[0-9]*\)?)?[0-9_\- \(\)]*$";
                    break;                
                case "email":
                    //pattern = "^[a-z0-9!#$%&amp;'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&amp;'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$";
                    pattern = "^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+[\.]([a-zA-Z0-9\._-]+)+$";
                    //pattern = "^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$";
                    break;                
                case "dateDMY": // Date in the format dd/mm/yyyy or dd-mm-yyyy
                    pattern = "^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$";
                    //pattern = "^([0-9]){2}(\/|-){1}([0-9]){2}(\/|-){1}([0-9]){4}$";
                    break;
                case "dateYMD": //For yyyy-mm-dd or yyyy/mm/dd use:
                    pattern = "^(19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$";
                    break;
                case "dateMDY": // For mm-dd-yyyy or mm/dd/yyyy use:
                    pattern = "^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$";
                    //pattern = "^([0-9]){2}(\/|-){1}([0-9]){2}(\/|-){1}([0-9]){4}$";
                    break;
                case "time": // Match various time formats
                    pattern = "^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))$|^([01]\d|2[0-3])(:[0-5]\d){0,2}$";
                    break;
                case "username": // 3-14 chars w _ and numbers
                    pattern = "^[a-zA-Z0-9_]{3,14}$";
                    break;
                case "ip":
                    pattern = "^((\d\.)|(\d\d\.)|(1\d\d\.)|(2[0-4][0-9]\.)|(25[0-5]\.)){3}((\d)|(\d\d)|(1\d\d)|(2[0-4][0-9])|(25[0-5]))$";
                    break;
                case "number":
                    //pattern = "\b(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\b";
                    pattern = "^(-?)\d+(\.?\d+)$";
                    break;
                case "zip":
                    pattern = "^([0-9]{5})(-[0-9]{4})?$";
                    break;
                case "url":
                    pattern = "^http(s)?:\/\/[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(\/.*)?$";
                    break;
                case "ccard_number":
                    res = cmtk_LuhnCheck(input.value);
                    if(res == true) {
                        pattern = ".+";
                    } else {
                        pattern = "";
                    }
                    break;
                case "ccard_exp":
                    pattern = "^(0?\d|1[0-2])[-\.\/](\d\d)$";
                    break;
                case "ccard_cvv":
                    pattern = "^\d{3,4}$";
                    break;
                case "password":
                    // Require at least 4 characters here
                    // TODO: Integrate with ex password strength rules?
                    pattern = "^.{4,}$";
                    cmtk_LastPassword = input.value;
                    break;
                case "confirm_password":
                    // Make it match the password box                    
                    if (input.value != cmtk_LastPassword) {
                        //  Confirm Password didn't match!
                        cmtk_LastPassword = "";
                        return false;
                    } else {
                        // Confirm password matched!
                        cmtk_LastPassword = "";
                        return true;
                    }
                    
                    break;
                case "custom":
                    pattern = "";
                    // NOTE: Custom validation ONLY handled on the server side,
                    // just return true
                    return true;
                    break;
                default:
                    pattern = "";
                    break;
            }
            if (pattern != "") {
                // NOTE: if you use getattribute here, you get the original value in firefox, not the current one!
                var match = input.value.match(pattern);
                if (match == null)
                {
                    return false;
                }
            }
        } else {
            // Assume notempty when validationtype is empty
            if (input.value == "") {
                return false;
            }
        }
    }else if (input.type=="checkbox") {
        if (input.checked != true) {
            return false;
        }
    }else if (input.type=="radio") {
    }else if (input.type=="file") {
        if (input.value=="") {
            return false;
        }
    }else if (input.type=="select-one" || input.type=="select")	{
        if (input.value=="") {
            return false;
        }
    }
    return true;
}


// Utility functions

function cmtk_isAlien(a) {
   return cmtk_isObject(a) && typeof a.constructor != 'function';
}
function cmtk_isArray(a) {
    return cmtk_isObject(a) && a.constructor == Array;
}
function cmtk_isBoolean(a) {
    return typeof a == 'boolean';
}
function cmtk_isEmpty(o) {
    var i, v;
    if (cmtk_isObject(o)) {
        for (i in o) {
            v = o[i];
            if (cmtk_isUndefined(v) && cmtk_isFunction(v)) {
                return false;
            }
        }
    }
    return true;
}
function cmtk_isFunction(a) {
    return typeof a == 'function';
}
function cmtk_isNull(a) {
    return typeof a == 'object' && !a;
}
function cmtk_isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}
function cmtk_isObject(a) {
    return (a && typeof a == 'object') || cmtk_isFunction(a);
}
function cmtk_isString(a) {
    return typeof a == 'string';
}
function cmtk_isUndefined(a) {
	var ret = false;
	if (a == null) {
		ret = true;
	}
	if (typeof a == 'undefined') {
		ret = true;
	}
    return ret;
}


function cmtk_LuhnCheck(ccnum) {

  // remove non digits
  ccnum=ccnum.replace(/\D/g, '');

  // Set the string length and parity
  var number_length=ccnum.length;
  var parity=number_length % 2;

  // Loop through each digit and do the maths
  var total=0;
  for (i=0; i < number_length; i++) {
    var digit=ccnum.charAt(i);
    // Multiply alternate digits by two
    if (i % 2 == parity) {
      digit=digit * 2;
      // If the sum is two digits, add them together (in effect)
      if (digit > 9) {
        digit=digit - 9;
      }
    }
    // Total up the digits
    total = total + parseInt(digit);
  }

  // If the total mod 10 equals 0, the number is valid
  if (total % 10 == 0) {
    return true;
  } else {
    return false;
  }

}

function cmtk_GetInputFromForm(frm, input_name) {
    var ret = null;    
    if (frm == null || frm == undefined) {return ret;}
    
    inputs = frm.elements;
    for (i=0; i<inputs.length; i++ )
    {
        var input = inputs[i];
        
        if (input.getAttribute("name") == input_name) {
            ret = input;            
            break;
        }
    }

    // Return the found input or null if none found
    return ret;
}

function cmtk_OnCMTKFormOnSubmit(frm) {
    // Function to deal with CMTK forms when they are submitted.
    //alert('Validating...');
    //alert(frm.action);
    var action = frm.action.substr(-4);
    // Make sure the
    var ret = cmtk_Validate(frm);
    //alert('Validate: ' + ret);
    if (ret == false) {return ret;}
    
    // Do we need to package the form up for an ajax request or let it go through?
    if (action == 'ajax') {
        // Ajax form, use the source url as the postback if 'ajax' specified        
        var _input = cmtk_GetInputFromForm(frm, 'cmtk_form_source_url');        
        if (_input != null) {
            var post_url = _input.value;
            //alert('Posting To: ' + post_url);
            
            // Get the form ID (guid, not form name)
            var form_guid_input = cmtk_GetInputFromForm(frm, 'cmtk_form_id');
            //alert(form_guid_input);
            var form_guid = "";
            if (cmtk_isObject(form_guid_input)) {
                form_guid = form_guid_input.value;
                //alert('Form GUID: ' + form_guid)
            }
            // Hide the form div
            $("#cmtk_frm_" + form_guid).hide();
            // Show the loading div
            $("#cmtk_frm_loading_" + form_guid).show();            
            
            // Start up the ajax post
            var data_string = $("#" + frm.id).serialize();
            $.ajax( {
                type: "POST",
                url: post_url,
                data: data_string,
                success: function (data) {
                    // Show the success message
                    //alert('Form Submitted!\n' + data_string + '\nResponse\n' + data);
                    // Hide the loading div
                    $("#cmtk_frm_loading_" + form_guid).hide();
                    // Show the success message if no data returned
                    if (data == "") {
                        $("#cmtk_frm_success_message_" + form_guid).show();
                    } else {                        
                        // Set the form div to the data and show it.
                        $("#cmtk_frm_" + form_guid).show();
                        $("#cmtk_frm_container_" + form_guid).parent.html(data);                        
                    }                    
                },
                error: function (data, error_type, ex_obj) {
                    // Show error
                    alert('Form Submit Error!\n');
                    // Hide the loading div
                    $("#cmtk_frm_loading_" + form_guid).hide();                    
                    // Show the form div                    
                    $("#cmtk_frm_" + form_guid).show();
                    // Show the error
                    $("#cmtk_frm_error_message_" + form_guid).html(data);
                },
                complete: function() {
                    // Don't do anything here, stub function
                    //alert('Form Submit Complete!');
                }
            } );
            
            // Return false so that the form doesn't submit normally since we
            // are using ajax
            return false;
        } else {
            // Input was not found in this form
            //alert('Input Not Found!');
        }
    }
}

