var rules = {
             'int':function (value,param) {
                                           var minMax = param.split(',');
                                           testValue = parseInt(value);
                                           if (value != testValue) {return false}
                                           if (minMax[0] && testValue < minMax[0]) {return false}
                                           if (minMax[1] && testValue > minMax[1]) {return false}
                                           return true;
                                          },
             'float':function (value,param) {
                                             var minMax = param.split(',');
                                             testValue = parseFloat(value);
                                             if (value != testValue) {return false}
                                             if (minMax[0] && testValue < minMax[0]) {return false}
                                             if (minMax[1] && testValue > minMax[1]) {return false}
                                             return true;
                                            },
             europeanDecimal:function (value,param) {
                                             value = value.replace(/\,/, '.');
                                             var minMax = param.split(',');
                                             testValue = parseFloat(value);
                                             if (value != testValue) {return false}
                                             if (minMax[0] && testValue < minMax[0]) {return false}
                                             if (minMax[1] && testValue > minMax[1]) {return false}
                                             return true;
                                            },
             email:function (value,param) {
                                           if (param == 'notRequired' && !value.length) {return true}
                                           var mailRegex = /^[^\@]+\@[^\.]+\.[^\.]+/;
                                           if (value.match(mailRegex)) { return true }
                                           return false;
                                          },
             hostname:function (value,param) {
                                           if (param == 'notRequired' && !value.length) {return true}
                                           var hostnameRegex = /[\w\d\.\-]+/;
                                           if (value.match(hostnameRegex)) { return true }
                                           return false;
                                          },
             url:function (value,param) {
                                           if (param == 'notRequired' && !value.length) {return true}
                                           var urlRegex = /^(http|ftp|mailto)\:\/\/[\%a-zA-z0-9\-\/\_\:\@\.]+$/;
                                           if (value.match(urlRegex)) { return true }
                                           return false;
                                          },
             'regex':function (value,param) {
                                             var regex = eval(param);
                                             return value.match(regex);
                                            },
             path:function (value,param) { alert("You should note that this is a fake test! Please implement rule: path");
					   return true;
                                            },
	     fileExt:function (value,param) { 
  		                             param = '/^.+\.'+param+'$/i';
                                             var regex = eval(param);
                                             return value.match(regex);
                                            },
             required:function (value,param) {
                                              if (!value) {return false}
                                              if (value.length <= 0) {return false}
                                              return true;
                                             },
             length:function (value,param) {
                                            var minMax = param.split(',');
                                            if (minMax[0]>0 && !value) {return false}
                                            if (value) {
                                              if (minMax[0]>0 && value.length < minMax[0]) { return false }
                                              if (minMax[1]>0 && value.length > minMax[1])  { return false }
                                            }
                                            return true;
                                           },
	     numChecked:function (value,param) {
  		                              return value;
                                           },
             'javascript':function(value,param) {
		                                 return eval(param);
             },
             repeat:function(value,param) {
                 var fieldName  = param;
                 var otherValue = "";
                 var elements = document.getElementsByTagName("input");
                 var numFound = 0;
                 for (var i = 0; i < elements.length; i++) {
                     if (elements[i].name == fieldName) {
                         numFound++;
                         otherValue = elements[i].value;
                     }
                 }
                 if (numFound == 0) {
                     alert("Internal error: Didn't find element with name " + fieldName);
                 }
                 else if (numFound > 1) {
                     alert("Internal error: More than one element exists with name " + fieldName);
                 }
                 return value == otherValue;
             }
            };

var formErrors = new Array;
var formHasErrors = false;
var _o2OnSubmitEval = {}; // add code to be evaluated on submit here. form name is key, codestring is value

function o2AddOnSubmitEval(formName, evalJs) {
  if( !_o2OnSubmitEval[formName] ) _o2OnSubmitEval[formName]='';
  _o2OnSubmitEval[formName] += evalJs+';';
}

function _o2SubmitForm(f, functionName) {
  if (_o2CheckForm(f, functionName)) {
    f.submit();
  }
}

function _o2CheckForm (f, functionName, postFunction) {
  if( !f ) return;   // vonheim@20060308 <form onsubmit> and <input type=submit> both calls this method. one of them does not include "f"
	
  // added by nilschd 20070115, submit button sends it self as an f with firefox 2.x
  if(f.type == "button") {
      f = f.form; // then we set the f to be the this buttons parent form
  }

  if( f.name && _o2OnSubmitEval[f.name] ) eval(_o2OnSubmitEval[f.name]);
  verifyForm(f);

  if (!formHasErrors) {
    if (window._o2MultilingualSubmitForm) {
      _o2MultilingualSubmitForm();
    }
    // In case you want to have som javascript executed before submitting the form, but after the rules are checked
    if (window.onRuleCheckSuccess) {
      onRuleCheckSuccess();
    }
    // f.submit(); // Just return true, don't submit!
    return true;
  }
  else {
    var errorTitle = ''; //XXX - Was "Error in input data". Removed because it was difficult to support different languages. vonheim@20060518
    if (f.getAttribute('ruleTitle')) {
      errorTitle = f.getAttribute('ruleTitle');
    }
    var errorBody = '';
    if (functionName) {
      if (formErrors && formErrors.length) {
        errorBody = formErrors.join("<br>");
      }
      eval(functionName+"('"+errorTitle+"','"+errorBody+"');");
    }
    else {
      if (formErrors && formErrors.length) {
        errorBody = formErrors.join("\n");
      }
      alert(errorTitle + "\n" + errorBody);
    }
  };
  return false;
}

function verifyForm (f) {

  formErrors.length = 0;
  formHasErrors = false;
  __checkBoxGroups=null;
  __ruleMsgSeen = null;
  checkNode(f);
  return !formHasErrors;
}

function getVerifyErrors () {
  return formErrors;
}

function checkNode (node) {
  if( !node ) return;
  if (node.nodeType==1) {
    if (node.disabled) { // Håkon, 20070228
      return;
    }
    // !node.disabled added by vonheim@20060311
    if ((node.tagName == 'INPUT' || node.tagName == 'SELECT' || node.tagName == 'TEXTAREA') && node.getAttribute('RULE') && !node.disabled ) {
      var rule = node.getAttribute('RULE')
      var ruleParts = rule.split(':');
      if (!rules[ruleParts[0]]) {
        alert("No such rule: "+ruleParts[0]);
        markError(node);
      }
      else {
        var params = new Array;
        for (var i = 1; i < ruleParts.length; i++) {
          params[params.length] = ruleParts[i];
        }
        var param = params.join(':');
        var value;
	

        if (node.tagName == 'SELECT') {
          value = node.options[node.selectedIndex].value;
        }
	else if(node.type.toLowerCase() == 'checkbox' && ruleParts[0] == 'numChecked') {
	    value =__checkCheckBoxGroup(node,param);
	}
	else if(node.id.substring(0,9) == 'comboBox_' && node.getAttribute("mode") == 'select') {
	    //20080208 nilschd, adding support for ComboBox in mode "select".
	    //Select mode allows you to use ComboBox as a select compononent with "type ahead feature"
	    var comboBoxId = node.id.substring(9, node.id.length-4 );
	    value = document.getElementById(comboBoxId).value;
	}
        else {
          value = node.value;
        }
	
        var ok = rules[ruleParts[0]](value,param);
        if (ok) {
	    // nilschd 20061120, we want to restore to the org. input formattng
	    if( __cssSeen != null && __cssSeen[node.name] != null ) {
		node.style.background='';
		node.className=__cssSeen[node.name];
	    }
	    else if(__bgColorSeen != null && __bgColorSeen[node.name] != null ) {
		node.style.background=__bgColorSeen[node.name];
	    }
	    else if( node.style.background == '#EE9999') {
		node.style.background='';
	    }
	    
	  // XXX 20060612 to allow colors on checkbox and radios
	  if(node.type.toLowerCase() == 'checkbox' ||  node.type.toLowerCase() == 'radio') {
	      node.parentNode.style.background = ''; 
	  }
        }
        else {
          markError(node);
        }
      }
    }
    else if (node.hasChildNodes) {
      var nodes = node.childNodes;
      for (var i=0; i<nodes.length; i++) {
        checkNode(nodes[i]);
      }
    }
  }
}

__ruleMsgSeen = null;
__cssSeen = null; // nilschd 20061120 used to remeber that what color/className and input field org. was
__bgColorSeen = null; // nilschd 20061120 used to remeber that what color/className and input field org. was
function markError (node) {
 
  if (node.getAttribute('ruleMsg')) {
      // XXX nilschd to disabled duplicate ruleMsg's for checkbox'es and radiogroups
      if(node.type.toLowerCase() == 'checkbox' ||  node.type.toLowerCase() == 'radio') {
	  if(__ruleMsgSeen == null) { __ruleMsgSeen = new Array(); }
	  if(__ruleMsgSeen[node.name] == null) {
	      formErrors[formErrors.length] = node.getAttribute('ruleMsg');
	      __ruleMsgSeen[node.name] = true;
	  }
      }
      else {
	  formErrors[formErrors.length] = node.getAttribute('ruleMsg');
      }
  }
  formHasErrors = true;
  
  // nilschd 20061120 we need to remember the org. formatting of this field
  if(node.className != null && node.className != '') {
      if(__cssSeen == null) { __cssSeen = new Array(); }
      __cssSeen[node.name] = node.className;
  }
  else if(node.style.background != null && node.style.background != '') {
      if(__bgColorSeen == null) { __bgColorSeen = new Array(); }
      __bgColorSeen[node.name] = node.style.background;
  }

  node.style.background = '#EE9999';
  // XXX 20060612 to allow colors on checkbox and radios
  if(node.type.toLowerCase() == 'checkbox' ||  node.type.toLowerCase() == 'radio') {
      node.parentNode.style.background = '#EE9999'; 
  }
}

// XXX 20060612 added by nilschd to allow have a group of checkboxes and to specify that
// XXX e.g. 2 or more must be selected
var __checkBoxGroups= null;
function __checkCheckBoxGroup(node,param) {
    if(__checkBoxGroups == null) __checkBoxGroups = new Array();


    var f= node.form; // the form
    var groupName = node.name; // the group of checkBoxes
    if(	__checkBoxGroups[f.name+'_'+groupName]!= null) { // we have allready checked this group, aka cached
	return __checkBoxGroups[f.name+'_'+groupName];
    }
    var totalChecked = 0;
    if(param=='') { // ok lets use default rule 1,*. Then the checkboxes acts like a radiogroup
	param='1,*';
    }
    
    var rules = param.split(",");

    if(f[groupName].length != null) {
      for(var i=0; i <f[groupName].length;i++) {
	if( f[groupName][i].checked ) {
	  totalChecked++;
	}
      }
    }
    else { // f[groupName].length is undefined if there's just one element in the group.
        if (node.checked) {
            totalChecked++;
        }
    }

    if(totalChecked >= parseInt(rules[0]) && (rules[1] =='*' || totalChecked <= parseInt(rules[1]))) {
	__checkBoxGroups[f.name+'_'+groupName]=true;
    }
    else {
	__checkBoxGroups[f.name+'_'+groupName]=false; //didn't meet requirments in the provided rule
    }
    return __checkBoxGroups[f.name+'_'+groupName]
}
