/*
 * formmail.js
 *
 * Formmailer using the XMLHttpRequest Object
 *
 * 09/04/2006 Felix M. Palmen
 *
 *
 * SYNOPSIS:
 *
 * var fm = new Formmail(
 *	document.getElementById("my_submit_button"),
 *	document.getElementById("my_wait_element"),
 *	document.getElementById("my_complete_element")
 * );
 *
 * fm.addCheck( ["isString"|"isEmail"], "fieldid", "errid", "errmsg");
 * [...]
 *
 *
 * When asked for a text/json reply (Accept:-header), the server side
 * script should return an object like this:
 *
 * {
 *   "success": [0|1],
 *   "replace": {
 *     "node_id_1": "new_text_1",
 *     "node_id_2": "new_text_2",
 *     [...]
 *     "node_id_n": "new_text_n"  // no comma here, IE is picky about that!
 *   }
 * }
 *
 */

function Formmail(submit, wait, complete, prewait)
{
  if (prewait == undefined)
  {
    prewait = 0;
  }

  // local variables:
  var form = submit.form;
  var checks = new Array();

  // use XMLHttpRequest to send mail if possible:
  var xmlhttp = false;

  // Microsoft:
  try
  {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  }
  catch (e)
  {
    try
    {
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    catch (e)
    {
      xmlhttp = false;
    }
  }

  // Mozilla et al:
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined')
  {
    try
    {
      xmlhttp = new XMLHttpRequest();
    }
    catch (e)
    {
      xmlhttp = false;
    }
  }

  // IceBrowser:
  if (!xmlhttp && window.createRequest)
  {
    try
    {
      xmlhttp = window.createRequest();
    }
    catch (e)
    {
      xmlhttp = false;
    }
  }
  
  // Check XMLHttpRequest Object for completeness:
  if (xmlhttp)
  {
    if (typeof(xmlhttp["setRequestHeader"]) == "undefined") xmlhttp = false;
    if ( navigator && navigator.userAgent.indexOf("Opera") > 0 )
    {
      // Operas XMLHttpRequest doesn't work properly:
      xmlhttp = false;
   /* // In case later versions do it better:
    * var opera = parseFloat(navigator.userAgent.match(/[0-9]+\.[0-9]+$/));
    * if (opera < 9) xmlhttp = false;
    */
    }
  }

  // Create querystring from form-fields:
  function qstring()
  {
    var components = new Array();
    for (var idx in form.elements)
    {
      var e = form.elements[idx];
      if (e && e.type && e.name && e.value)
      {
      	components.push( encodeURIComponent(e.name) + '='
            + encodeURIComponent(e.value) );
      }
    }
    return components.join("&");
  }

  // Change Texts:
  function newtext(id, text)
  {
    var node = document.getElementById(id);
    if (node)
    {
      if (node.type && node.value)
      {
        node.value = text;
      }
      else
      {
        while (node.firstChild)
        {
          node.removeChild(node.firstChild);
        }
        node.appendChild(document.createTextNode(text));
      }
    }
  }

  // Check for non-empty field:
  function isString(text)
  {
    return (text != "");
  }

  // Check for syntactically correct email:
  function isEmail(text)
  {
    return (text.search(/^[a-zA-Z0-9._-]+@[^.@ ]+\.[^@ ]+$/) >= 0);
  }

  // Add a form check: (public)
  this.addCheck = function(check, fieldid, errid, errmsg)
  {
    var chkrec = {
    	"field": fieldid,
        "check": check,
	"id": errid,
	"text": errmsg
    };
    checks.push(chkrec);
  }

  // Event-Hander for form submit:
  form.onsubmit = function()
  {
    // Check form fields:
    var form_ok = true;
    var error = {};
    for (var idx in checks)
    {
      var data = checks[idx];
      if (!error[data.field])
      {
        var field = document.getElementById(data.field);
        if (field.type)
        {
          if (
	      (data.check == "isEmail") && (!isEmail(field.value)) ||
	      (data.check == "isString") && (!isString(field.value))
	  )
	  {
            form_ok = false;
            error[data.field] = 1;
	    newtext(data.id, data.text);
	  }
	  else
	  {
	    newtext(data.id,"");
	  }
        }
      }
    }
    if (!form_ok)
    {
      return false;
    }

    if (!xmlhttp)
    {
      // Use standard submit when XMLHttpRequest isn't available:
      return true;
    }

    // Disable submit-button:
    submit.disabled = true;

    // POST in asynchronous mode:
    xmlhttp.open("POST", submit.form.action, true)

    // Event-Handler for HTTP Response:
    xmlhttp.onreadystatechange = function()
    {
      if ( xmlhttp.readyState == 4 )
      {
        // Eval JSON:
        var response = eval('(' + xmlhttp.responseText + ')');

	// Replace Texts like specified by server-side script:
	for (var id in response.replace)
	{
	  newtext(id, response.replace[id]);
	}

	// Hide Wait-Message:
	if (wait && wait.style)
	{
	  wait.style.display = "none";
	}

	// Enable submit button:
	submit.disabled = false;

	if (response.success == 1)
	{
	  // If mail was sent, show confirmation message:
	  if (complete && complete.style)
	  {
	    complete.style.display = "block";
	  }
	}
      }
    }; // End of HTTP Response Handler


    // Standard Content-Type for formdata:
    xmlhttp.setRequestHeader("Content-Type",
        "application/x-www-form-urlencoded; charset=utf-8");

    // Request JSON Reply from Server:
    xmlhttp.setRequestHeader("Accept", "text/json");

    // Show Wait-Message:
    if (wait && wait.style)
    {
      wait.style.display = "block";
    }

    // Do Request:
    window.setTimeout(function() { xmlhttp.send(qstring()); }, prewait);

    // Do NOT submit in normal way:
    return false;

  }; // End of submit handler

}


