function CustomError(number,description) {
    this.number = number
    this.description = description
}
function parseNumber(str) {
  if (str==void 0) return Number.NaN
  if (!isNaN(+str)) return +str
  var save = str, pref = /^[^0-9]+/, suff = /[^0-9]+$/, prefix = pref.exec(str), suffix = suff.exec(str), fac = 1;
  if (suffix) {
    if (suffix[0].match(/bi?l?l?i?o?ns?/)) fac = 1000000000;
    else if (suffix[0].match(/mi?l?l?i?o?ns?/)) fac = 1000000;
    else if (suffix[0].match(/tho?u?s?a?n?d?s?/)) fac = 1000;
    else if (suffix[0].match(/hund/)) fac = 100;
  }
  str=str.match(/[0-9,.]+/)||''
  if (str!='') {
    str=str[0].replace(/,/,'')
    str*=fac
    str.prefix = prefix
    str.suffix = suffix
  }
  return str||Number.NaN
}
Array.prototype.add = function (w) {var l=this.length;this[l]=w;return l;}
RegExp.prototype.toString = function () {return this.source}
RegExp.EMAIL = /^([\w-_]+\.)*[\w-_]+\@([\w-_]+\.)+[a-zA-Z]{2,12}$/;
RegExp.URL = /((\w+):\/\/)?(\w+\.+\w+(\.\w+)*)(\/(\S*))?/;
RegExp.NOT_VALID_TELEPHONE = /[^0-9\s\.\(\)\+\/x(ext)(xtn)]/g;
RegExp.COUNT_DIGITS = /(\d)/g;
String.prototype.isValidTelNo = function () {
  var v = this.match(RegExp.COUNT_DIGITS)
  if (v&&v.length>6&&!this.match(RegExp.NOT_VALID_TELEPHONE)) return true
  return new CustomError(0,'\''+this+'\' is not a valid telephone number')
}
String.prototype.isValidLongNo = function (min,max) {
      if (this.match(new RegExp("^\\d{"+min+","+max+"}$"))) return true;
      if (this.match(/[^\d]/)) return new CustomError(0,'\''+this+'\' should only contain numbers');
      if (min==max) return new CustomError(0,'\''+this+'\' should be '+min+' digits long');
   return new CustomError(0,'\''+this+'\' should be '+min+'-'+max+' digits long');
}
String.prototype.isEmpty = function () {
  if (!this.length) return true
  if (this.match(/^\s+$/)) return true
  return false
}
String.prototype.checkLength = function (min,max) {
  min=min||0
  max=max||512
  if (this.length<min) return new CustomError(0,'text is too short (minimum is '+min+' characters)')
  if (this.length>max) return new CustomError(0,'text is too long (maximum is '+max+' characters)')
  return true  
}
String.prototype.trim = function () {
  return this.replace(/(^\s+)|(\s+$)/g,'')
}
String.prototype.isEmail = function () {
  if (this.match(RegExp.EMAIL)) return true
}
String.prototype.isUrl = function (opt) {
  if (opt&&!this.length) return true
  if (this.match(RegExp.URL)) return true
}
String.prototype.isValidEmail = function () {
  if (this.match(RegExp.EMAIL)) return true
  return new CustomError(0,'\''+this+'\' is not a valid email address')
}
String.prototype.isValidUrl = function () {
  if (this.match(RegExp.URL)) return true
  return new CustomError(0,'\''+this+'\' is not a valid URL')
}
String.prototype.isValidNumber = function (low,high) {
	if (isNaN(this)) return new CustomError(0,'\''+this+'\' is not a valid number');
	var t = +this;
	if (low != null && high != null) {
		if (t<low) {
			return new CustomError(0,'\''+this+'\' is less than '+low);
		}
		if (t>high) {
			return new CustomError(0,'\''+this+'\' is greater than '+high);
		}
	}
	return true;
}
String.prototype.isValidAsCurrency =  function () {
  var m
  if (m=this.match(/^(\D*)\d*(\.\d*)$/)) {
    if (m[1]) return new CustomError(0,'\''+this+'\' should not contain a prefix or currency symbol')
    if (m[2].length>3) return new CustomError(0,'\''+this+'\' should only have 2 decimal places')
    return true
  }
  if (this.match(',')) return new CustomError(0,'\''+this+'\' should not contain commas')
  return new CustomError(0,'\''+this+'\' is not a valid currency figure')
}
String.prototype.isValidPercentage = function (dp) {
  var m
  if (m=this.match(/^(\d*)(.)(\d*)%?$/)) {
    if (m[1]&&!m[2]&&m[1].match(/^0{2,}/)) return new CustomError(0,'\''+this+'\' appears to be missing a decimal point')
    if (parseFloat(this)>100) return new CustomError(0,'\''+this+'\' is greater than 100%')
    return true
  }
  return new CustomError(0,'\''+this+'\' is not a valid percentage')
}
function isValidDate (list) {
  var day = list[1].value||'-';
  var month = list[0].value|| '-';
  var year = list[2].value||'-';
	  var yearAdd = 0 ;
	  if (document.layers) {
		  yearAdd = 1900;
	  }	  
  var d = new Date(+year,+month-1,+day)


  if (d.getDate()==+day && (d.getMonth())==+month-1 && ((d.getYear()+yearAdd)==+year || d.getFullYear()==+year)) return true
	//alert(d.getDate()+' '+day+'\n'+d.getMonth()+' '+month+'\n'+d.getYear()+' '+year+'\n'+d.getFullYear()+' '+year);
  return new CustomError(0,month+'/'+day+'/'+year+' is not a valid date')
}

function oneFieldRequired (list) {
  for (var i=0,val=false;i<list.length;i++) {
   if (val) break;
   val = !list[i].value.toString().isEmpty();
}
  if (val) return true
  else return new CustomError(0,'Please fill out one of the desired fields');  
}
function oneFieldOnly (list) {
  for (var i=0,val=0;i<list.length;i++) {
   if (!list[i].value.toString().isEmpty()) val++;
}
  if (val==1) return true
  else return new CustomError(0,'Please fill out one (and only one) of the desired fields');  
}
function Validate(form,silent) {
  Validate.currentForm = form;
  form.onreset = function () {Validate.resetErroredElements()}
  Validate.ErroredElements = [];
  Validate.errorMessage = [];
  Validate.errorMessage.addError = Validate.errorMessageAdd;
  var validate , currentGroup, currentGroupList = [];
  var elms = form.elements, valid, emptyCount = 0, l=elms.length;
  for (var i=0;i<l;i++) {
    var elm = elms[i];
	  if (!document.layers&&!document.all&&elm.type!='hidden') elm.focus()
    var str
    if (elm.onblur&&(str=elm.onblur())) {
      elm.validator = Validate.getValidator(elm,str);
      valid = elm.validator.check(elm);
	    elm.title = valid.description||'';
      if (valid!=true) {
        if (valid.number==-1) emptyCount++;
        else if (Validate.errorMessage[Validate.errorMessage.length]!=(elm.validator.description+valid.description)) Validate.errorMessage.addError(elm.validator.description+valid.description)
        Validate.ErroredElements.add(elm)

      }
      if (elm.validator.hiddenField) {
        var ev = elm.validator
        if (String.prototype[ev.hiddenAction]) elms[ev.hiddenField].value = elm.value[ev.hiddenAction](elms[ev.hiddenField])
        else elms[ev.hiddenField].value = self[ev.hiddenAction](elm,elms[ev.hiddenField])
      }
      if (elm.validator.groupFunc) {
        var list = currentGroupList[elm.validator.groupName]
        if (!list) {
          list = currentGroupList[elm.validator.groupName] = new Validate.ValidateList(elm.validator.groupName,elm.validator.groupFunc);
          currentGroupList.add(list)
        }
        list.addElement(elm)
      }
    }
  }
  for (i=0;i<currentGroupList.length;i++) {
    Validate.checkGroup(currentGroupList[i]);
    }
  if (emptyCount) Validate.errorMessage.addError(emptyCount+' required field(s) were empty')
  Validate.onValidate(Validate.errorMessage,silent)
  if (Validate.errorMessage.length) return Validate.onCustomError(Validate.errorMessage,silent)
  return true
  }
  Validate.errorMessage = [];
  Validate.errorMessageAdd = function (message) {
    if (this[message] ) return
    this.add(message)
    this[message]=true;
  }
  Validate.checkGroup = function (group,simple) {
    var valid
  if (self[group.func]) valid = self[group.func](group.elementList)
  else alert('Debug: Group function '+group.func+' not found');
  if (simple) return valid
    if (valid!=true) {
      Validate.errorMessage.add((group.name? group.name+': ' : '')+valid.description)
    for (j=0;j<group.elementList.length;j++) {
        Validate.ErroredElements.add(group.elementList[j])
      }
  }
  }
  Validate.onValidate = function () {return true}
  Validate.validators = {};
  Validate.functions = {};
  Validate.getFunc = function (name) {
    return this.functions[name]||name
  }
  Validate.getValidator = function (elm,str) {
    if (this.validators[str]) return this.validators[str]
   return this.validators[str]= new this.Validator(str)  
  }
  

  Validate.setErroredElements = function () {
    if (!document.layers) {
      var elms = this.ErroredElements
      for (var i=0;i<elms.length;i++) {
        var e = elms[i]
        if (e.type=="radio"||e.type=="checkbox") continue;
        if (e.style.origColor == void 0) e.style.origColor = e.style.backgroundColor||''
        e.style.backgroundColor = this.CustomErrorColor
        e.onkeypress=e.onkeydown=e.onkeyup=e.onmouseup= Validate.elementCheck
        //e.onchange=
      }
      this.lastErroredElements = elms
    }
  }
  Validate.setElementStatus= function (list,valid) {
  	for (var i=0;i<list.length;i++)	{
    if (list[i].type=="radio") continue
    if (list[i].style.origColor == void 0) list[i].style.origColor = list[i].style.backgroundColor||''
		list[i].style.backgroundColor = valid==true ? list[i].style.origColor : Validate.CustomErrorColor 
		list[i].title = valid.description||''
	}
 }
  Validate.elementCheck = function () {
    if (this.type=="radio"||document.layers) return
    var test=this.validator.check(this);
	if (test==true) this.style.backgroundColor = this.style.origColor
	else this.style.backgroundColor = Validate.CustomErrorColor   
	this.title = test.description||''
    if (this.validateGroup) {
      test = Validate.checkGroup(this.validateGroup,true)
	  Validate.setElementStatus(this.validateGroup.elementList,test)
    }
  }
  Validate.resetErroredElements = function () {
    if (!document.layers) {
      var elms = this.currentForm.elements
      for (var i=0;i<elms.length;i++) {
         if (elms[i].style.origColor!=void 0) elms[i].style.backgroundColor = elms[i].style.origColor
      }
    }
  }
  Validate.ValidateList = function (name,func) {
    this.name = name;
    this.func = func;
    this.elementList = [];
  }
  Validate.ValidateList.prototype.addElement = function (elm) {
    this.elementList.add(elm)
    this.finalElement = elm
    elm.validateGroup = this
  }
  Validate.Validator = function (str) {
    var parseArray = str.split('_')
    this.description = this.formatDescription(parseArray[0])
    if (parseArray[1]!='opt') this.required = true
    if (parseArray[1]=='rad') this.radioButton = true
    if (parseArray[2]) {
      this.func = Validate.getFunc(parseArray[2])
      this.args=parseArray[3]||'()';
    }
    if (parseArray[4]&&parseArray[4]!='null') {
      this.groupFunc = Validate.getFunc(parseArray[4]);
      this.groupName = parseArray[5]||parseArray[4]
    }
    if (parseArray[6]) {
      this.hiddenField = parseArray[6]
      this.hiddenAction = parseArray[7]
    }
  }
  Validate.Validator.prototype.formatDescription = function (desc) {
    if (!desc||desc=='null') return ''
    return desc+': '
  }
  Validate.Validator.prototype.check = function (elm) {
    if (this.radioButton) return this.handleRadioButtons(elm)
    var value = elm.value||'';
    if (!value&&elm.options) value=elm.options[elm.selectedIndex||0].value||'';
    var empt = value.isEmpty();
    if (elm.type=="checkbox"&&elm.checked==false) empt = true;
    if (this.required&&empt) {
      var errNo = 0
      if (!this.description) errNo=-1
      return new CustomError(errNo,'field was empty')
    }
    if (!this.required&&empt) return true
    if (String.prototype[this.func]) {
      self.$temp = value
      return eval('self.$temp.'+this.func+this.args)
    }
    else if (self[this.func]) return self[this.func](value)
    else if (!this.func||this.func=='null') return true
    else alert('Debug: function '+this.func+' not found');
    return true
  }
  Validate.Validator.prototype.handleRadioButtons = function (elm) {
    !this.buttonGroup&&(this.buttonGroup = elm.form.elements[elm.name])
    var checked = false,i=0
    for (var i=0;i<this.buttonGroup.length&&!checked;i++) {
      checked = this.buttonGroup[i].checked
    }
    if (checked) return true
    else return new CustomError(0,'no choice made (not highlighted)')
  }



  function confirmPassword(list) {
    if (list.length!=2) alert('Debug: 2 password fields not found');
  if (list[0].value==list[1].value) return true
  else return new CustomError(0,'fields do not match')
  }
  
  
  
  Validate.CustomErrorColor = '#E0ECFF';
  Validate.CustomErrorDescription = 'light blue';
  Validate.onCustomError = function (errorMessage,silent) {
    if (silent) return false;
    Validate.setErroredElements();
    alert(
		'The following problems were encountered with the form:  \n'
	    +((!document.layers)? ('\nThe fields in question will be highlighted '+(this.CustomErrorDescription)) : '')+'\n\n  '
        + errorMessage.join('\n  ') 
		+ '\n\nPlease correct the problems and resubmit the form'
	)
  return false
  }
  Validate.functions = {
    pct : 'isValidPercentage',
    cur : 'isValidAsCurrency',
    num : 'isValidNumber',
    eml : 'isValidEmail',
    url : 'isValidUrl',
    grpDat : 'isValidDate',
    grpReq : 'oneFieldRequired',
    grpRad : 'oneFieldOnly',
    tel : 'isValidTelNo',
    cnf : 'confirmPassword',
    len : 'checkLength',
    lon : 'isValidLongNo',
    mus : 'mustAgree'
  }
  function setHidden(elm,hidden){
    var val = parseNumber(elm.value)
    var desc = elm.validator.description ? elm.validator.description+': ' : '';
    var correct = confirm(desc+'field with value: '+elm.value+' has been interpreted as: '+val)
  }

 
  // string validate format:
  
  //[field description]_[opt(ional)|req(uired)|rad(required radio))]_[(type of field (3) or null)]_([comma separated argument list])_[type of group]_[groupname]_[hidden fieldname]_[hidden field parsing function]
  
  function formSubmit(name) {
    var form = document.getElementById(name)
    if (!form.onsubmit||form.onsubmit()) form.submit()
  }
  function formReset(name) {
    var form = document.getElementById(name)
    form.reset()
  }
  
