/*
FormValidation.js v. 1.0.4: A JavaScript form validation library.
Copyright (c) 2001, 2002, 2003, 2004, Paul Strack

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
function addEvent(obj, evType, fn){
 if (obj.addEventListener){
   obj.addEventListener(evType, fn, true);
   return true;
 } else if (obj.attachEvent){
   var r = obj.attachEvent("on"+evType, fn);
   return r;
 } else {
   return false;
 }
}

function Validator(label) {
  this.label = label;
}

function initFormValidation() {
  for (var i=0; i<document.forms.length; i++) {
    var form = document.forms[i];
    form.getIterator = function() {return new FormIterator(this);}
    form.validate = form_validate;
    form._validate = _form_validate;
    form.onsubmit = function() { return this.validate();}
    for (var j=0; j<form.length; j++) {
      initFieldValidation(form.elements[j]);
    }
    initFormData(form);
  }

  for (var i=0; i<document.forms.length; i++) {
    for (var j=0; j<form.length; j++) {
      var field = form.elements[j];
      if (field.format) field.format();
      if (field.compute) field.compute();
    }
  }
}


function initFormData(form) {
  for (var i=0; i<form.length; i++) {
    var element = form.elements[i];
    var name = element.name;

    if ((name != null) && (name != "")) {
      name = name.charAt(0).toUpperCase() + name.substring(1);
      var target = "document.forms[0].elements[" + i + "]";
      var baseObject = formdata;
      var index = nonRadioIndex(element);

      if (index >= 0) {
        if (!formitems[index]) {
          formitems[index] = new Object();
        }
        baseObject = formitems[index];
      }

      var getter = "return " + target + ".getValue();";
      if (element.parse) {
        getter = "return " + target + ".parse();";
      }
      baseObject["get" + name] = new Function(getter);

      var setter = target + ".setValue(value);";
      if (element.format) {
        var setter = target + ".setValue(validations['" + 
                     element.name + "'].format(value));";
      }
      baseObject["set" + name] = new Function("value", setter);

      if (element.getText) {
        var getText = "return " + target + ".getText();";
        baseObject["get" + name + "Text"] = new Function(getText);
      }

      if (element.compute) {
        var compute = "return " + target + ".compute();";
        baseObject["compute" + name] = new Function(compute);
      }
    }
  }
}

function formatInteger(value) {
  value = "" + value; 
  if (value == "") return "";
  value = parseInteger(value);
  if (isNaN(value)) {
    return "ERROR:" + NUMBER_ERROR.replace("{0}", this.label);
  } else {
    return "" + value; 
  }
}

function formatSignedInteger(value) {
  value = "" + value; 
  if (value == "") return "";
  value = parseSignedInteger(value);
  if (isNaN(value)) {
    return "ERROR:" + NUMBER_ERROR.replace("{0}", this.label);
  } else {
    return "" + value; 
  }
}


function formatDecimal(value) {
  value = "" + value; 
  if (value == "") return "";
  value = parseDecimal(value);

  if (isNaN(value)) {
    return "ERROR:" + NUMBER_ERROR.replace("{0}", this.label);
  } else if (this.scale != null) {
    
    value += parseFloat("1E-" + this.scale)/2;
  }

  value += ""; 
  if (value.charAt(0) == ".") {
    value += "0";
  }

  if ((this.scale != null) && (value != "")) {
    var decimalPlace = value.indexOf(".");
    var decimalPart = "";
    if (decimalPlace < 0) {
      decimalPart = ".";
    } else {
      var decimalEnd = decimalPlace + this.scale + 1;
      decimalPart = value.substring(decimalPlace, decimalEnd);
      value = value.substring(0, decimalPlace);
    }
    while (decimalPart.length < (this.scale + 1)) {
      decimalPart += "0";
    }
    value += decimalPart;
  }

  return value;
}


function formatSignedDecimal(value) {
  value = "" + value; 
  var sign = "";

  while (value.charAt(0) == " ") value = value.substring(1);
  if (value.charAt(0) == "-") sign = "-";

  var result = formatDecimal(value);
  if (result.indexOf("ERROR:") == 0) {
    return "ERROR:" + NUMBER_ERROR.replace("{0}", this.label);
  } else {
    return sign + result;
  }
}

function formatCurrency(value) {
  value = "" + value; 
  if (value == "") return "";
  value = parseDecimal(value);

  if (isNaN(value)) {
    return "ERROR:" + NUMBER_ERROR.replace("{0}", this.label);
  } else {
        value += 0.005;
  }

  value += ""; 
  if (value.charAt(0) == ".") {
    value += "0";
  }

  var decimalPlace = value.indexOf(".");
  var decimalPart = "";
  if (decimalPlace < 0) {
    decimalPart = ".";
  } else {
    var decimalEnd = decimalPlace + 3;
    decimalPart = value.substring(decimalPlace, decimalEnd);
    value = value.substring(0, decimalPlace);
  }
  while (decimalPart.length < 3) {
    decimalPart += "0";
  }

  var newValue = "";
  for (var i=value.length; i>3; i-=3) {
    newValue = "," + value.substring(i-3, i) + newValue;
  }
  newValue = "$" + value.substring(0,i) + newValue + decimalPart;

  return newValue;
}

function formatSignedCurrency(value) {
  value = "" + value; 
  value += ""; 
  var sign = "";

  while (value.charAt(0) == " ") value = value.substring(1);
  if (value.charAt(0) == "-") sign = "-";

  var result = formatCurrency(value);
  if (result.indexOf("ERROR:") == 0) {
    return "ERROR:" + NUMBER_ERROR.replace("{0}", this.label);
  } else {
    return sign + result;
  }
}

function formatPhone(value) {
  if (value == "") return "";

  value = stripNonNumeric(value);
  if (value.length > 3) {
    var oldValue = value;
    value = value.substring(0,3) + "-" + value.substring(3,6);
    if (oldValue.length > 6) {
      value += "-" + oldValue.substring(6,10);
    }
  }

  if (value.length != 12) {
    return "ERROR:" + PHONE_ERROR.replace("{0}", this.label);
  } else {
    return value;
  }
}


function formatSSN(value) {
  if (value == "") return "";

  value = stripNonNumeric(value);
  if (value.length > 3) {
    var oldValue = value;
    value = value.substring(0,3) + "-" + value.substring(3,5);
    if (oldValue.length > 5) {
      value += "-" + oldValue.substring(5,9);
    }
  }

  if (value.length != 11) {
    return "ERROR:" + SSN_ERROR.replace("{0}", this.label);
  } else {
    return value;
  }
}

function formatPostal(value) {
  if (value == "") return "";

  value = stripNonNumeric(value);
  if (value.length > 5) {
    value = value.substring(0,5) + "-" + value.substring(5,9);
  }

  if ((value.length != 5) && (value.length != 10)) {
    return "ERROR:" + POSTAL_ERROR.replace("{0}", this.label);
  } else {
    return value;
  }
}

function formatEmail(value) {
  if (value == "") return "";

  value += ""; 
  var indexOfAtSign = value.indexOf("@");
  var indexOfPeriod = value.lastIndexOf('.');

  if (value.indexOf(" ") >= 0) {
    return "ERROR:" + NO_SPACE_ERROR.replace("{0}", this.label);
  } else if (indexOfAtSign < 1) {
    return "ERROR:" + EMAIL_ERROR.replace("{0}", this.label);
  } else if (value.indexOf("@", indexOfAtSign+1) >= 0) {
    return "ERROR:" + EMAIL_ERROR.replace("{0}", this.label);
  } else if ((indexOfPeriod-indexOfAtSign) < 2) {
    return "ERROR:" + EMAIL_ERROR.replace("{0}", this.label);
  } else if ((value.length - indexOfPeriod) < 3) {
    return "ERROR:" + EMAIL_ERROR.replace("{0}", this.label);
  } else {
    return value;
  }
}

function formatDate(value) {
  if (value == "") return "";
  var date = parseDate(value);
  if (isNaN(date)) {
    return "ERROR:" + DATE_ERROR.replace("{0}", this.label);
  } else {
    var month = date.getMonth()+1;
    var day = date.getDate();
    var year = date.getFullYear();
    return month + "/" + day + "/" + year;
  }
}

function parseInteger(value) {
  return parseInt(stripNonDecimal(value));
}

function parseSignedInteger(value) {
  value += ""; 
  while (value.charAt(0) == " ") {
    value = value.substring(1);
  }
  var sign = 1;
  if (value.charAt(0) == "-") {
    sign = -1;
  }
  return sign * parseInteger(value);
}


function parseDecimal(value) {
  return parseFloat(stripNonDecimal(value));
}


function parseSignedDecimal(value) {
  value += ""; 
  while (value.charAt(0) == " ") {
    value = value.substring(1);
  }
  var sign = 1;
  if (value.charAt(0) == "-") {
    sign = -1;
  }
  return sign * parseDecimal(value);
}

function parseCurrency(value) {
  return parseDecimal(value);
}


function parseSignedCurrency(value) {
   return parseSignedDecimal(value);
}

function parseDateWithZero(value){
	var returnValue = value;	
	if(value.length<2){
		if(value.charAt(0)=='0'){
			returnValue = value.charAt(1);
		} else {
			returnValue = parseInt(value);
		}
	} 
	return returnValue;
}

function parseDate(value) {
  if ((typeof value == "object") && (value.constructor == Date)) {
    return value;
  }
  value += ""; 
  var date = NaN;
  var dateArray = value.split("/");
  
  if (dateArray.length != 3) {
    dateArray = value.split("-");
  }
  if (dateArray.length == 3) {
    var month;
	var day;
	var year = parseInt(dateArray[2]);
    month = parseDateWithZero(dateArray[0]);
	day = parseDateWithZero(dateArray[1]);
  	
    if (year < 100) {   
      var today = new Date();
      var todayYear = today.getFullYear();
      var century = parseInt(todayYear / 100);
      year = 100 * century + year;

      if ((year - todayYear) > 30) {
        year = year - 100;
      }

      if ((todayYear - year) > 70) {
        year = year + 100;
      }
    }

    if (!(isNaN(day) || isNaN(month) || isNaN(year))) {
      date = new Date(year, month-1, day);

      var newMonth = date.getMonth()+1;
      var newDay = date.getDate();
      var newYear = date.getFullYear();
      if ( (newYear != year) || (newMonth != month) ||
           (newDay != day) ) {
        date = NaN;
      }
    }
  }
  return date;
}

function stripNonNumeric(value) {
  var result = "";
  var c;              

  value += ""; 

  for (var i=0; i<value.length; i++) {
    c = value.charAt(i);
    if ((c >= "0") && (c <= "9")) {
      result += c;
    }
  }
  return result;
}


function stripNonDecimal(value) {
  var result = "";
  var c;              

  value += ""; 

  for (var i=0; i<value.length; i++) {
    c = value.charAt(i);
    if (((c >= "0") && (c <= "9")) || (c == ".")) {
      result += c;
    }
  }
  return result;
}

function text_getValue() {
  return this.value;
}

function text_setValue(value) {
  this.value = value;
}

function select_getValue() {
  var result = "";

  var index = this.selectedIndex;
  if (index >= 0) {
    result = this.options[index].value;
  }

  return result;
}

function select_getText() {
  var result = "";

  var index = this.selectedIndex;
  if (index >= 0) {
    result = this.options[index].text;
  }

  return result;
}

function select_setValue(value) {
  var index = -1;

  for (var i=0; i<this.options.length; i++) {
    if (this.options[i].value == value) {
      index = i;
      break;
    }
  }

  this.selectedIndex = index;
}

function checkbox_getValue() {
  var result = "";

  if (this.checked == true) {
    result = this.value;
  }

  return result;
}


function checkbox_setValue(value) {
  if (value) {
    this.checked = true;
  } else {
    this.checked = false;
  }
}

function group_getValue() {
  var result = "";

  for (var i=0; i<this.length; i++) {
    if (this[i].checked == true) {
      result = this[i].value;
    }
  }

  return result;
}

function group_setValue(value) {
  for (var i=0; i<this.length; i++) {
    if (this[i].value == value) {
      this[i].checked = true;
    } else {
      this[i].checked = false;
    }
  }
}

function radio_getValue() {
  return this.form[this.name].getValue();
}

function radio_setValue(value) {
  this.form[this.name].setValue(value);
}

function checkRequired(field) {
  var error = ""; 

  if ( (field.required == true) && 
       ((field.getValue() == "") || (trim(field.getValue()) == '<br />'))) {
    error += "    - " + field.label;
    var index = nonRadioIndex(field) + 1;
    if (index > 0) {
      error += ITEM_MSG.replace("{0}", index);
    }
    error += "\n";
  }

  return error;
}

function checkRange(field) {
  var value = parseSignedDecimal(field.getValue());
  if (isNaN(value)) return "";

  var error = ""; 
  var label = field.label;
  var max = field.max;
  var min = field.min;

  if ((min != null) && (max != null)) {
    if ((value < min) || (value > max)) {
      error = RANGE1_ERROR.replace("{0}", label);
      error = error.replace("{1}", field.formatValue(min));
      error = error.replace("{2}", field.formatValue(max));
    }
  } else if (min != null) {
    if ((value < min)) {
      error = RANGE2_ERROR.replace("{0}", label);
      error = error.replace("{1}", field.formatValue(min));
    }
  } else if (max != null) {
    if ((value > max)) {
      error = RANGE3_ERROR.replace("{0}", label);
      error = error.replace("{1}", field.formatValue(max));
    }
  }

  return error;
}

function checkLength(field) {
  var value = field.getValue();
  if (value == null) return "";
  var length = value.length;
  var error = ""; 
  var label = field.label;
  var minlength = field.minlength;
  var maxlength = field.maxlength;

  if (value == '' || value == null) {
  	return "";
  }
  
  if ((minlength != null) && (maxlength != null)) {
    if ((length < minlength) || (length > maxlength)) {
      if (minlength == maxlength) {
        error = LENGTH0_ERROR.replace("{0}", label);
        error = error.replace("{1}", maxlength);
      } else {
        error = LENGTH1_ERROR.replace("{0}", label);
        error = error.replace("{1}", minlength);
        error = error.replace("{2}", maxlength);
      }
    }
  } else if (minlength != null) {
    if ((length < minlength)) {
      error = LENGTH2_ERROR.replace("{0}", label);
      error = error.replace("{1}", minlength);
    }
  } else if (maxlength != null) {
    if ((length > maxlength)) {
      error = LENGTH3_ERROR.replace("{0}", label);
      error = error.replace("{1}", maxlength);
    }
  }

  return error;
}

function field_format() {
  var value = validations[this.name].format(this.getValue());
  value += ""; 
  if (value.indexOf("ERROR:") == 0) {
    return value.substring(6);
  } else {
    this.setValue(value);
    return "";
  }
}

function field_parse() {
  return validations[this.name].parse(this.getValue());
}

function field_validate() {
  var error = ""; 

  if (!this.label) return;


  if (this.format) error += this.format();
  error += checkRange(this);
  error += checkLength(this);
  if (this.compute) error += this.compute();


  if (error != "") {
    this.focus();
  }
}

function form_validate() {
  if (FORM_IS_SUBMITTED) return false;

  var error = "";         
  var missingFields = ""; 
  var checkFieldComputations = false;
  
  i = this.getIterator();
  
  if (this.compute) {
    error += this.compute();
  } else {
    checkFieldComputations = true;
  }
  
  while (i.hasNext()) {
    var field = i.next();
    
    missingFields += checkRequired(field);
    if (field.format) error += field.format();
    error += checkRange(field);
    error += checkLength(field);
    if (checkFieldComputations && field.compute) {
      error += field.compute();
    }
  }

  if (missingFields != "") {
    error = REQUIRED_ERROR.replace("{0}", missingFields) +
            error;
  }

  if (error == "") { 
    FORM_IS_SUBMITTED = true;
    return true;     
  } else {           
    alert(error);    
    return false;    
  }
}

function _form_validate() {
  var error = "";         
  var missingFields = ""; 
  var checkFieldComputations = false;
  
  i = this.getIterator();
  
  if (this.compute) {
    error += this.compute();
  } else {
    checkFieldComputations = true;
  }
  
  while (i.hasNext()) {
    var field = i.next();
    
    missingFields += checkRequired(field);
    if (field.format) error += field.format();
    error += checkRange(field);
    error += checkLength(field);
    if (checkFieldComputations && field.compute) {
      error += field.compute();
    }
  }

  if (missingFields != "") {
    error = REQUIRED_ERROR.replace("{0}", missingFields) +
            error;
  }

  if (error == "") { 
    return true;     
  } else {           
    return false;    
  }
}


function FormIterator(form) {
  this.form = form;
  this.count = 0;

  this.hasNext = function() { 
    return(this.count < this.form.length);
  }

  this.next = function() {
    var field = this.form[this.count];
    do {
      this.count++;
    } while ((this.count<this.form.length) && 
             (!(this.form[this.count].label) || 
              isNotFirstRadioButton(this.form[this.count])));
    return field;
  }

  if (!(this.form[this.count].label)) {
    this.next();
  }
}

function goToNextEditableField(field) {
  var index = -1;
  var elements = field.form.elements;
  for (i=indexInForm(field); i<elements.length; i++) {
    if (!elements[i].readonly) {
      index = i;
      break;
    }
  }
  if (index > 0) {
    elements[index].focus();
  } else {
    field.blur();
  }
}

function initFieldValidation(field) {
  var name = field.name;

  if (validations[name]) {
    var validationsItem = validations[name];

    if (validationsItem.datatype) {
      var formatFunction = "format" + validationsItem.datatype;
      var parseFunction = "parse" + validationsItem.datatype;
      if (window[formatFunction]) {
        validationsItem.format = window[formatFunction];
      }
      if (window[parseFunction]) {
        validationsItem.parse = window[parseFunction];
      }
    }

    for (property in validationsItem) {
      if (property == "parse") {
        field.parse = field_parse;
        field.parseValue = validationsItem.parse;
      } else if (property == "format") {
        field.format = field_format;
        field.formatValue = validationsItem.format;
      } else {
        field[property] = validationsItem[property];
      }
    }
  }

  field.validate = field_validate;
  if (field.readonly) {
    field.onfocus = function() { goToNextEditableField(this); }
  }

  if (field.type=="checkbox") {
    field.getValue = checkbox_getValue;
    field.setValue = checkbox_setValue;
    field.onclick = function() { this.validate(); }
  } else if (field.type=="radio") {
    field.getValue = radio_getValue;
    field.setValue = radio_setValue;
    field.onclick = function() { this.validate(); }

    if (isFirstRadioButton(field)) {
      var group = field.form[field.name];
      group.getValue = group_getValue;
      group.setValue = group_setValue;
      if (validations[name]) {
        var validationsItem = validations[name];
        for (property in validationsItem) {
          if (property == "parse") {
            group.parse = function() { return this[0].parse(); }
          } else if (property == "format") {
            group.format = function() { return this[0].format(); }
          } else {
            group[property] = validationsItem[property];
          }
        }
      }
    }
  } else if (field.type=="select-one") {
    field.getValue = select_getValue;
    field.setValue = select_setValue;
    field.getText = select_getText;
    field.changed = false;

    field.onchange = function() { this.changed = true; }
    field.onblur = function() { 
      if (this.changed) {
        this.changed = false;
        this.validate();
      }
    }
  } else if ( (field.type=="text") ||
              (field.type=="hidden") ||
              (field.type=="textarea") ||
              (field.type=="file") ||
              (field.type=="password") ) {
    field.getValue = text_getValue;
    field.setValue = text_setValue;
    field.onchange = function() {this.validate();}
  }
}

function indexInForm(field) {
  var elements = field.form.elements;
  var index = -1;
  for (i=0; i<elements.length; i++) {
    if (elements[i] == field) {
      index = i;
      break;
    }
  }
  return index;
}

function indexInGroup(field) {
  var index = -1;
  var group = field.form[field.name];
  if ((typeof group == "object") && (group.length)) {
    for (var i=0; i<group.length; i++) {
      if (group[i] == field) {
        index = i;
        break;
      }
    }
  }
  return index;
}

function nonRadioIndex(field) {
  if (field.type != "radio") {
    return indexInGroup(field);
  } else {
    return -1;
  }
}

function radioIndex(field) {
  if (field.type == "radio") {
    return indexInGroup(field);
  } else {
    return -1;
  }
}

function isFirstRadioButton(field) {
  return(radioIndex(field)==0);
}

function isNotFirstRadioButton(field) {
  return(radioIndex(field)>0);
}

function trim(s) {
  while (s.substring(0,1) == ' ') {
    s = s.substring(1,s.length);
  }
  while (s.substring(s.length-1,s.length) == ' ') {
    s = s.substring(0,s.length-1);
  }
  return s;
}

validations = new Object();
formdata = new Object();
formitems = new Array();

document.onload = function() { initFormValidation(); }
FORM_IS_SUBMITTED = false;


NUMBER_ERROR = "{0} is not a number.\n\n";

PHONE_ERROR = "{0} is not a valid phone number (###-###-#### including area code).\n\n";

SSN_ERROR = "{0} is not a valid Social Security Number (###-##-####).\n\n";

POSTAL_ERROR = "{0} is not a valid US Zip Code.\n\n";

NO_SPACE_ERROR = "{0} may not have spaces.\n\n";
EMAIL_ERROR = "{0} is not a valid email address (for example: name@domain.com).\n\n";

DATE_ERROR = "{0} is not a valid date.\n\n";

ITEM_MSG = " (item {0})";

RANGE1_ERROR = "The value for {0} must be between {1} and {2}.\n\n";

RANGE2_ERROR = "The value for {0} cannot be less than {1}.\n\n";

RANGE3_ERROR = "The value for {0} cannot be more than {1}.\n\n";

LENGTH0_ERROR = "{0} must be exactly {1} characters.\n\n";

LENGTH1_ERROR = "{0} must be between {1} and {2} characters.\n\n";

LENGTH2_ERROR = "{0} cannot be less than {1} characters.\n\n";

LENGTH3_ERROR = "{0} cannot be more than {1} characters.\n\n";

REQUIRED_ERROR = "The following required fields are missing:\n\n{0}\n";
