function validator(formname)
{
  if(!document.forms[formname])
  {
    alert('form not found');
  }
  
  validator.formObj = document.forms[formname];
  
  for(i=0; i < validator.formObj.elements.length; i++)
  {
    var element = validator.formObj.elements[i];
    if(element.getAttribute('validate'))
    {
      var validate = element.getAttribute('validate');
      element.parentNode.innerHTML = '<div class="' + validate + '">' + element.parentNode.innerHTML + '</div>';
    }
  }
  
  validator.getValue = function(element)
  {
    if(!element) return '';
    if((element.length>1 && element.tagName.toUpperCase() != 'SELECT') || element.type == 'radio')
    {
      if(!element.length) // it's an radio elem, get the ObjectNodeList of the radio elem
        element = element.form.elements[element.name];

      var radioLength = element.length;
	    for(var i = 0; i < radioLength; i++)
      {
		    if(element[i].checked)
        {
			    return element[i].value;
		    }
	    }
      return "";
    }
    else if (element.type == 'checkbox')
    {
      if (element.checked)
        return element.value;
      else
        return '';
    }
    else if (element.type == 'select-one')
    {
      if (-1 != element.selectedIndex)
        return element.options[element.selectedIndex].value;
    }
    else if (element.type == 'select-multiple')
    {
      var selectedoptions = new Array(); 
      for (var i = 0; i < element.options.length; i++) 
        if (element.options[i].selected) 
          selectedoptions.push([element.options[i].value]);

      if(selectedoptions.length > 0)
        return selectedoptions;
      else
        return '';
    }
    else if (element.tagName.toUpperCase() == 'SELECT') // this will not work for a multiselect !!!!
    {
      if (-1 != element.selectedIndex)
        return element.options[element.selectedIndex].value;
    } else
      return element.value;
  }
  
  validator.setState = function(element, state)
  {
    var classNames    = element.parentNode.className.split(' ');
    var newClassName  = '';
    for(var i=0; i < classNames.length; i++)
    {
      if(classNames[i].indexOf('state_')===-1)
      {
        newClassName += classNames[i] + ' ';
      }
    }
    newClassName += 'state_' + state;
    element.parentNode.className =  newClassName;
  }
  
  validator.validate = function(formname)
  {
    if(formname)
    {
      var elements = document.forms[formname];
    }
    else
    {
      var elements = validator.formObj.elements;
    }
  
    var returnValue = true;
    for(var i=0; i < elements.length; i++)
    {
      var element = elements[i];

      if(element.getAttribute('validate'))
      {
        var validate  = element.getAttribute('validate').split(' ');
        var correct   = true;
        var value     = validator.getValue(element).trim();
        
        for(var v=0; v < validate.length; v++)
        {
          switch(validate[v])
          {
            case 'required':
              correct = validator.validation_required(value);
              break
            case 'email':
              correct = validator.validation_email(value);
              break;
            case 'url':
              correct = validator.validation_url(value);
              break;
            case 'date':
              correct = validator.validation_date(value);
              break;
            case 'int':
              correct = validator.validation_int(value);
              break;
            case 'float':
              correct = validator.validation_float(value);
              break;
            case 'telephone':
              correct = validator.validation_telephone(value);
              break;
            case 'zipcode':
              correct = validator.validation_zipcode(value);
              break;
          }
          
          if(!correct)
          {
            returnValue = false;
            break;
          }
        }
        
        validator.setState(element, ((correct) ? 'correct' : 'incorrect'));
      }
    }
  
    return returnValue;
  }
  
  /* rules */
  validator.validation_required = function(value)
  {
    value = unescape(value.trim());
    return (value.length<1) ? false : true;
  }
  
  validator.validation_email = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
	    var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.){1,2}[a-zA-Z]{2,4}$/;
      return filter.test(value);
    }
    return true;
  }
  
  validator.validation_url = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
      var v = new RegExp(); 
      v.compile("^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$");
	    return v.test(value);
    }
    return true;
  }
  
  validator.validation_int = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
      var filter = /^\d+$/;
      return filter.test(value);
    }
    return true;
  }
  
  validator.validation_date = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
      var filter = /^([0-9]{2})-([0-9]{2})-([0-9]{4})$/;      
      return filter.test(value);
    }
    return true; 
  }
  
  validator.validation_float = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
      var filter = /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
      return filter.test(value);
    }
    return true;
  }
  
  validator.validation_telephone = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
      var filter = /^([\+])?([0-9-]{8,20})$/;      
      return filter.test(value);
    }
    return true;
  }
  
  validator.validation_zipcode = function(value)
  {
    value = unescape(value);
    if(value.length>0)
    {
	    var filter  = /^[0-9]{4}[ ]?[a-zA-Z]{2}$/;
      return (filter.test(value) ? true : false);
    }
    return true;
  }
}

