
// form handling routines created by Jan Verhoeven
// version: 20060809


// routines to
// validate form date
// Preset form fields

// you can add you own validators to this library
// add them to the switch in the validateElements function

// if you want a form field to be validated add the attribute validator="somevalidator"
// where 'somevalidator' is one of the following allowed validators

//  validator= "notempty"
//  validator= "authenticate"
//  validator= "email"
//  validator= "integer"
//  validator= "nlfloat"  dutch float format  123,456
//  validator= "nldate"   dutch date format dd-mm-yyyy
//  validator= "word"     only alpha without spaces
//  validator= "symbol"   alpha numeric plus the underscore _
//  validator= "url"
//  validator= "name"     alpha numeric plus space
//  validator= "digit8"   8 digits


// objects
function HxQuestion(owner)
{
  this.owner = owner;
  this.name = "";
  this.skip = false;
  this.value = "";
  this.type = "";
  this.setValue = _hxqSetValue;
  this.validator = "";

}

function HxDataFormController()
{
	this.forms = new Array();
}

var HxDataForms = new HxDataFormController();

function HxDataForm(form)
{
  HxDataForms.forms[form.name] = this;

  this.questions = new Array();
  this.form = form;
  this.setFormData = _setFormData;
  this.setFormDataJson = _setFormDataJson;
  this.setFormDataXml = _setFormDataXml;
  this.setCustomAttribute = _setCustomAttribute;
  this.initialize = _hxdfInitialize;
  this.observe = _hxdfObserve;
  this.serialize = _hxdfSerialize;
  this.serializeXml = _hxdfSerializeXml;
  this.$F = _hxdfGetField;
  this.$FV = _hxdfGetFieldValue;
  this.onChange = null;
}

function _hxdfObserve(onChangeHandler)
{
	var i, L;
	var element;
	L = this.form.elements.length;
	
	for (i=0; i<L; i++)
	{
		element = this.form.elements[i];
		switch(element.type)
		{
			case "text":
			case "textarea":
			case "select-one":
			element.onchange = _hxdfChange;	
			break;
			case "radio":
			case "checkbox":
			element.onclick = _hxdfChange;
			break;
		}
	}
	
	this.onChange = onChangeHandler;

}

function _hxdfChange()
{
	var df = HxDataForms.forms[this.form.name];
	
	
	var q = df.questions["$$" + this.name];
	q.setValue();
	
	if (typeof(df.onChange == "function") )
	{
		df.onChange( df.form, this.name, q.value );
	}
}



function _hxdfInitialize()
{
  var i, L;
  var element;
  var question;
  var type;
  
  this.questions.length = 0;
  L = this.form.elements.length;
  for (i=0;i<L;i++)
  {
    element = this.form.elements[i];
    type = element.type;

    if ((type == "button") || (type == "submit") || (type == "hidden")) continue;

    if (this.questions["$$" + element.name]) continue;
    question = new HxQuestion(this);
    question.name = element.name;
    question.type = element.type;
	question.validator = element.getAttribute("validator");
    this.questions["$$" + element.name] = question;
  }

  for (key in this.questions)
  {
     if ( key.indexOf("$$") != 0 ) continue;
     question = this.questions[key];
     question.setValue();

  }
  
}

function _hxdfSerialize()
{
  var result = "";
  var question;
  var atom;

  for (key in this.questions)
  {
        if ( key.indexOf("$$") != 0 ) continue;

        question = this.questions[key];
        atom = question.name + "=" + escape(question.value);

        if (result == "")
          result = atom
        else
          result += "&" + atom;
  }

  return result;
}

function _hxdfSerializeXml()
{
  var result = "<form>\n";
  var question;

  for (key in this.questions)
  {
        if ( key.indexOf("$$") != 0 ) continue;

        question = this.questions[key];
        result+= "<field name='" + question.name + "' value='" + escapeXML(question.value) + "'/>\n";

  }

  return result+= "</form>";
}


function _hxdfGetField(name)
{
   return this.questions["$$" + name];
}

function _hxdfGetFieldValue(name)
{
   var question = this.$F(name);
   if (question)
     return question.value
   else
     return "";
}



function _hxqSetValue()
{
  var form;
  var name;

  form = this.owner.form;
  name = this.name;

  switch (this.type)
  {
    case "hidden":
    case "text":
    case "password":
    case "textarea":
    case "select-one":
      this.value = form.elements[name].value;
      //PresetSelect(_form.elements[FieldName],FieldValue)
      break
    case "radio":
      this.value = getRadioValue(form.elements[name]);
      break
    case "checkbox":
      if (form.elements[name].checked)
        this.value = form.elements[name].value
      else
        this.value = "";
      break
  }
}

// general form routines

function DisableForm(pForm)
{
  var i, L;
  var element;
  var type;
  L = pForm.elements.length;
  for (i=0;i<L;i++)
  {
    element = pForm.elements[i];
    type = element.type;

    if ((type == "button") || (type == "submit") || (type == "hidden")) continue;
	
	element.disabled = true;

  }

}

// smart data entry
function smartKeyPress(e)
{
	var keyValue;
	var radioIndex;
	var radioFocus;
	var formIndex;
	var L;
	
	if (!e)
	{
		var e = window.event;
		keyValue = e.keyCode;
	}
	else
	{
		keyValue = e.which;
	}
	
	radioIndex = keyValue - 97; // A, B, C etc
	
	var tg = (e.target) ? e.target : e.srcElement;
	
	if ( tg.type == "radio")
	{
		radios = tg.form[tg.name ];
		if ((radioIndex >=0 ) && (radioIndex < radios.length)	)
		{
			radioFocus = radios[radioIndex];
			radioFocus.checked = true; // 20060608
			radioFocus.click();
			radioFocus.focus();			
			
			var lastRadio = radios[ radios.length -1 ];
			
			formIndex = smartIndexOf(tg.form, lastRadio);
			
			smartFocusNext(tg.form, formIndex);
			
			e.returnValue = false;
			
			
		}
	}
//	else if ( tg.type == "select-one" )
//	{
//		if ((radioIndex >=0 ) && (radioIndex < tg.options.length)	)	
//		{
//			tg.selectedIndex = radioIndex;
//			formIndex = smartIndexOf(tg.form, tg);
			
//			smartFocusNext(tg.form, formIndex);
			
//			e.returnValue = false;
//		}
		
		
//	}
	
}

function smartIndexOf( theForm, theElement)
{
	var i;
	var L = theForm.elements.length;
	
	for (i = 0; i < L; i++)
	{
		if (theForm[i] == theElement)
		{
			return i;
		}
	}
	return -1;
}

function smartFocusFirst(theForm)
{
	var index = 0;

	while (index < theForm.elements.length )
	{
		if ( smartIsVisible( theForm[index] ) )
		{
			theForm[index].focus();
			break;
		}
		index++;
	}
}


function smartFocusNext( theForm, formIndex)
{
	var index = formIndex + 1;
	var element
	
	while (index < theForm.elements.length )
	{
		if ( smartIsVisible( theForm[index] ) )
		{
			
			element = theForm[index];
			
			if (element.type =="radio" )
			{
				var radios = theForm[ element.name ];
				if (radios.length)
				{
				  radios[radios.length -1].scrollIntoView(false);
				}
			}
			theForm[index].focus();
			break;
		}
		index++;
	}
}

function smartIsVisible( element )
{
	
	if ( element.style )
	{
		if (element.style.display == "none" ) return false;
	}
	
	var parent;
	
	parent = element.parentNode;
	
	while (parent)
	{
		if (parent.style )
		{
			if ( parent.style.display == "none" ) return false;
		}
		parent = parent.parentNode;
	}
	return true;
}


function smartGetValue( element )
{
    var i, L;
	var result = "";
	switch (element.type)
    {
    case "hidden":
      result = element.value;
      break
    case "text":
      result = element.value;
      break
    case "password":
      result = element.value;
      break
    case "select-one":
      var options = element.options;
	  L = option.length;
	  for (i=0; i< L; i++)
	  {
		if (! options[i].selected ) continue;
		result = options[i].value;
		break;
	  }
      break;
    case "radio":
	  var radios = element.form.elements[element.name];
	  L = radios.length;
	  for (i=0; i< L; i++)
	  {
		if ( radios[i].checked )
		{
			result = radios[i].value;
			break;
		}
	  }
      break
    case "checkbox":
      if (element.checked) 
	  {
		result = element.value;
	  }
	  else
	  {
		result = "";
	  }
      break
    case "textarea":
      result = element.value;
      break;
    }
	
	return result;
}





// -- general validation routine --
function ValidateRadioGroup(pRadioGroup) {
var i,L
  if (pRadioGroup.length) {
    L=pRadioGroup.length
    for (i=0;i<L;i++) {
      if (pRadioGroup[i].checked) return true
    }
    return false
  }
  else return pRadioGroup.checked
}

function ValidateDate(pValue,pMinYear,pMaxYear) {
var tmp, DateParts, TheYear
  var RegEx=/^(?:(?:31(-)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(-)(?:0?[1,3-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(-)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(-)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/
  tmp=RegEx.test(pValue)
  if (! tmp) return false
  DateParts=pValue.split("-")
  TheYear= parseInt(DateParts[2])
  return (TheYear>=pMinYear) && (TheYear<=pMaxYear)
}

function ValidateISODate(pValue)
{
  var RegEx=/^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$/
  return RegEx.test(pValue);
}

function ValidateEmail(pValue) {
  var RegEx=/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/
  return RegEx.test(pValue)
}

function ValidateInteger(pValue) {
  var RegEx=/^[+-]?[0-9]+$/
  return RegEx.test(pValue)
}

function ValidateFloat(pValue) {

  var tmp = pValue.replace(".", "");
  var RegEx=/^[+-]?[0-9]+([,][0-9]+)?$/
  return RegEx.test(tmp)
}


function ValidateNotEmpty(pValue) {
  var RegEx=/^./
  return RegEx.test(pValue)
}


function ValidateSofiNumber(pValue)
{ 
  var sofinr = pValue;
  var checksum=0; 
  
  if(isNaN(sofinr) || sofinr.length!=9) return false; 
  for(i=0;i<8;i++)
  { 
     checksum += (sofinr.charAt(i)*(9-i)); 
  } 
  checksum -= sofinr.charAt(8); 
  if(checksum%11!=0)
  { 
    return false;   
  } 
  else
  {
    return true;
  }
} 


function ValidatePostCodeA(pValue) {
  var RegEx=/^([0-9]){4,4}$/
  return RegEx.test(pValue)
}

function ValidatePostCodeB(pValue) {
  var RegEx=/^([a-z,A-Z]){2,2}$/
  return RegEx.test(pValue)
}
function validateField(theFormElt,thePattern) {
  var re = new RegExp(thePattern);
  var fv = theFormElt.value;
  return re.test(fv);
}


function validateForm(theForm) {
  if (validateElements(theForm)) {
     theForm.submit();
  }
}


function validateElements(theForm){// return true if all is well
  var elArr=theForm.elements;
  for(var i=0;i<elArr.length;i++) {
    var aElement=elArr[i];
    v=aElement.validator;
    if (aElement.errmsg == null) {
      m='U heeft '+aElement.name+' niet of onjuist ingevuld';
    }
    else {
      m = aElement.errmsg;
    }
    switch (v) {
     case "authenticate":
        m = aElement.name + ' : Het wachtwoord moet bestaan uit 5 tot 16 alphanumerieke karakters';
        var gotIt = validateField(aElement,"^[a-zA-Z0-9]{5,16}$");
        break;
     case "nldate":
        var gotIt = validateField(aElement,"^[0-3]?[0-9][-/][01]?[0-9][-/][0-9]{4}$");
        break;
     case "integer":
        var gotIt = validateField(aElement,"^[+-]?[0-9]+$");
        break;
     case "nlfloat":
        var gotIt = validateField(aElement,"^[+-]?[0-9]+([,][0-9]+)?$");
        break;
     case "email":
        var gotIt = validateField(aElement,"^[0-9a-zA-Z][0-9a-zA-Z.]*@[0-9a-zA-Z]+[.][a-zA-Z]+$");
        break;
     case "notempty":
        var gotIt = validateField(aElement,"^.");
        break;
     case "symbol":
        m = 'Het veld '+ aElement.name + ' moet bestaan uit minimaal 3 alphanumerieke karakters';
        var gotIt = validateField(aElement,"^[a-zA-Z0-9]{3,}$");
        break;
     case "aspfile":
        m = 'Het veld '+ aElement.name + ' moet verwijzen naar een asp bestand met .asp als extensie.';
        var gotIt = validateField(aElement,"^[a-zA-Z0-9_]{3,}\.asp$");
        break;
     case "name":
        var gotIt = validateField(aElement,"^[a-zA-Z0-9 ]{3,}$");
        break;
     case "digit8":
        var gotIt = validateField(aElement,"^[0-9]{8}$");
        break;
     default:
        var gotIt = true;
    }

    if(!gotIt){
      alert(m);
      return false;
    }
  }
  return true;
}

function _setFormData(formData) {
var FormFields, FormField, i, L
var FieldName, FieldValue, FieldObject, FieldType
var _form = this.form;

  // formData must be in escaped Url get form name1=value1&name2=value2
  if (formData=="") return
  FormFields=formData.split("&")
  L=FormFields.length
  for (i=0;i<L;i++)
  {
    FormField=FormFields[i].split("=")
    FieldName=FormField[0]
    FieldValue=unescape(FormField[1])
    FieldObject= this.form.elements[FieldName]

    if (! FieldObject) continue;
    FieldType=FieldObject.type
    if (FieldType==undefined) {
      FieldType=FieldObject[0].type
    }
    switch (FieldType)
    {
    case "hidden":
      _form.elements[FieldName].value=FieldValue
      break
    case "text":
      _form.elements[FieldName].value=FieldValue
      break
    case "password":
      _form.elements[FieldName].value=FieldValue
      break
    case "select-one":
      PresetSelect(_form.elements[FieldName],FieldValue)
      break
    case "radio":
      PresetRadio(_form.elements[FieldName],FieldValue)
      break
    case "checkbox":
      PresetCheckbox(_form.elements[FieldName],FieldValue)
      break
    case "textarea":
      _form.elements[FieldName].value=FieldValue
      break
    }
  }
}


function _setFormDataJson(formData) {
var FormFields, FormField, i, L
var FieldName, FieldValue, FieldObject, FieldType
var _form = this.form;

  // formdata must be in XmlToJson format
  if (formData == null) return;
  
  L = formData.nodes.length;
  for (i=0;i<L;i++)
  {
    FormField = formData.nodes[i];
    FieldName = FormField.attributes[0].value;
    FieldValue = FormField.attributes[1].value;

    FieldObject= this.form.elements[FieldName]

    if (! FieldObject) continue;
    FieldType=FieldObject.type
    if (FieldType==undefined) {
      FieldType=FieldObject[0].type
    }
    switch (FieldType)
    {
    case "hidden":
      _form.elements[FieldName].value=FieldValue
      break
    case "text":
      _form.elements[FieldName].value=FieldValue
      break
    case "password":
      _form.elements[FieldName].value=FieldValue
      break
    case "select-one":
      PresetSelect(_form.elements[FieldName],FieldValue)
      break
    case "radio":
      PresetRadio(_form.elements[FieldName],FieldValue)
      break
    case "checkbox":
      PresetCheckbox(_form.elements[FieldName],FieldValue)
      break
    case "textarea":
      _form.elements[FieldName].value=FieldValue
      break
    }
  }
}

function _setFormDataXml(containerId) {
var FormFields, FormField, i, L
var FieldName, FieldValue, FieldObject, FieldType
var _form = this.form;

  // find the container
  var container = document.getElementById(containerId);
  if (container == null) return;
  
  FormFields = container.getElementsByTagName("field");
  L = FormFields.length
  for (i=0;i<L;i++)
  {
    FormField = FormFields[i];
    FieldName = FormField.getAttribute("name");
    FieldValue = FormField.getAttribute("value");

    FieldObject= this.form.elements[FieldName]

    if (! FieldObject) continue;
    FieldType=FieldObject.type
    if (FieldType==undefined) {
      FieldType=FieldObject[0].type
    }
    switch (FieldType)
    {
    case "hidden":
      _form.elements[FieldName].value=FieldValue
      break
    case "text":
      _form.elements[FieldName].value=FieldValue
      break
    case "password":
      _form.elements[FieldName].value=FieldValue
      break
    case "select-one":
      PresetSelect(_form.elements[FieldName],FieldValue)
      break
    case "radio":
      PresetRadio(_form.elements[FieldName],FieldValue)
      break
    case "checkbox":
      PresetCheckbox(_form.elements[FieldName],FieldValue)
      break
    case "textarea":
      _form.elements[FieldName].value=FieldValue
      break
    }
  }
}


function escapeXML(value)
{
  tmp = value.replace( /&/g, "&amp;");
  tmp = tmp.replace( /'/g, "&apos;");
  tmp = tmp.replace( /\"/g, "&quot;");
  tmp = tmp.replace( /</g, "&lt;");
  tmp = tmp.replace( />/g, "&gt;");
  return tmp;
}

function unescapeXML(value)
{
  tmp = tmp.replace( /&apos;/g, "'");
  tmp = tmp.replace( /&quot;/g, "\"");
  tmp = tmp.replace( /&lt;/g, "<");
  tmp = tmp.replace( /&gt;/g, ">");
  tmp = value.replace( /&amp;/g, "&");
  return tmp;

}


function _setCustomAttribute(name, value)
{
   var elements = this.form.elements;
   var element;
   var i;

   for (i=0; i< elements.length; i++)
   {
      element = elements[i];
      element.setAttribute(name, value);
   }

}


function PresetCheckbox(pCheckBox,pValue)
{
 var items, i, L, ci,cL

 if (pValue=="") return
  if (pCheckBox.length) {
    // multiple options
    items=pValue.split(",")
    L=items.length
    cL=pCheckBox.length
    for (i=0;i<L;i++)
    {
      for (ci=0;ci<cL;ci++)
      {
        if (pCheckBox[ci].value==items[i])
        {
          pCheckBox[ci].checked=true
          break
        }
      }
    }
  }
  else
  {
    // single option
    if (pCheckBox.value==pValue) {
      pCheckBox.checked=true
    }
  }
}

function PresetRadio(pRadio,pValue) {
	var i,L
	if (pRadio.length) {
		L=pRadio.length
		for (i=0;i<L;i++) {
			if (pRadio[i].value==pValue) {
			pRadio[i].checked=true
			}
		}
	}
	else
	{
  // single choice
		if (pRadio.value==pValue)
		{
			pRadio.checked=true
		}
	}
}

function getRadioValue(pRadio)
{
	var i,L;

	if (pRadio.length)
	{
		L=pRadio.length
		for (i=0;i<L;i++)
		{
			if (pRadio[i].checked)
			{
				return pRadio[i].value;
			}
		}
		return "";
	}
	else
	{
  // single choice
		if (pRadio.checked)
			return pRadio.value
		else
			return "";
	}
}


  function PresetSelect(pSelect,pValue) {
  var i,L
    L=pSelect.options.length
    for (i=0;i<L;i++) {
      if (pSelect.options[i].value==pValue) {
        pSelect.selectedIndex=i
        return
      }
    }
  }
  


