/********************
***** Ajax Core *****
********************/

// return Ajax object
function ajaxObject() {
  var ajaxRequest;  // infamous Ajax variable
  var error;  // error object

  // browser support code
  try { ajaxRequest = new XMLHttpRequest(); /* Opera 8.0+, Firefox, Safari */ }
  catch(error) {
    try { ajaxRequest = new ActiveXObject('Msxml2.XMLHTTP'); /* IE browsers */ }
    catch(error) {
      try { ajaxRequest = new ActiveXObject('Microsoft.XMLHTTP'); /* other supported browsers */ }
      catch(error) {
        // no Ajax support
        alert('Your browser does not support Ajax!');
        ajaxRequest = false;  // Ajax failure
      }
    }
  }

  return ajaxRequest;  // return Ajax object/failure
}

// submit via Ajax
function ajaxSend(ajaxRequest, uri, qs) {
  // request data from the server via Ajax
  ajaxRequest.open('POST', uri, true);
  ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  ajaxRequest.send('ajax=true'+(qs!=''?'&'+qs:''));
}

// build query string for Ajax
function buildQS(formID) {
  var qs = '';
  var frm = document.getElementById(formID);  // get form object
  for(var j=0; j<frm.length; j++)  // loop through form elements
    if(frm.elements[j].name && (frm.elements[j].type!='checkbox' || (frm.elements[j].type=='checkbox' && frm.elements[j].checked)))  // element has a name and isn't a checkbox or is checked
      qs += (qs.length?'&':'') + escape(frm.elements[j].name) + '=' + escape(frm.elements[j].type=='checkbox'?(frm.elements[j].value?frm.elements[j].value:'on'):frm.elements[j].value);  // add key/value pair
  return qs;
}

/*************************
***** Ajax Functions *****
*************************/

// fill given container with Ajax results
function ajaxCallback(qs) {
  var ajaxRequest = ajaxObject();  // get Ajax object
  if(!ajaxRequest) return false;  // Ajax failed to start

  // receive data from server via Ajax when complete
  ajaxRequest.onreadystatechange = function() {
    if(ajaxRequest.readyState==4)  // Ajax request completed
      ajaxParseResponse(ajaxRequest.responseText);  // send results to pre-defined ajaxParseResponse()
  }

  // request data from the server via Ajax
  ajaxSend(ajaxRequest, window.location.href, qs);
}

// fill given container with Ajax results, submitting to self
function ajaxSelf(containerID, qs, seamless, skipFormInit) {
  var ajaxRequest = ajaxObject();  // get Ajax object
  if(!ajaxRequest) return false;  // Ajax failed

  // set processing circle
  if(!seamless)  // if flagged as seamless, then don't show processing circle
    document.getElementById(containerID).innerHTML = '<p class="center"><img src="/images/processing-circle.gif" />&nbsp; <span id="'+containerID+'-status">Sending request...<\/span><\/p>';

  // receive data from server via Ajax when complete
  ajaxRequest.onreadystatechange = function() {
    switch(ajaxRequest.readyState) {
      case 1:  // loading
        if(document.getElementById(containerID+'-status'))
          document.getElementById(containerID+'-status').innerHTML = 'Processing request...';
        break;
      case 2:  // loaded
      case 3:  // interative
        if(document.getElementById(containerID+'-status'))
          document.getElementById(containerID+'-status').innerHTML = 'Updating screen...';
        break;
      case 4:  // complete
        document.getElementById(containerID).innerHTML = ajaxRequest.responseText;
        if(!skipFormInit) formInit();  // initialize first form
    }
  }

  ajaxSend(ajaxRequest, window.location.href, qs);  // request data from the server via Ajax

  return true;  // Ajax succeeded
}

// fill given container with Ajax results, submitting to self
function ajaxSubmit(containerID, formID, seamless, skipFormInit) {
  return ajaxSelf(containerID, buildQS(formID), seamless, skipFormInit);  // request data from the server via Ajax
}

/************************
***** Auto-complete *****
************************/

// set value to auto-complete selection
function autocompleteSelect(inputID, value, formID) {
  document.getElementById(inputID).value = value;  // set value of input with selected value
  autocompleteToggle(inputID);  // toggle visibility of auto-complete box
  if(formID!=undefined) formSubmit(formID);  // submit form

  return false;  // don't follow link
}

// toggle auto-complete box
function autocompleteToggle(inputID, qs) {
  var containerID = inputID+'_complete';  // auto-complete results container

  if(qs!=undefined && document.getElementById(inputID).value.length>2) {  // get auto-complete suggestions, display them
    var ajaxRequest = ajaxObject();  // get Ajax object
    if(!ajaxRequest) return false;  // Ajax failed to start

    // receive data from server via Ajax when complete
    ajaxRequest.onreadystatechange = function() {
      if(ajaxRequest.readyState==4) {  // request complete
        document.getElementById(containerID).innerHTML = ajaxRequest.responseText;  // set container contents
        document.getElementById(containerID).style.display = ajaxRequest.responseText!='' ? '' : 'none';  // if has contents then display box, otherwise hide it
      }
    }

    // request data from the server via Ajax
    ajaxSend(ajaxRequest, window.location.href, 'complete='+escape(document.getElementById(inputID).value)+(qs?'&'+qs:''));
  }
  else  // hide suggestions
    document.getElementById(containerID).style.display = 'none';
}

// hide any auto-complete divs
function autocompleteHideAll() {
  var divs = document.getElementsByTagName('div');  // get all divs
  for(var j=0; j<divs.length; j++)  // loop through divs
    if(divs[j].id.indexOf('_complete')!=-1)  // is an auto-complete div
      divs[j].style.display = 'none';  // hide div
}

/***************
***** Form *****
***************/

// click click button on "enter" keypress
function clickOnEnter(evt, buttonID) {
  if((window.event && evt.keyCode==13) || (evt.which && evt.which==13)) {  // IE and others (13 is ASCII for Enter key)
    if(buttonID!='') {  // button ID given
      var btn = document.getElementById(buttonID);
      btn.focus();  // set focus on button (just in case there are onBlur events)
      btn.click();  // invoke button click
    }
    else  // no button ID given
      this.blur();  // drop focus

    return false;
  }
  else
    return true;
}

// select first element in given form
function formInit(formID) {
  if(typeof(formID)!='string') {  // page init
    var found = false;  // haven't found an initializable

    for(var j=0; j<document.forms.length; j++)
      if(document.forms[j].parentNode.className.split(' ').indexOf('navbar')==-1 && document.forms[j].className.split(' ').indexOf('noInit')==-1) {
        found = true;
        break;
      }

    if(found) {  // if found, use that form
      var frm = document.forms[j];
      for(var j=0; j<frm.elements.length; j++)
        if(frm.elements[j].type!='hidden') {
          frm.elements[j].focus();
          if(frm.elements[j].select)
            frm.elements[j].select();
          break;
        }
    }
  }
  else {
    var frm = document.getElementById(formID);  // get specified/first form
    // select first blank element
    if(frm)  // form exists
      for(var j=0; j<frm.elements.length; j++)
        if(frm.elements[j].type=='checkbox'?!frm.elements[j].checked:frm.elements[j].value=='') {
          frm.elements[j].focus();
          break;
        }
  }
}

// submit form (contents of given form ID)
function formSubmit(formID, forgoAjax, containerID, skipFormInit) {
  var frm = document.getElementById(formID);  // get form object

  autocompleteHideAll();  // hide all auto-complete divs

  // check for errors
  var errors = '';  // init errors
  for(var j=0; j<frm.elements.length; j++)  // loop through form elements
    if(frm.elements[j].name!='' && frm.elements[j].className) {  // has a name attribute and assigned class(es)
      var classes = frm.elements[j].className.split(' ');  // split classes by spaces
      var display = frm.elements[j].title?frm.elements[j].title:(frm.elements[j].name).replace(/^(.)|\s(.)/g, function ($1) { return $1.toUpperCase(); } );  // name to display

      if(classes.indexOf('required')!=-1 && (frm.elements[j].type=='checkbox'?!frm.elements[j].checked:frm.elements[j].value==''))
        errors += "\n  * "+display;
      else if(classes.indexOf('date')!=-1 && frm.elements[j].value.search(/^([0-9]{1,2}\/[0-9]{1,2}\/([12][09])?[0-9]{2})?$/)==-1)
        errors += "\n  * "+display+' (must be in MM/DD/YYYY format)';
      else if(classes.indexOf('email')!=-1 && frm.elements[j].value.search(/^([-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?)?$/i)==-1)
        errors += "\n  * "+display+' (must be valid e-mail address format)';
      else if(classes.indexOf('numeric-positive')!=-1 && frm.elements[j].value.search(/^([0-9\.]+)?$/)==-1)
        errors += "\n  * "+display+' (must be positive number)';
      else if(classes.indexOf('phone')!=-1 && frm.elements[j].value.search(/^(([0-9]{3})?[0-9]{7})?$/)==-1)
        errors += "\n  * "+display+' (must be seven or ten-digit number, no dashes or parentheses)';
      else if(classes.indexOf('time')!=-1 && frm.elements[j].value.search(/^([0-9]{1,2}(:[0-9]{2})?( ?[ap]m)?)?$/i)==-1)
        errors += "\n  * "+display+' (must have the hour, minutes, and AM or PM)';
      else if(classes.indexOf('zipcode')!=-1 && frm.elements[j].value.search(/^([0-9]{5}([0-9]{4})?)?$/)==-1)
        errors += "\n  * "+display+' (must be five or nine-digit number, no dashes)';
//      else if(classes.indexOf('')!=-1 && frm.elements[j].value.search(/^()?$/)==-1)
//        errors += "\n  * "+display+' (must be )';
    }

  if(errors) {  // has errors
    alert('You must fill in the following to continue:'+errors);  // display errors
    formInit(formID);  // initialize form
    return false;  // don't submit form
  }
  else if(forgoAjax)  // don't use Ajax
    return true;  // submit form normal way
  else  // attempt Ajax
    return !ajaxSubmit(containerID?containerID:'ajax', formID, false, skipFormInit);  // submit via Ajax, returning results
}

// click submit button on "enter" keypress
function submitOnEnter(evt, formID) {
  if((window.event && evt.keyCode==13) || (evt.which && evt.which==13)) {  // IE and others (13 is ASCII for Enter key)
    this.blur();  // drop focus (just in case there are onBlur events)
    formSubmit(formID);  // submit form
  }
}

/********************
***** Prototype *****
********************/

// add Array's indexOf support to IE
if(!Array.indexOf) {  // Array class doesn't have indexOf method
  Array.prototype.indexOf = function(value) {  // add indexOf functionality
    for(var j=0; j<this.length; j++)  // loop through array to find matching value
      if(this[j]==value)  // array element matches value
        return j;  // return matching array index
    return -1;  // not found
  }
}

window.onload = formInit;  // initialize first form on page load
