/*******************************************************************************
 *
 * File       : verify_form.js 
 * Author     : Duco Dokter 
 * Created    : Sun Jan 27 14:07:01 2002 
 * CVS Version: $Id: verify_form.js,v 1.4 2004/07/22 15:02:31 dokter Exp $ 
 * Copyright  : Wyldebeast & Wunderliebe
 * License    : GPL
 * Contact us : dokter@wyldebeast-wunderliebe.com
 *
 * This is a generic form verification library. The function verify
 * does the main loop over the elements of the form specified as it's
 * argument, performs the checks specified and returns true or false,
 * depending on whether the form is filled in properly or not.
 *
 * Please check our website for examples and documentation:
 * http://www.wyldebeast-wunderliebe.com/projects/verify_form/verify_form.html
 *
 * LICENSE INFO:
 * ----------------------------------------------------------------------------- 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version. This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details. You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ******************************************************************************/


/* Global variables holding the error message and header.
 */
var errorMsg;
var errorHeader = "";


/* Language to use. Default is English
 */
var language  = "fr";

var cssURL    = "";
var errWindow = null;


var dict = new Array();

dict["en"] = new Array(5);
dict["nl"] = new Array(5);
dict["fr"] = new Array(5);

dict["en"]["header"]   = "Form not submitted because of the errors listed.";
dict["en"]["required"] = " is required ";
dict["en"]["requires"] = " requires ";
dict["en"]["nomatch"]  = " doesn't match ";
dict["en"]["close"]    = "Close";

dict["nl"]["header"]     = "Formulier niet verstuurd vanwege de volgende fouten:";
dict["nl"]["required"]   = " is verplicht ";
dict["nl"]["requires"]   = " veronderstelt ";
dict["nl"]["nomatch"]    = " voldoet niet aan ";
dict["nl"]["close"]      = "Sluiten";

dict["fr"]["header"]   = "Impossible d'envoyer le formulaire:";
dict["fr"]["required"] = " est requis(e)";
dict["fr"]["requires"] = " requis ";
dict["fr"]["nomatch"]  = " n'est pas un(e)";
dict["fr"]["close"]    = "Fermer";


/**
 * Create an event listener for the form, that listens to changes, and applies the
 * required class to new required fields.
 */
function vfInit(form) {
	
  for (var i = 0; i < form.length; i++) {

    if (form.elements[i].type == "radio" || form.elements[i].type == "checkbox") {
      form.elements[i].onclick = elementEventHandler;
    }
  }
  
  // Init disabled and required fields
  for (var i = 0; i < form.length; i++) {

  	var disables = form.elements[i].getAttribute("disables");
  	var requires = form.elements[i].getAttribute("requires");
	
	if(disables!=null) {
		var disableFields = disables.split(',');
		
		for (var j= 0; j < disableFields.length; j++) {
			// Valid only if radio or checkbox is checked
		  if(form.elements[i].checked == false) {
			continue;  
		  }
		  try {
			form.elements[i].form.elements[disableFields[j]].setAttribute("disabled", "true");
			form.elements[i].form.elements[disableFields[j]].value = "";
		  }
		  catch (ex) {
		// how sad
		  }
		}
	}
	
	if(requires!=null) {
		var requiredFields = requires.split(',');
		
		for (var j= 0; j < requiredFields.length; j++) {
			// Valid only if radio or checkbox is checked
		  if(form.elements[i].checked == false) {
			continue;  
		  }
		  try {
			form.elements[i].form.elements[requiredFields[j]].setAttribute("required", "true");
		  }
		  catch (ex) {
		// how sad
		  }
		}
	}
	
  }
  
}


/**
 * Verify the complete form for all values.
 */
function verify(form) {

  errorMsg = "<UL>\n";

  var formOK   = true;
  
  for (var i= 0; i < form.length; i++) {
    
    var elt = form.elements[i];
    
    verifyField(elt) || (formOK = false);
  }
  
  errorMsg += "</UL>\n";
  
  if (! formOK) {
    showErrWindow(errorMsg);
  }
  
  return formOK;
}


/**
 * Verification dispatcher
 */
function verifyField(elt) {
  /* Now do some element specific thingies
   */
  switch(elt.type) {
  case "text":
    return verifyText(elt);
  case "password":
    return verifyText(elt);
  case "hidden":
    return verifyText(elt);
  case "textarea":
    return verifyText(elt);
  case "radio": 
    return  verifyRadio(elt);
  case "checkbox":
    return  verifyCheckbox(elt);
  case "select-one":
    return verifySelect(elt);
  case "select-multiple":
    return verifySelect(elt);
  default:
    return true;
  }
}
  

/**
 * Verification of a select element. The element is ok-ed when the 
 * value of the option is not empty.
 */
function verifySelect(elt) {
    
  var required = elt.getAttribute("required");
  var errmsg   = elt.getAttribute("errmsg");
  
  if (required != null && isEmpty(elt.value)) {
    
    if (errmsg == null || errmsg == "") {
      errorMsg += "<LI>" + elt.name + dict[language]["required"] + "</LI>\n";
    }
    else {
      errorMsg += "<LI>" + errmsg + "</LI>\n";
    }
    
    return false;
  }
  
  return true;
}
  
  
/**
 * Verify a radio field
 */
function verifyRadio(elt) {
   
  var ok   = true;
  var lErr = "";
  
  var check    = elt.getAttribute("check");
  var required = elt.getAttribute("required");
  var errmsg   = elt.getAttribute("errmsg");

  if (elt.checked && check != null) {
    
    var err = eval(check + "()");
    
    if (err != 0) {
      lErr += "<LI>" + elt.name + ": " + err + "</LI>\n";
      ok = false;
    }
  }
  
  // Now check if the radio group itself is required
  if (required != null) {
    
    var noneOK = true;
    
	if(undefined != elt.form.elements[elt.name].length) {
		for (var i= 0; i < elt.form.elements[elt.name].length; i++) {
		  if (elt.form.elements[elt.name][i].checked) {
		noneOK = false;
		break;
		  }
		}
	}
	else {
		if(elt.checked) {
			noneOK = false;
		}
	}
    
    if (noneOK) {
      lErr += "<LI>" + elt.name + dict[language]["required"] + "</LI>\n";
    }
    
    ok = ! noneOK;
  }
  
  if (! ok) {
    if (errmsg != null && errmsg != "") {
      errorMsg += "<LI>" + errmsg + "</LI>\n";
    }
    else {
      errorMsg += lErr;
    }
  }
  
  return ok;
}


/**
 * Verification of checkbox just calls radio validation.
 */
function verifyCheckbox(elt) {

  return verifyRadio(elt);
}


/**
 * Verify a text field. The field is OK if one of the following conditions 
 * is true:
 *
 * 1. it's not required and empty;
 * 2. it's not empty and doesn't have a mask specified;
 * 3. it's not empty and satisfies it's specified mask.
 */
function verifyText(elt) {

  var ok   = true;
  var lErr = "";
  
  var check    = elt.getAttribute("check");
  var mask     = elt.getAttribute("mask");
  var required = elt.getAttribute("required");
  var errmsg   = elt.getAttribute("errmsg");
  
  if (! isEmpty(elt.value) && mask != null && ! verifyMask(elt.value, mask)) {
    ok = false;
    lErr += "<LI>" + elt.name + ": " + elt.value + dict[language]["nomatch"] + mask + "</LI>\n";
  }
  
  
  /* Perform extra check by evaluating CHECK attribute
   */
  if (! isEmpty(elt.value) && check != null) {
    
    var err = eval(check + "('" + elt.value + "')");
    
    if (err != 0) {
      lErr += "<LI>" + elt.name + ": " + err + "</LI>\n";
      ok = false;
    }
  }
  
  if (required != null && isEmpty(elt.value)) {
    ok = false;
    lErr += "<LI>" + elt.name + dict[language]["required"] + "</LI>\n";
  }
  
  if (! ok) {
    if (errmsg != null && errmsg != "") {
      errorMsg += "<LI>" + errmsg + "</LI>\n";
    }
    else {
      errorMsg += lErr;
    }
  }
  
  return ok;
}


/**
 * The text element may have a mask specified. This should take the form of a
 * regular expression. If the element doesn't match the mask, false is returned.
 */
function verifyMask(value, mask) {

  exp = new RegExp(mask);
  return exp.test(value);
}


/**
 * Determine whether a value is empty. This is true when all characters in the
 * value are one of "\n, \t, ' '".
 */
function isEmpty(value) {
    
  for (var i= 0; i < value.length; i++) {
    var c = value.charAt(i);
    
    if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
  }
  
  return true;
}
  

/**
 * Event handler for onclick events, that takes care of form logic
 */
function elementEventHandler(e) {
  var elt = null;

  try {
    if (e != null) {
      // Moz
      elt  = e.currentTarget ;
    }
    else {
      // IE
      e    = window.event;
      elt  = e.srcElement;
    }
  }
  catch (ex) {
    return;
  }
  
  if (elt == null) {
    return;
  }
  /* Find all fields that (un)require or dis/enable other fields
   */
  var requires = elt.getAttribute("requires");
  var unrequires = elt.getAttribute("unrequires");
  var disables = elt.getAttribute("disables");
  var enables  = elt.getAttribute("enables");
  
  /*
   * Set the required attribute to the fields that are required by
   * this element, if this is checked, or set to not required
   * otherwise.
   */
   
  if (requires != null && elt.checked) {
    
    var requiredFields = requires.split(',');
    
    for (var j= 0; j < requiredFields.length; j++) {
      
      try {
	elt.form.elements[requiredFields[j]].setAttribute("required", "true");
      }
      catch (ex) {
	// how sad
      }
    }
  }
  else if (requires != null) {
    
    var requiredFields = requires.split(',');
    
    for (var j= 0; j < requiredFields.length; j++) {
      
      try {
	elt.form.elements[requiredFields[j]].removeAttribute("required");
      }
      catch (ex) {
	// how sad
      }
    }
  }
  
  if (unrequires != null && elt.checked) {
    
    var requiredFields = unrequires.split(',');
    
    for (var j= 0; j < requiredFields.length; j++) {
      
      try {
	elt.form.elements[requiredFields[j]].removeAttribute("required");
      }
      catch (ex) {
	// how sad
      }
    }
  }

  
  
  if (disables != null && elt.checked) {
    
    var disableFields = disables.split(',');
    
    for (var j= 0; j < disableFields.length; j++) {
      
      try {
	elt.form.elements[disableFields[j]].setAttribute("disabled", "true");
	elt.form.elements[disableFields[j]].value = "";
      }
      catch (ex) {
	// how sad
      }
    }
  }
  else if (disables != null) {
    
    var disableFields = disables.split(',');
    
    for (var j= 0; j < disableFields.length; j++) {
      
      try {
	elt.form.elements[disableFields[j]].removeAttribute("disabled");
      }
      catch (ex) {
	// how sad
      }
    }
  }

  if (enables != null && elt.checked) {
    
    var enableFields = enables.split(',');
    
    for (var j= 0; j < enableFields.length; j++) {
      
      try {
	elt.form.elements[enableFields[j]].removeAttribute("disabled");
      }
      catch (ex) {
	// how sad
      }
    }
  }
  else if (enables != null) {
    
    var enableFields = enables.split(',');
    
    for (var j= 0; j < enableFields.length; j++) {
      
      try {
	elt.form.elements[enableFields[j]].setAttribute("disabled", "true");
	elt.form.elements[enableFields[j]].value = "";
      }
      catch (ex) {
	// how sad
      }
    }
  }

  try {
    e.cancelBubble= true;
  }
  catch (e) {}
}
  
  

/**
 * Popup the error window if it's not already there, and write the errors.
 */ 
function showErrWindow(message) {

  if ( (errWindow != null && errWindow.closed) || (errWindow == null ) ) {
    errWindow = open("", "errors", "width=400,height=500,resizeable=no,menubar=no,locationbar=no,statusbar=no");
  }
  else {
    errWindow.focus();
  }
  
  errWindow.document.open();
  errWindow.document.write("<HTML>\n<HEAD>\n");
  
  if (cssURL != "") {
    errWindow.document.write("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"" + cssURL + "\">\n");
  }
  
  errWindow.document.write("</HEAD>\n<BODY CLASS=\"vfErrMsg\">\n");
  errWindow.document.write("<P>" + dict[language]["header"] + "</P>\n");
  errWindow.document.write("<P>" + message + "</P>\n");
  errWindow.document.write("<TABLE><TR><TD><FORM>\n");
  errWindow.document.write("<INPUT TYPE=\"button\" NAME=\"\" VALUE=\"" + dict[language]["close"] + "\" ONCLICK=\"window.close();\">\n");
  errWindow.document.write("</TR></TD></TABLE></FORM>\n");
  errWindow.document.write("</BODY>\n</HTML>\n");
  errWindow.document.close();
}
  
  
/*******************************************************************************
 *
 * User functions to customize behaviour.
 *
 ******************************************************************************/


/**
 * Set you own error header
 */
function setErrorHeader(header) {
  dict[language]["header"] = header;
}


/**
 * Set the stylesheet to use for the error window.
 */
function setStylesheet(url) {
  cssURL = url;
}


/**
 * Set the language to use if it exists.
 */
function setLanguage(lang) {

  if (dict[lang] != null) {
    language = lang;
  }
}
