function Exception(title) {
  this.title = title;
}

var xFormParser = {
  filters : {
    PREPROCESSOR  : 1,
    POSTPROCESSOR : 2,
    RESET         : 4,
    CLEAR         : 8,
    desc          : {
      1 : 'preprocessor',
      2 : 'postprocessor',
      4 : 'reseter',
      8 : 'cleaner'
    },
    list          : new Array()
  },
  nextElementIndex : 0,
  nsList : {}
};

xFormParser.getNextElementIndex = function() {
  return this.nextElementIndex++;
};

xFormParser.init = function(ns) {
  this.registerNS('form', 'xf');
  this.registerNS('buttons',  'xfButtons');
};

xFormParser.getFilter = function(filterName) {
  for (var i = 0; i < xFormParser.filters.list.length; i++) {
    if (xFormParser.filters.list[i].filter.getName() == filterName) {
      return xFormParser.filters.list[i].filter;
    }
  }
};

xFormParser.getFilterNS = function(filterName) {
  return this.nsList[filterName];
};

xFormParser.registerFormFilter = function(filter, mode, ns) {
  this.filters.list.push(
    {filter : filter,
     mode   : mode}
  );
  this.registerNS(filter.ns, ns);
};

xFormParser.registerNS = function(ns, uri) {
  this.nsList[ns] = uri;
};

xFormParser.parse = function(root) {
  var forms = root.getElementsByTagName('form');

  function attachFiltersToForm(form) {
    for (var i = 0; i < xFormParser.filters.list.length; i++) {
      form.addFilter(
        xFormParser.filters.list[i].filter,
        xFormParser.filters.list[i].mode);
    }
  }

  for (var i = 0; i < forms.length; i++) {
    if (forms.item(i).getAttribute(this.getFilterNS('form') + ':parse') == 'yes') {
      logBuffer.log('i\'ve found new parseable form', logBuffer.MSG_NOTICE);
      var xform = new xForm(forms.item(i));
      attachFiltersToForm(xform);

      xform.process(xFormParser.filters.PREPROCESSOR, xform);
    }
  }
};

xFormParser.onClone = function(oldElement, newElement) {
  this.cleanElement(newElement);
  newElement.setAttribute(xFormParser.getFilterNS('form') +  ':cloned', 'yes');
  oldElement.xform.process(xFormParser.filters.PREPROCESSOR |
                           xFormParser.filters.CLEAR,
                           xFormElementFactory.createElement(oldElement.xelement.parent, newElement));
};

xFormParser.cleanElement = function(element) {
  if (element != undefined && element.xelement) {
    element.xelement = null;
  }

  if (!(element != undefined && element.childNodes)) {
    return;
  }

  for (var i = 0; i < element.childNodes.length; i++) {
    xFormParser.cleanElement(element.childNodes[i]);
  }
};

var logBuffer = {
  MSG_NOTICE  : 1,
  MSG_WARNING : 2,
  MSG_ERROR   : 4,
  MSG_DEBUG   : 8,
  MSG_ALL     : 4095,
  heap : new Array(),
  errLevel : 4095,
  reset : function() {
    this.heap = new Array()
  }
};

logBuffer.setErrorLevel = function(level) {
  this.errLevel = parseInt(level);
};

logBuffer.getErrorLevel = function() {
  return parseInt(this.errLevel);
};

logBuffer.log = function(message, messageType) {
  messageType = isNaN(messageType) ? this.MSG_DEBUG : messageType;
  if ((messageType & this.errLevel) > 0) {
    log(sprintf('&nbsp;&nbsp;%s', String(message)));
  }
};

logBuffer.addEvent = function(element, context, message, messageType) {
  this.heap[this.heap.length] = {
    element : element,
    context : context,
    message : message,
    messageType : isNaN(messageType) ? this.MSG_DEBUG : messageType};
  this.log(message, messageType);
};

logBuffer.getMessages = function() {
  var result = new Array();

  for (var i = 0; i < this.heap.length; i++) {
    if ((this.heap[i].messageType & this.errLevel) > 0) {
      result.push(this.heap[i].message);
    }
  }
  return result;
};

xFormParser.init();