//<script language="javascript">
/*=============================================================================
 WebSolvers Framework Library
 Copyright 2003, WebSolvers, Inc., All Rights Reserved.

 Library Validation
 Cross-Browser/Platform common Validation library
 
 Revision History:
 6-4-03 Created

 Provides
 The following validation types are provided
	skip
	req([if variable][, [if value]])
	join([string])
	label('[string]')	- overrides the label provided in the form.
	read				- Sets the field to read only (does not
						allow input from user.
	onclick('[code]')	- Sets the onclick event handler
	onchange('[code]')	- Sets the onchange event handler
	end([string],[string],...) - value must end with one of the following.

  Notes:
=============================================================================

 The WebSolvers Framework Library may be used and/or modified by anyone owning
 the original work as it was incorporated into an original development project
 so long as this copyright notice and the comments above remain intact.  

 By using this code you agree to indemnify WebSolvers, Inc. from any liability
 that might arise from its use.

 This code may not be sold exclusively or as a part of other code without prior 
 written consent and is expressly forbidden.

 Obtain permission before redistributing this software over the Internet or 
 in any other medium. In all cases the copyright and header must remain intact. 
============================================================================= */

function processForm() {
  var i = 0;
  var frm = null;
  var strID = "";
  for(i = 0 ; i < processForm.arguments.length; i++) {
    strID = processForm.arguments[i];    if(strID && strID.elements)
      frm = strID;
    else if(strID && strID.length)      frm = document.forms[strID];
    if(frm)      validate._procForm(frm, document);  }
}

//======================================================================================
//                                 Internal Routines
//======================================================================================
function validate() {
  var i = 0, strArgs = "";    for(i = 0; i < validate.arguments.length; i++) {
    strArgs += ",validate.arguments[" + i + "]";  }  
  if(strArgs && strArgs.length) {    eval("processForm("+strArgs.substring(1,strArgs.length)+");");  }
    return this._toValue();
}

validate._init = function() {
  if(this.__inited)
    return;

  this._valid = new Array();  
    
  this.typeID = "valid";
  this.labelID = "label";
  this.defaultID = "default";
  
  this.reqField = "_REQ";
  this.reqMessage = "A required field is missing.";    
    
  this.__inited = 1;
}

validate._resync = function() {
  this._init();

  this.checkField = this._checkField;
  this.procType = this._procType;
  
  this.getType = this._getType;
  this.getLabel = this._getLabel;
  this.getDefault = this._getDefault;
  this.notify = this._notify;
  
  this.addValidator = this._addValidator;
}

validate._checkField = function(field) {
	var fields = null;
	var i = 0;

  this._resync();

  validate.procType(field);

	if(!field.validate)
		return true;

	if(field.type.substr(0,6).toLowerCase() == "select") {
		field.values = new Array();
		if(field.multiple) {
			for(i = 0; i < field.options.length; i++)
				if(field.options[i].selected)
					field.values.push(field.options[i].value);
		} else if(field.selectedIndex > -1 && field.selectedIndex < field.options.length) {
			field.values.push(field.options[field.selectedIndex].value);
		}
			
		return field.validate();
	} else if(field.type.toLowerCase() == "radio" || field.type.toLowerCase() == "checkbox") {
		fields = field.form.getElements(field.name);
		
		// If the field is the "parent" of "subs" we need to
		// process them all inline, but we only want
		// to run validation once for the entire group
		if(fields && fields.length && (fields[0] == field)) {
			field.values = new Array();
			if(field.checked)
				field.values[0] = field.value;
			for(i = 1; i < fields.length; i++) {
        validate.procType(fields[i]);
    		fields[i].values = new Array();
    		// If the "sub" element is checked we tag its value
    		if(fields[i].checked)
    		  fields[i].values[0] = fields[i].value;
    		// If the "sub" element validates we add its value to the "parent"
				if(fields[i].values.length && fields[i].isValid())
					field.values.push(fields[i].values[0]);
			}
		} else if(!fields || !fields.length) {
			field.values = new Array();
			if(field.checked)
				field.values[0] = field.value;
		} else {
		  //We skip calls to "sub" elements
		  return true;
		}
		return field.validate();
	} else {
		field.values = new Array(field.value);
		return field.validate();
	}
}

validate._procType = function(fld) {
	var type = this.getType(fld);
	var st = 0;
	var lt = -1;
	var pos = 0;
	var str = "";
	var func = null;
	var param = null;
	var preproc = null;
	var tag = null;
	var esc = "";
	var aryType = null;
	var aryOpt = null;
  var reType = /^(.+?)(?:\((.*?)\))?(?:\||$)/;
  var reParam = /^(?:'((?:[^']*'')*.*?)')|(?:"((?:[^"]*"")*.*?)")|(.*?)(?:,|$)/;

	var i = 0;
	
	if(fld.__isValidatable)
	  return fld;

  this._resync();

	fld._valFunc = new Array();
	fld._valParam = new Array();
	
	fld.validate = fieldObject_Validate;
	fld.isValid = fieldObject_IsValid;
	fld.isCircular = fieldObject_IsCircular;

  while(type && type.length && reType.test(type)) {
    aryType = reType.exec(type);

    type = type.substring(0, aryType.index) + type.substring(aryType[0].length, type.length);

		for(i = 0; i < this._valid.length; i++) {
			tag = this._valid[i];
			if(aryType[1].toLowerCase() == tag.tag) {
			  func = tag.func;
			  param = new Array();
			  if(tag.params) {
			    str = aryType[2];

			    while(str && str.length && reParam.test(str) && (tag.params == -1 || param.length < tag.params)) {
			      aryOpt = reParam.exec(str);

            var pval = '';
            
            if(aryOpt[1] || aryOpt[1] == 0) {
              pval += aryOpt[1].toString();
            }

            if(aryOpt[2] || aryOpt[2] == 0) {
              pval += aryOpt[2].toString();
            }

            if(aryOpt[3] || aryOpt[3] == 0) {
              pval += aryOpt[3].toString();
            }

            param.push(pval);

            str = str.substring(0, aryOpt.index) + str.substring(aryOpt[0].length, str.length);
			    }
			    aryOpt = null;
			  }
			  
		    if(func || preproc) {
		    	if(preproc) {
		    		preproc(fld, param);
		    	}
		    	if(func) {
		    		fld._valFunc[i = fld._valFunc.length] = func;
		    		fld._valParam[i] = param;
		    	}
		    	
		    	preproc = null;
		    	func = null;
		    	param = null;
		    }
			  
			}
		}
    
  }
  
  aryType = null;
	
	fld.__isValidatable = 1;
	
	return fld;
}

validate._notify = function(field) {
  this._resync();

	if(field.valError != " ") {
		if(field.type != "hidden" && field.focus)
			field.focus();
		alert(this.getLabel(field, field.valError));
	}
	
	return false;
}

validate._getType = function(field) {
  this._resync();

	if(field.length && !field.type)
		field = field[0];

	var type = field.getAttribute(this.typeID);

	return (type && type.length ? type : "str");
}

validate._getLabel = function(field, msg) {
  this._resync();

	if(field.length && !field.type)
		field = field[0];

	var label = field.getAttribute('_' + this.labelID);
	
	if(!label) {
		label = field.getAttribute(this.labelID);

		return (label && label.length ? label : field.name) + msg;
	} else {
		return label;
	}
}

validate._getDefault = function(field) {
  this._resync();

	if(field.length && !field.type)
		field = field[0];

	var def = field.getAttribute(this.defaultID);

	return (def && def.length ? def : "");
}

validate._addValidator = function(tag, func, prefunc, params, paramesc) {
	var idx = 0;
	var j = 0;
	var idx2 = 0;

	var type = new validatorObject(tag, func, prefunc, params, paramesc);

  this._resync();
	
	this._valid[idx = this._valid.length] = type;
	this._valid['T_'+tag] = idx;
	
	if(arguments.length > 5)
		for(j = 5; j < arguments.length; j++) {
			type = new validatorObject(arguments[j], func, prefunc, params, paramesc);
			this._valid[idx2 = this._valid.length] = type;
			this._valid['T_'+tag] = idx2;
		}
}

function validatorObject(tag, func, prefunc, params, paramesc) {
	this.tag = tag;
	this.func = func;
	this.preFunc = prefunc;
	this.params = params;
	this.paramEsc = paramesc;
}

validate._procForm = function(frm, doc) {
	var i = 0;
	var j = 0;
	var field = null;
	var req = null;

  frm._onsubmit = frm.onsubmit;
  frm.onsubmit = formObject_TmpOnSubmit;
  
	if(!frm.index && frm.index != 0)
		frm.index = i;

  if(!frm.getElement)
    frm.getElement = formObject_getElement;
  if(!frm.getElements)
    frm.getElements = formObject_getElements;

  req = frm.getElement(validate.reqField);
	if(req && req.value && req.value.length) {
		req = req.value.split(',');
		for(i = 0; i < req.length; i++) {
		  field = frm.getElements(req[i].trim());

      for(j = 0 ; j < field.length; j++) {				
				field[i][validate.typeID] = "req";
				field[i]['_' + validate.labelID] = validate.reqMessage;
				validate.procType(dhtml.quickNorm(field[i], doc));
			}
		}
	} else {
		for(i = 0; i < frm.elements.length; i++) {
			field = frm.elements[i];

			validate.procType(dhtml.quickNorm(field, doc));
		}
	}

	if(!frm.validate)
		frm.validate = formObject_Validate;

	if(!frm.lock)
		frm.lock = formObject_Lock;
	if(!frm.unlock)
		frm.unlock = formObject_Unlock;

	frm.onsubmit = frm._onsubmit;
	frm._onsubmit = null;

	return true;
}

function formObject_TmpOnSubmit() {
	alert('Please wait for the page to finish loading before submitting this form.');
	return false;
}

function formObject_Validate() {
	var i = 0;
	var func = null;

	for(i = 0; i < this.elements.length; i++)
		if(!validate.checkField(this.elements[i]))
			return false;

  if(!func)
    eval("func=window." + this.name + "_Validate;");
  if(!func)
    eval("func=window." + this.name + "_onValidate;");
  if(!func)
    eval("func=window." + this.name + "_OnValidate;");

  if(func && !func(this))
    return false;

	return true;
}

function formObject_Lock(strMsg, intSecs) {
	var cmd = "";
	
	if(this._locked) {
		alert(strMsg);
		return false;
	}
	
	this._locked = true;
	cmd = "document.forms[" + this.index + "].unlock();";
	window.setTimeout(cmd, intSecs * 1000);
	
	return true;
}

function formObject_Unlock() {
	this._locked = false;
}

function formObject_getElement(name, idx) {
  var field = this.elements[name];
  
  if(!field)
    return null;
  
  if(!idx || idx < 0)
    idx = 0;
  
  if(field.name && field.name == name)
    return field;
    
  if(field.length && idx < field.length)
    return field[idx];
}

function formObject_getElements(name) {
  var field = this.elements[name];

  if(!field)
    return new Array();
  
  if(field.name && field.name == name)
    return new Array(field);
    
  if(field.length)
    return field;
    
  return new Array();
}

function fieldObject_Validate() {
	if(!this.values) {
		alert("'" + this.name + ".validate()' should not be called directly please use '" + this.name + ".form.validate()' instead.");
	}
	if(!this.isValid())
		return validate.notify(this);
	else
		return true;
}

function fieldObject_IsValid() {
	var i = 0;
	var res = null;
	
	// If we are in a circular loop we just drop out assuming all is ok
	if(this.__inIsValid)
	  return true;
	  
	this.__inIsValid = 1;
	
	this.valError = null;

	for(i = this._valFunc.length-1; i > -1 && !this.valError; i--) {
		res = this._valFunc[i](this.values, this._valParam[i], this);
		if(res[0].length)
			this.valError = res[0];
		this.values = res[1];
	}
	
	this.__inIsValid = 0;
	
	return (!this.valError);
}

function fieldObject_IsCircular() {
  return this.__inIsValid;
}

function fieldObject_MakeValid(type, label, def) {
	dhtml.quickNorm(this);

	this.setAttribute(validate.typeID, type);
	this.setAttribute(validate.labelID, label);
	this.setAttribute(validate.defaultID, def);
}

function validator_Skip(value) {
	var l = new Array();
	for(var j = 0; j < value.length; j++) {
		if(value[j] && value[j].toString().length)
			l[l.length] = value[j];
	}

	return new Array("", l);
}

function validator_Req(value, params, elem) {
	var el = null;
	var val = null;
	var i = 0;
	var f = false;

  //If we have a parameter at position 0 it
  //means that we are only required if the
  //specified parameter is valid	
	if(params.length > 0) {
	  //Store the element specified
	  el = elem.form.getElement(params[0]);
		//If we cannot find the element we silently fail
		if(!el)
		  return new Array('', value);
  }

  //If we have an element we will validate
  //it and pull its values, since they will
  //be needed further
  if(el) {

    // We drop out with all good if we are in a circular reference    
    if(el.isCircular())
      return new Array('', value);
    //If we have an parameter at position 1 it means
    //we need to compare our val to it, if we have
    // a match then we proceed. 
    if(params.length > 1) {
      if(validate.checkField(el)) {
        val = el.values;
      } else if(!params[1].toString().trim().length) {
        val = new Array();
        f = 1;
      } else
        return new Array(' ', value);

      //Loop through all returned values looking for
      //one that matches our requirement
      for(i = 0; i < val.length && !f; i++)
        if(val[i] != null)
          f = (val[i].toString().trim() == params[1].toString().trim());

      //If we did not find any matches, we are done.        
      if(!f)
        return new Array('', value);

      //Otherwise the field is required and we can test that now.
    } else {
      if(el.isValid())
        val = el.values;
      else
        return new Array(' ', value);

      //If we have no values, then there is no requirement.
      if(!val || !val.length || !val[0] || !val[0].length)
        return new Array('', value);
    }
  }

  //If the value has no length then we stop with an error.
	if(!value || !value.length)
		return new Array(' is required.', value);

  //Now we loop through all values checking them as well.
	for(var i = 0; i < value.length; i++)
		if((!value[i] && value[i] != 0) || !value[i].toString().trim().length)
			return new Array(' is required.', value);

  //Goody we are done and everything is correct.			
	return new Array('', value);
}

function validator_Match(value, params, elem) {
	var el = null;
	var val = null;
	
	if(params[0]) {
		el = elem.form.getElement(params[0]);
		if(el) {
      // We drop out with all good if we are in a circular reference    
      if(el.isCircular())
        return new Array('', value);

			if(validate.checkField(el))
				val = el.values[0];
			else 
				return new Array(' ', value);
		}
	}
	if(!value.length && val.length)
		return new Array(' does not match.', value);

	for(var i = 0; i < value.length; i++)
		if(value[i] != val)
			return new Array(' does not match.', value);
			
	return new Array('', value);
}

function validator_Dupe(value, params, elem) {
	var el = null;
	var val = null;
	
	if(params[0]) {
		el = elem.form.getElement(params[0]);
		if(el) {
      // We drop out with all good if we are in a circular reference    
      if(el.isCircular())
        return new Array('', value);

			if(validate.checkField(el))
				val = el.values[0];
			else 
				return new Array(' ', value);
		}
	}
	value.push(val);
			
	return new Array('', value);
}

function validator_Join(value, params) {
	var j = value.join(params[0]);
	value.length = 0;
	value[0] = j;
	
	return new Array('', value);
}

function validator_End(value, params, elem) {
	var i = 0, j = 0;
	var match = 0;
	var ret = null;
	for(i = 0; i < value.length; i++)
			if(value[i] && value[i].toString().length) {
				match = 0;
				for(j = 0; j < params.length && !match; j++)
					match = (value[i].toString().substring(value[i].length-params[j].length, value[i].length) == params[j]);
					
				if(!match)
					return new Array(' must end with [' + params.join(' or ') + ']', value);
			}
					
	return new Array('', value);
}

function validator_EndI(value, params, elem) {
	var i = 0, j = 0;
	var match = 0;
	var ret = null;
	for(i = 0; i < value.length; i++)
			if(value[i] && value[i].toString().length) {
				match = 0;
				for(j = 0; j < params.length && !match; j++)
					match = (value[i].toString().substring(value[i].length-params[j].length, value[i].length).toLowerCase() == params[j].toLowerCase());
					
				if(!match)
					return new Array(' must end with [' + params.join(' or ') + ']', value);
			}
					
	return new Array('', value);
}

validate._resync();

validate.addValidator('skip', validator_Skip);
		
validate.addValidator('req', validator_Req, null, 2, "'");

validate.addValidator('match', validator_Match, null, 1, "'");

validate.addValidator('join', validator_Join, null, 1, "'");

validate.addValidator('dupe', validator_Dupe, null, 1, "'");

validate.addValidator('label', null, function anonymous(elem, params) {
		elem[validate.labelID] = params[0];
	}, 1, "'");
	
validate.addValidator('read', null, function anonymous(elem, params) {
		elem.readonly = true;
		elem.setEvent("focus", function anonymous(e) { this.blur(); });
	});
	
validate.addValidator('onchange', null, function anonymous(elem, params) {
		var func = null;
		eval("func = function anonymous(e) { " + params[0] + "};");
		elem.setEvent("change", func);
	}, 1, "'");

validate.addValidator('onclick', null, function anonymous(elem, params) {
		var func = null;
		eval("func = function anonymous(e) { " + params[0] + "};");
		elem.setEvent("click", func);
	}, 1, "'");

validate.addValidator('endi', validator_EndI, null, -1, "'");

validate.addValidator('end', validator_End, null, -1, "'");
