

  var FormValidator = {

    fieldRequiredClassName: 'required',
    fieldEmailClassName: 'email',
    strictFormatClassName: 'strictFormat',
    strictExtensionsClassName: 'strictExtensions',
    fieldErrorClassName: 'fieldError',
    labelErrorClassName: 'labelError',
    fieldEmptyOnClickClassName: 'emptyOnClick',
    fieldCanBeDefaultClassName: 'canBeDefault',
	titleErrorClassName: 'error',
    showNames: true,
    stripSuffixes: false, // strip the suffix that is  appended to the name with an underscore
    capitializeLabels: true, // force every name first letter to uppercase
    stripUnderscores: true, // strip the underscores of names

    initialize: function()
    {
      // set submit event of each form
      var form;
      for (var i = 0; form = document.getElementsByTagName('form')[i]; i++)
      {
        this.addEvent(form, 'submit', (function (scope, form) {
          return function(e)
          {
            (function(){
              this.submit(form);
            }).call(scope);
          };
        })(this, form));
      }


      // set form elements' click and blur events
      var element, elements = this.getElementsByClassName(this.fieldEmptyOnClickClassName, 'input');
      for (var i = 0; element = elements[i]; i++)
      {
        element.onclick = function(){if(this.defaultValue == this.value && this.type.toLowerCase() != 'submit'){this.value = ''}};
        element.onblur = function(){if(this.value.trim() == ''){this.value = this.defaultValue}};
      }
    },


    // submit form
    submit: function(form)
    {
      var errorMssg;

      if (errorMssg = this.check(form))
      {
        /* Email wordt E-mail, RP 2009-10-05 */
        alert(errorMssg.replace('Email', 'E-mail'));
        return false;
      }
      
      branche_selection = document.getElementById('cP_branche');
      
      if (typeof(branche_selection) != 'undefined' && branche_selection != null)
      {
        if (branche_selection.options[branche_selection.selectedIndex].value == "")
        {
          alert('U heeft nog geen branche gekozen.');
      
          return false
        }
      }
      return true;
    },


    // check whether the required fields have been filled in
    check: function(form)
    {
      var
        errorMssg,
        requiredInput, requiredInputs = this.getElementsByClassName(this.fieldRequiredClassName, 'input', form),
       questionTitle, inputCollection, collectionInput, inputLabel, alternatives, alternative, alternativeIsSet = false,
        names = '\n';

      for (i = 0; requiredInput = requiredInputs[i]; i++)
      {
        // no value in radio or checkbox collection selected
        // or no value filled in or value is the default value and this is not allowed
        if (
          ((requiredInput.type == 'radio' || requiredInput.type == 'checkbox') && !this.getInputCollectionValue(inputCollection = this.getInputCollection(requiredInput.name, requiredInput.type, form)))
          ||
          (requiredInput.type != 'radio' && requiredInput.type != 'checkbox' && (requiredInput.value.trim() == '' || (requiredInput.value == requiredInput.defaultValue && !this.hasClassName(requiredInput, this.fieldCanBeDefaultClassName))))
        )
        {
          if (requiredInput.type == 'radio' || requiredInput.type == 'checkbox')
          {
			if (questionTitle = this.getQuestionTitle(requiredInput)) this.addClassName(questionTitle, this.titleErrorClassName);

			for (j = 0; collectionInput = inputCollection[j]; j++)
            {
              if (inputLabel = this.getLabel(collectionInput.id)) this.addClassName(inputLabel, this.labelErrorClassName);
//              errorMssg = 'U heeft nog niet alle relevante velden ingevuld.';
              errorMssg = document.getElementById('fm_allFields').innerHTML;
            }
            for (j = 0; collectionInput = inputCollection[j]; j++)
            {
              if (collectionInput.name) names += '\n' + this.capitalize(this.stripSuffixes ? collectionInput.name.replace(/_[^_\s]*$/ ,'') : collectionInput.name);
              break;
            }
          }
          else
          {
            alternatives = requiredInput.className.match(/.*alternatives=\[([^\]]*)\].*/);
            if (alternatives)
            {
              alternatives = alternatives[1].split(',');

              for (j = 0; alternative = document.getElementById(alternatives[j]); j++)
              {
                if (!(alternative.value.trim() == '' || (alternative.value == alternative.defaultValue && !this.hasClassName(alternative, this.fieldCanBeDefaultClassName))))
                {
                  alternativeIsSet = true;
                }
              }

              if (alternativeIsSet)
              {
                this.removeClassName(requiredInput, this.fieldErrorClassName);
              }
              else
              {
                this.addClassName(requiredInput, this.fieldErrorClassName);
//              errorMssg = 'U heeft nog niet alle relevante velden ingevuld.';
                errorMssg = document.getElementById('fm_allFields').innerHTML;
                names += '\n' + this.capitalize(this.stripSuffixes ? requiredInput.name.replace(/_[^_\s]*$/ ,'') : requiredInput.name);
              }
            }
            else
            {
              this.addClassName(requiredInput, this.fieldErrorClassName);
//              errorMssg = 'U heeft nog niet alle relevante velden ingevuld.';
              errorMssg = document.getElementById('fm_allFields').innerHTML;
              names += '\n' + this.capitalize(this.stripSuffixes ? requiredInput.name.replace(/_[^_\s]*$/ ,'') : requiredInput.name);
            }
          }
        }
        else
        {
          if (requiredInput.type == 'radio' || requiredInput.type == 'checkbox')
          {
			if (questionTitle = this.getQuestionTitle(requiredInput)) this.removeClassName(questionTitle, this.titleErrorClassName);

            for (j = 0; collectionInput = inputCollection[j]; j++)
            {
              if (inputLabel = this.getLabel(collectionInput.id)) this.removeClassName(inputLabel, this.labelErrorClassName);
            }
          }
          else
          {
            this.removeClassName(requiredInput, this.fieldErrorClassName);
          }
        }
      }

      if (!errorMssg)
      {
        var emailInput, emailInputs = this.getElementsByClassName(this.fieldEmailClassName, 'input', form);

        for (var i = 0; emailInput = emailInputs[i]; i++)
        {
          if (emailInput.value != "" && emailInput.value.search(/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/) == -1)
          {
            this.addClassName(emailInput, this.fieldErrorClassName);
//            errorMssg = 'Het opgegeven e-mail adres is ongeldig.';
            errorMssg = document.getElementById('fm_email').innerHTML;
            names += '\n' + this.capitalize(this.stripSuffixes ? emailInput.name.replace(/_[^_\s]*$/ ,'') : emailInput.name);
          }
          else
          {
            this.removeClassName(emailInput, this.fieldErrorClassName);
          }
        }
      }

      if (!errorMssg)
      {
        var format, strictFormatInput, strictFormatInputs = this.getElementsByClassName(this.strictFormatClassName, 'input', form);

        for (i = 0; strictFormatInput = strictFormatInputs[i]; i++)
        {
          if (strictFormatInput.value != '')
          {
            format = strictFormatInput.className.replace(/.*format=([^\s$]*).*/, '$1');
            if (new RegExp(format).test(strictFormatInput.value) == false)
            {
//              errorMssg = (strictFormatInput.type == 'file' ? 'Het bestandstype is niet juist.' : 'De notatie is niet correct.');
              errorMssg = (strictFormatInput.type == 'file' ? document.getElementById('fm_filetype').innerHTML : document.getElementById('fm_notation').innerHTML);
              this.addClassName(strictFormatInput, this.fieldErrorClassName);
              names += '\n' + this.capitalize(this.stripSuffixes ? strictFormatInput.name.replace(/_[^_\s]*$/ ,'') : strictFormatInput.name);
            }
            else
            {
              this.removeClassName(strictFormatInput, this.fieldErrorClassName);
            }
          }
        }
      }

      if (!errorMssg)
      {
        var extension, extensions, strictExtensionsInput, strictExtensionsInputs = this.getElementsByClassName(this.strictExtensionsClassName, 'input', form);

        for (i = 0; strictExtensionsInput = strictExtensionsInputs[i]; i++)
        {
          if (strictExtensionsInput.value != '')
          {
            eval(strictExtensionsInput.className.replace(/.*(extensions=\[[^\]]*\]).*/, '$1'));

            for (j = 0; extension = extensions[j]; j++)
            {
              if (strictExtensionsInput.value.replace(/.*\.([^\.]*)/, '$1').toLowerCase() == extension.toLowerCase())
              {
                this.removeClassName(strictExtensionsInput, this.fieldErrorClassName);
                break;
              }
            }
            if (j == extensions.length)
            {
//              errorMssg = 'Alleen bestanden met de extensie \'' + extensions.join('\', \'').replace(/,([^,]*$)/, ' of$1') + '\' zijn toegestaan.';
              errorMssg = document.getElementById('fm_extensions').innerHTML.replace('%s', extensions.join('\', \'').replace(/,([^,]*$)/, ' of$1'));
              this.addClassName(strictExtensionsInput, this.fieldErrorClassName);
              names +=  '\n' + this.capitalize(this.stripSuffixes ? strictExtensionsInput.name.replace(/_[^_\s]*$/ ,'') : strictExtensionsInput.name);
              break;
            }
          }
        }
      }

      return (errorMssg ? (this.showNames ? errorMssg + (this.stripUnderscores ? names.replace(/_/g, ' ') : names) : errorMssg) : false);
    },


	initializeOptionalInputs: function()
	{
		var
			inputsContainer, input, inputs = this.getElementsByClassName('showNext', 'input'),
			collectionInput, inputCollection, inputCollectionValue, optionalInputsContainer, optionalInputs, optionalInput, row, rows;

		for (var i = 0; input = inputs[i]; i++)
		{
			inputsContainer = this.getParent(input, 'table');
			inputCollection = this.getInputCollection(input.name, input.type, inputsContainer);
			inputCollectionValue = this.getInputCollectionValue(inputCollection, input.type, inputsContainer)
			optionalInputsContainer = this.getNextElement(inputsContainer, 'table');
			rows = optionalInputsContainer.getElementsByTagName('tr');

			optionalInputsContainer.style.display = (/(^|\s)ja(\s|$)/i.test(inputCollectionValue) ? (document.all ? 'block' : 'table') : 'none');

			// optional inputs classname

			for (k = 0; row = rows[k]; k++)
			{
				optionalInputs = row.getElementsByTagName('input');
				if (!optionalInputs.length) continue;

				optionalInput = row.getElementsByTagName('input')[0];
				if (optionalInput.type != 'radio') continue;

				if (/(^|\s)ja(\s|$)/i.test(inputCollectionValue)) this.addClassName(optionalInput, this.fieldRequiredClassName);
				else this.removeClassName(optionalInput, this.fieldRequiredClassName);
			}

			// trigger input events

			for (j = 0; collectionInput = inputCollection[j]; j++)
			{
/*
				this.addEvent(collectionInput, 'change', (function (scope, input, inputCollection, inputsContainer, rows, optionalInputsContainer) {
				  return function(e)
				  {
					(function(){

						setTimeout((function (scope, input, inputCollection, inputsContainer, rows, optionalInputsContainer) {
							return function(e)
							{
								(function(){

									optionalInputsContainer.style.display = (input.checked ? (document.all ? 'block' : 'table') : 'none');

									// optional inputs classname

									for (k = 0; row = rows[k]; k++)
									{
										optionalInputs = row.getElementsByTagName('input');
										if (!optionalInputs.length) continue;

										optionalInput = row.getElementsByTagName('input')[0];
										if (optionalInput.type != 'radio') continue;

										inputCollectionValue = this.getInputCollectionValue(inputCollection, input.type, inputsContainer)

										if (/(^|\s)ja(\s|$)/i.test(inputCollectionValue)) this.addClassName(optionalInput, this.fieldRequiredClassName);
										else this.removeClassName(optionalInput, this.fieldRequiredClassName);
									}

								}).call(scope);
							};
						})(this, input, inputCollection, inputsContainer, rows, optionalInputsContainer), 300);
						
					}).call(scope);
				  };
				})(this, input, inputCollection, inputsContainer, rows, optionalInputsContainer));
*/

				this.addEvent(collectionInput, 'mouseup', (function (scope, input, inputCollection, inputsContainer, rows, optionalInputsContainer) {
				  return function(e)
				  {
					(function(){

						setTimeout((function (scope, input, inputCollection, inputsContainer, rows, optionalInputsContainer) {
							return function(e)
							{
								(function(){

									inputCollectionValue = this.getInputCollectionValue(inputCollection, input.type, inputsContainer);
//alert(inputCollectionValue);

									optionalInputsContainer.style.display = (/(^|\s)ja(\s|$)/i.test(inputCollectionValue) ? (document.all ? 'block' : 'table') : 'none');

									// optional inputs classname

									for (k = 0; row = rows[k]; k++)
									{
										optionalInputs = row.getElementsByTagName('input');
										if (!optionalInputs.length) continue;

										optionalInput = row.getElementsByTagName('input')[0];
										if (optionalInput.type != 'radio') continue;

										if (/(^|\s)ja(\s|$)/i.test(inputCollectionValue)) this.addClassName(optionalInput, this.fieldRequiredClassName);
										else this.removeClassName(optionalInput, this.fieldRequiredClassName);
									}

								}).call(scope);
							};
						})(this, input, inputCollection, inputsContainer, rows, optionalInputsContainer), 10);
						
					}).call(scope);
				  };
				})(this, input, inputCollection, inputsContainer, rows, optionalInputsContainer));
			}
		}
	},


	// get parent element with optionally specific tagName
	getParent: function(element, tagName)
	{
		var parent = element.parentNode;

		if (!tagName) return parent;

		while(parent.tagName && (parent.tagName.toLowerCase() != tagName.toLowerCase())) parent = parent.parentNode;

		return parent;
	},


	// get previous element, optionally of specfic tagName
	getPreviousElement: function(element, tagName)
	{
		while(element.previousSibling)
		{
			if (element.previousSibling.nodeType == 1 && (!tagName || element.previousSibling.tagName.toLowerCase() == tagName))
			{
				return element.previousSibling;
			}
			element = element.previousSibling;
		}

		return false;
	},


	// get next element, optionally of specfic tagName
	getNextElement: function(element, tagName)
	{
		while(element.nextSibling)
		{
			if (element.nextSibling.nodeType == 1 && (!tagName || element.nextSibling.tagName.toLowerCase() == tagName))
			{
				return element.nextSibling;
			}
			element = element.nextSibling;
		}

		return false;
	},


    // get radio button or checkbox collection; optionally by name and in container
    // for checkboxes only the alphabetical start of the name is compared to include them in a collection (to exclude suffixed details in their name that make them unique)
    getInputCollection: function(name, type, container)
    {
      var
        input, allInputs = (container || document).getElementsByTagName('input'),
        collection = [];

      for (var i = 0; input = allInputs[i]; i++)
      {
        if ((name && (type == 'radio' ? input.name : input.name.replace(/(^[a-zA-Z]*).*/, '$1')) == name) || (!name && input.type == type))
        {
          collection.push(input);
        }
      }

      return collection;
    },


    // get radio button or checkbox collection value; optionally from input element collection, or collection by name whereby optionally the elements should be found in container
    // dependancies getInputCollection
    getInputCollectionValue: function(collection, type, container)
    {
      if (!collection || typeof(collection) == 'string') collection = getInputCollection(collection, type, container);

      for (var i = 0; i < collection.length; i++)
      {
        if (collection[i].checked)
        {
          return collection[i].value;
        }
      }
    },


    // get label by for value
    getLabel: function(forValue, container)
    {
      var labels = (container || document).getElementsByTagName('label');

      for (var i = 0; i < labels.length; i++)
      {
        if (labels[i].getAttribute('for') == forValue || (document.all && labels[i].getAttribute('htmlFor') == forValue))
        {
          return labels[i];
        }
      }
    },


	// get title of question
	getQuestionTitle: function(element)
	{
		if (element.parentNode.parentNode.tagName.toLowerCase() == 'tr') return element.parentNode.parentNode.getElementsByTagName('td')[0];
		else if (element.parentNode.tagName.toLowerCase() == 'p') return this.getPreviousElement(element.parentNode, 'p');
	},


    // standalone getElementsByClassName function from http://www.robertnyman.com/index.php?p=256
    getElementsByClassName: function(className, tag, container)
    {
      var
        testClass = new RegExp("(^|\\s)" + className + "(\\s|$)"),
        tag = tag || '*', container = container || document,
        elements = (tag == '*' && container.all)? container.all : container.getElementsByTagName(tag),
        returnElements = [], current, length = elements.length;

      for(var i=0; i<length; i++){
        current = elements[i];
        if(testClass.test(current.className)){
          returnElements.push(current);
        }
      }

      return returnElements;
    },


    // standalone addClassName from http://particletree.com/features/javascript-basics-for-prototyping/
    // dependancies: String.prototype.trim
    addClassName: function(element, className)
    {
      this.removeClassName(element, className);
      element.className = (element.className + " " + className).trim();
    },


    // standalone removeClassName from http://particletree.com/features/javascript-basics-for-prototyping/
    // dependancies: String.prototype.trim
    removeClassName: function(element, className)
    {
      element.className = element.className.replace(className, "").trim();
    },


    // check whether an element has a specific class
    hasClassName: function(element, name)
    {
      var i, list = element.className.split(" ");

      for(i = 0; i < list.length; i++)
        if(list[i] == name)
          return true;

      return false;
    },


    // better addEvent function from http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
    addEvent: function(element, type, fn)
    {
      if (element.addEventListener)
      {
        element.addEventListener(type, fn, false);
      }
      else if (element.attachEvent)
      {
        element['e' + type + fn] = fn;
        element[type + fn] = function() {
          element['e' + type + fn](window.event);
        };
        element.attachEvent('on' + type, element[type + fn]);
      }
    },


	capitalize: function(string)
	{
		if (this.capitializeLabels) return string.charAt(0).toUpperCase() + string.slice(1);
		else return string;
	}


  };


  // string trim function from http://www.somacon.com/p355.php
  String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g,"");
  }


