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]);
    }
  }
}





