// this is our general object for handling forms
  var formState = new Object();
  
  /**
  *   Is the value in use at on the server?
  *   
  *
  */
  formState.postForm = function(form, url, onSuccess){
     
      // we get a handle to the feedback dif
      var formInfoDivId = form.id + '_InfoDiv';
      var md = dojo.byId(formInfoDivId);
      
      // tell the user we are working on it
      md.innerHTML = "Submitting. Please wait ...";
      md.className = "messageDivWaitOn";
      
      
      // the url is complete including controller and action.
      // call the form validation script
      dojo.xhrPost( {
              url: url, 
              handleAs: "json",
              timeout: 30000,
              form: form.id,
              load: function(response, ioArgs){

                    console.debug("Successful submission");                  

                    if(response[0]){

                        // valid so hide the form
                        form.className = "formOff";
                        // turn no the success div and 
                        // and set the inner html if we have 
                        // a message from the server
                        var sd = dojo.byId(form.id + '_SuccessDiv');
                        if (response[1]) sd.innerHTML = response[1];
                        sd.className = "formSuccessDivOn";
                        
                        // if the response is bigger than 2 then 
                        // we have been given a script to run
                        // by the server
                        if(response.length > 2){
                            var script = response[2];
                            console.debug("about to eval:" + script); 
                            eval(script);
                        }
                        
                        // we may also have been given a script to run by 
                        // the caller to run on success
                        if(onSuccess){
                            console.debug("about to eval:" + onSuccess);
                            eval(onSuccess);
                        }

                    }else{
                        // we are invalid so display the error message.
                        md.innerHTML = response[1];
                        md.className = "messageDivAlertOn";
                    }
                    
                    // always return response - dojo likes it
                    return response;
              },
              error: function(response, ioArgs){
                    console.error("HTTP status code: ", ioArgs.xhr.status);
                    md.innerHTML = "Error! HTTP status code: " . ioArgs.xhr.status;
                    md.className = "messageDivAlertOn";
                    return response;
              }
      });
      
      // whatever we do return false to prevent form submission by
      // normal route
      return false;
      
  };
  
  /**
  *   Is the value in use at on the server?
  *   
  *
  */
  formState.validateField = function(input, url){
      
      // get a handle on the feedback div
      // so we can write messages to it
      var md = dojo.byId(input.name + '_InfoDiv');
      
      // tell the user we are working on it
      md.innerHTML = "Validating...";
      md.className = "messageDivWaitOn";
      
      // calculate the URL to call on the basis of there being a field validate function
      // assumes the url is to the controller and that a action of the form
      // validateFieldName exists.
      var action =  "/validate-" + input.name.toLowerCase();        
      var furl = url + action; // + '?field_value=' + escape(input.value); 
      
      // call the field validation action via ajax
      dojo.xhrGet( {
              url: furl, 
              handleAs: "json",
              timeout: 30000,
              content: {"field_value" : input.value},
              load: function(response, ioArgs){
                if(response[0]){
                    // we are valid 
                    if (response[1] && response[1].length > 0){
                        // valid and contratulatory message
                        md.innerHTML = response[1];
                        md.className = "messageDivInfoOn";
                    }else{
                        // valid and no congratulations
                        md.innerHTML = "";
                        md.className = "messageDivOff";                          
                    }
                    
                    // if the response is bigger than 2 then 
                    // we have been given a script to run
                    if(response.length > 2){
                        var script = response[2];
                        eval(script);
                    }
                    
                }else{
                    // we are invalid so display the error message.
                    md.innerHTML = response[1];
                    md.className = "messageDivAlertOn";
                }
                return response;
              },
              error: function(response, ioArgs){
                  // problems talking to the server so 
                  // display error
                  md.innerHTML = ioArgs.xhr.status;
                  md.className = "messageDivAlertOn";
                  console.error("HTTP status code: ", ioArgs.xhr.status);
                  return response;
              }
      });  
      
  };
  
  formState.fieldChanged = function(fieldId, newValue){
      var field = dojo.byId(fieldId);
      if (field){
          field.innerHTML = newValue;
      }else{
          console.debug('Attempt to alter non-existent field with id: ' + fieldId);
      }
  };
  
  formState.messageDivOff = function(input){
       var md = dojo.byId(input.name + '_InfoDiv');
       md.innerHTML = "";
       md.className = "messageDivOff";
  }
  
  // shows the text version of a combi box
  formState.combiShowText = function(trigger){
      
      // select is the first div txt the second.
      var selectAndTxtDivs = trigger.parentNode.parentNode.getElementsByTagName('div');
      
      // enable and disable
      selectAndTxtDivs[0].getElementsByTagName('select')[0].disabled = true;
      selectAndTxtDivs[1].getElementsByTagName('input')[0].disabled = false;
      
      // hide show
      selectAndTxtDivs[0].style.display = 'none';
      selectAndTxtDivs[1].style.display = 'block';
      
  
  }
  
  // shows the select version of a combi box
  formState.combiShowSelect = function(trigger){
      var selectAndTxtDivs = trigger.parentNode.parentNode.getElementsByTagName('div');
      
      // fire a key press event on the input to clear any validation messages
      // selectAndTxtDivs[1].getElementsByTagName('input')[0].onkeyup();
      
      selectAndTxtDivs[0].getElementsByTagName('select')[0].disabled = false;
      selectAndTxtDivs[1].getElementsByTagName('input')[0].disabled = true;
      selectAndTxtDivs[0].style.display = 'block';
      selectAndTxtDivs[1].style.display = 'none';
  }