function FormHandler(form) {

  var form = form;

  var dataElements = new Array();

  var saveDataElements = new Array();

  this.onDataChanged = onDataChanged;



  construct.call(this);



  function construct() {

    var eventHandler = new EventHandler(form);

    eventHandler.attachEvent("onsubmit", onFormSubmit);

    var elements = form.elements;

    for(var i=0; i<elements.length; i++) {

      var className = " " + elements[i].className + " ";

      if(className.indexOf(' data ') != -1) {

        dataElements[dataElements.length] = new DataElement(this, elements[i]);

      } else if(className.indexOf(' savedata ') != -1) {

        saveDataElements[saveDataElements.length] = elements[i];

        elements[i].disabled = true;

      }

    }

  }



  function getFormChanged() {

    var changed = {};

    changed["anyChanged"] = false;

    for(var i=0; i<dataElements.length; i++) {

      if(dataElements[i].isChanged()) {

        changed[dataElements[i].getDataIndex()] = true;

        changed["anyChanged"] = true;

      }

    }

    return changed;

  }



  function onDataChanged() {

    var changed = getFormChanged();

    for(var i=0; i<saveDataElements.length; i++) {

      var dataIndex = NVL(saveDataElements[i]["dataindex"], 0);

      saveDataElements[i].disabled = !changed[dataIndex];

    }

  }



  function onFormSubmit() {

    return getFormChanged()["anyChanged"];

  }



  function DataElement(formHandler, element) {

    var element = element;

    var formHandler = formHandler;

    var initValue;

    var capturedEvents = new Array("onchange", "onclick", "onkeydown", "onkeyup", "onpaste");

    this.isChanged = new Function("return false;");

    this.getDataIndex = getDataIndex;



    construct.call(this);



    function construct() {

      element.dataElement = this;



      if(element.tagName.toLowerCase() == "input" && (element.type.toLowerCase() == "text" || element.type.toLowerCase() == "password" || element.type.toLowerCase() == "file")) {

        initValue = element.value;

        this.isChanged = isTextChanged;

      } else if(element.tagName.toLowerCase() == "textarea") {

        initValue = element.value;

        this.isChanged = isTextChanged;

      } else if(element.tagName.toLowerCase() == "input" && (element.type.toLowerCase() == "checkbox" || element.type.toLowerCase() == "radio")) {

        initValue = element.checked;

        this.isChanged = isCheckboxChanged;

      } else if(element.tagName.toLowerCase() == "select") {

        initValue = element.selectedIndex;

        this.isChanged = isSelectChanged;

      } else {

        throw "Unknown data element";

      }



      var eventHandler = new EventHandler(element);

      for(var i=0; i<capturedEvents.length; i++) {

        eventHandler.attachEvent(capturedEvents[i], onDataChanged);

      }

    }



    function isTextChanged() {

      return initValue != element.value;

    }



    function isCheckboxChanged() {

      return initValue != element.checked;

    }



    function isSelectChanged() {

      return initValue != element.selectedIndex;

    }



    function onDataChanged() {

      formHandler.onDataChanged();

      return true;

    }



    function getDataIndex() {

      return NVL(element["dataindex"], 0);

    }

  }

}



function initFormHandlers() {

  var forms = document.forms;

  for(var i=0; i<forms.length; i++) {

    var className = " " + forms[i].className + " ";

    if(className.indexOf(' data ') != -1) {

      new FormHandler(forms[i]);

    }

  }

}


