/* Copyright (C) The MoreMotion Organization. http://www.moremotion.org
 * All rights reserved. This software is published under the terms of the GPL.
 */
function RecordChanged(elm, fname) {
  PMgr.recordChanged(elm, fname);
};
function ProcessObjectManager() {
  this.selectOption = function(node) {
    var f = OMgr.getEnclosingObject(node);
    if (f) f.selectOption();
  };
  this.getForm = function(name) {
    var forms = document.forms;
    for (var i = 0; i < forms.length; i++) {
      var form = forms[i];
      if (OMgr.getAttribute(form,"mo:type") == "ProcessForm" && OMgr.getAttribute(form,"mo:name") == name) {
        return OMgr.getObject(form);
      }
    }
    return null;
  };
  this.getField = function(formName, blockName, fieldName, recordNumber) {
    try {
      if (recordNumber == null) recordNumber = 1;
      return this.getForm(formName).getBlock(blockName).getRecord(recordNumber).getField(fieldName);
    } catch (e) {}
    return null;
  }
  this.submitProcessForm = function(formName, commandName, target) {
    if (formName.after) {
      return this.getForm(formName).submit(commandName, target);
    } else {
      var prm = formName;
      return this.getForm(prm.formName).submit(prm.commandName, prm.target);
    }
  };
  this.getEnclosingField = function(node) {
    if (OMgr.getAttribute(node,"mo:field")) {
      return OMgr.getObject(node);
    }
    var node = OMgr.findParentNode(node,"mo:field");
    if (node) {
      return OMgr.getObject(node);
    }
    return null;
  };
  this.getEnclosingRecord = function(node) {
    if (OMgr.getAttribute(node,"mo:type") == "ProcessRecord") {
      return OMgr.getObject(node);
    }
    var node = OMgr.findParentNode(node,"mo:type","ProcessRecord");
    if (node) {
      return OMgr.getObject(node);
    }
    return null;
  };
  this.getEnclosingBlock = function(node) {
    if (OMgr.getAttribute(node,"mo:type") == "ProcessBlock") {
      return OMgr.getObject(node);
    }
    var node = OMgr.findParentNode(node,"mo:type","ProcessBlock");
    if (node) {
      return OMgr.getObject(node);
    }
    return null;
  };
  this.getEnclosingForm = function(node) {
    if (OMgr.getAttribute(node,"mo:type") == "ProcessForm") {
      return OMgr.getObject(node);
    }
    var node = OMgr.findParentNode(node,"mo:type","ProcessForm");
    if (node) {
      return OMgr.getObject(node);
    }
    return null;
  };
  this.getContainedBlockNode = function(node) {
    if (OMgr.getAttribute(node,"mo:type") == "ProcessRecord") {
      return node;
    } else {
      return OMgr.findChildNode(node,null,"mo:type","ProcessRecord",4);
    }
  };
  this.recordChanged = function(node, fname) {
    var prec = this.getEnclosingRecord(node);
    if (prec) prec.setModified(fname);
  };
  this.fieldChanged = function(node) {
    var f = this.getEnclosingField(node);
    if (f) f.setModified();
  };
  this.setInitialOption = function(elm, initialOption) {
    if (initialOption) {
      for (var i = 0; i < elm.options.length; i++) {
        if (initialOption == elm.options[i].value) {
          elm.options[i].selected = true;
          elm.options[i].setAttribute("selected","true");
          return;
        }
      }
    }
  };
  this.toggleSelection = function(elm,color) {
    var rec = OMgr.findParentObject(elm,"mo:type","ProcessRecord");
    if (rec) rec.checkRecord(elm.checked,color);
  };
  this.toggleAllSelections = function(elm,blockName) {
    var node = OMgr.findParentNode(elm,"mo:type","ProcessForm")
    if (node) {
      var block = OMgr.findChildObject(node,"type:ProcessBlock","mo:name",blockName);
      if (block) block.processAllSelections(elm.checked == true);
    }
  };
  this.keyCode = null;
  this.specialSelect = function(node,color) {
    if (this.keyCode == null || !(this.keyCode == 16 || this.keyCode == 17) ) return;
    var r = OMgr.getObject(node);
    if (r) {
      var selected = r.isSelected();
      if (this.keyCode == 16 && !selected) {
        r.checkRecord(true);
      } else if (this.keyCode == 17 && selected) {
        r.checkRecord(false);
      }
    }
  };
  this.specialKeyDown = function(e) {
    this.keyCode = (e.keyCode) ? e.keyCode : e.keyChar;
  };
  this.specialKeyUp = function(e) {
    this.keyCode = null;
  };
};
var PMgr = new ProcessObjectManager();
function ProcessForm(node) {
  this.base = MoreMotionObject;
  this.base(node);
  this.isProcessForm = true;
  this.getBlock = function(name) {
    var block = OMgr.findChildObject(this.node.parentNode,"type:ProcessBlock","mo:name",name);
    if (block) {
      block.form = this;
      return block;
    }
    return null;
  };
  this.getCommand = function(name) {
    var elms = this.node.elements["__pcommand"];
    if (!elms) return null;
    if (!elms.length) elms = [elms];
    for (var i = 0; i < elms.length; i++) {
      var cmd = new ProcessCommand(elms[i]);
      if (cmd.name == name) {
        return cmd;
      }
    }
    return null;
  };
  this.setAction = function(action) {
    this._action = this.node.action;
    this.node.action = action;
  };
  this.resetAction = function() {
    if (this._action) this.node.action = this._action;
  }
  this.reset = function() {
    this.node.reset();
    var elms = this.node.elements;
    for (var i = 0; i < elms.length; i++) {
      elm = elms[i];
      if (elm.name.substr(0,4) == "pbm_" && elm.name.indexOf("_modified") > 0) {
        elm.value = "";
      }
    }
  };
  this.disableCommandButtons = function() {
    var elms = this.node.elements["__pcommand"];
    if (!elms) return;
    if (!elms.length) elms = [elms];
    for (var i = 0; i < elms.length; i++) {
      var elm = elms[i];
      if (elm.type == "submit" || elm.type == "button") {
        elm.disabled = true;
      }
    }
  };
  this.enableCommandButtons = function() {
    var elms = this.node.elements["__pcommand"];
    if (!elms) return;
    if (!elms.length) elms = [elms];
    for (var i = 0; i < elms.length; i++) {
      var elm = elms[i];
      if (elm.type == "submit" || elm.type == "button") {
        elm.disabled = false;
      }
    }
  };
  this.createHidden = function(name) {
    var frm = this.node;
    var elm = frm.elements[name];
    if (elm) {
      elm.value = "";
    } else {
      elm = document.createElement("INPUT")
      elm.name = name;
      elm.type = "hidden";
      frm.appendChild(elm);
    }
    return elm;
  };
  this.submit = function(commandName, targetParam) {
    if (this.boolProp("formDisabled")) return false;
    var c = this.getCommand(commandName);
    if (this._validate(c, true) == false) return false;
    if (c.props.confirmMessage && !confirm(c.props.confirmMessage)) {
      return false;
    }
    this.createHidden("_cmd").value = commandName;
    var pageInfo = OMgr.getPageInfo(this.node);
    this.createHidden("_originpage").value = pageInfo.name;
    if (pageInfo.variant) this.createHidden("_variant").value = pageInfo.variant;
    this.createHidden("_scope").value = this.props.formConfigName || this.name;
    if (this.props.lang != "ml") this.createHidden("_lang").value = pageInfo.lang;
    this.createHidden("_rand").value = (new Date()).getTime();
    this.createHidden("_enc").value = pageInfo.charset;
    if (c.props.beforeSubmitFunc) {
      try {
        var func = eval(c.props.beforeSubmitFunc);
        if (func(this, commandName) == false) return false;
      } catch (e) {
        alert(OMgr.resource("INVALID_BEFORE_SUBMIT_FUNCTION_DEFINITION",c.props.beforeSubmitFunc + " : " + e.message));
        return false;
      }
    }
    var target = null;
    if (targetParam) {
      var lc = targetParam.trim().toLowerCase();
      if (lc == "*") target = null;
      else if (lc == "default") target = "";
      else if (lc == "new window") target = "_blank";
      else if (lc == "whole page") target = "_top";
      else if (lc == "parent frame") target = "_parent";
      else target = targetParam;
    }
    var origTarget = null;
    if (target != null) {
      origTarget = this.node.target;
      this.node.target = target;
    }
    if (!this.node.target) {
      this.props.formDisabled = "true";
      this.saveProps();
      this.disableCommandButtons();
    }
    this.eliminateTemplateRecords();
    this.node.submit();
    if (origTarget != null) {
      this.node.target = origTarget;
    }
    return true;
  };
  this.ajaxSubmit = function(prm) {
    if (this.boolProp("formDisabled")) return false;
    var c = this.getCommand(prm.commandName);
    if (prm.beforeSubmitFunc) c.props.beforeSubmitFunc = prm.beforeSubmitFunc;
    if (prm.validateInput) c.props.validateInput = prm.validateInput;
    if (prm.confirmMessage) c.props.confirmMessage = prm.confirmMessage;
    if (prm.busyImage) c.props.busyImage = prm.busyImage;
    if (prm.submitMethod) c.props.submitMethod = prm.submitMethod;
    var acc = new RequestParameterAccumulator(prm.requestParams);
    acc.forAjax = true;
    if (this._validate(c, true, acc) == false) return false;
    if (c.props.confirmMessage && !confirm(c.props.confirmMessage)) {
      return false;
    }
    acc.add("_cmd",prm.commandName);
    acc.add("_originpage",this.props.originPage);
    acc.add("_variant",this.props.variant);
    acc.add("_scope",this.props.formConfigName || this.name);
    acc.add("_usedsourceareas",AjaxMgr.getAlreadyUsedSourceAreas());
    var func = prm.beforeSubmitFunc || c.props.beforeSubmitFunc;
    if (func) {
      try {
        if (func.after) func = eval(func);
        if (func(this, prm.commandName) == false) return false;
      } catch (e) {
        alert(OMgr.resource("INVALID_BEFORE_SUBMIT_FUNCTION_DEFINITION",c.props.beforeSubmitFunc + " : " + e.message));
        return false;
      }
    }
    this.collectAjaxHiddenBoxes(acc);
    var props = new Object();
    props.callbackFunc = prm.callbackFunc;
    props.userData = prm.userData;
    var request = new AjaxRequest(acc,null,props);
    request.service = "AjaxProcessManager.doms";
    request.busyImage = prm.busyImage || c.props.busyImage;
    request.waitForResponse = prm.waitForResponse;
    request.pageInfo = OMgr.getPageInfo(this.node);
    request.method = prm.submitMethod || "POST";
    request.send();
    return true;
  };
  this.collectAjaxHiddenBoxes = function(acc) {
    var elms = this.node.elements["__ajax_hidden"];
    if (!elms) return;
    if (!elms.length) elms = [elms];
    for (var i = 0; i < elms.length; i++) {
      var elm = elms[i];
      acc.add( OMgr.getAttribute(elm,"mo:name"),elm.value);
    }
  };
  this.clear = function() {
  };
  this.validate = function(commandName) {
    var c = this.getCommand(commandName);
    if (c == null) {
      alert(OMgr.resource("EXECUTION_COMMAND_NOT_FOUND", commandName, this.name));
      return false;
    }
    return this._validate(c, false);
  };
  this._validate = function(c, forSubmit, acc) {
    if (c.props.requiredBlocks) {
      if (!acc) acc = new Object();
      acc.rpps = new Array();
      if (forSubmit == true) acc.forSubmit = true;
      var blks = c.props.requiredBlocks.split(",");
      for (var i = 0; i < blks.length; i++) {
        var def = blks[i];
        var rpp = def.after(":");
        var blockName = def.before(":",def);
        if (forSubmit) acc.rpps[blockName] = rpp;
      }
      for (var i = 0; i < blks.length; i++) {
        var def = blks[i];
        var rpp = def.after(":");
        var blockName = def.before(":",def);
        var b = this.getBlock(blockName);
        if (b) {
          b.setId(i+1);
          if (rpp && forSubmit) {
            acc.rpps[blockName] = null;
            if (b.checkSelectedModified(rpp) == false) {
              return false;
            }
          }
          acc.validate = c.boolProp("validateInput");
          acc.parentRecNum = new Stack();
          if (b.validate(acc) == false) return false;
          if (forSubmit) b.setPBInfo(acc);
        }
      }
    }
    return true;
  };
  this.eliminateTemplateRecords = function() {
    var blocks = OMgr.getObjects(this.node,"mo:type","ProcessBlock");
    for (var i = 0; i < blocks.length; i++) {
      var block = blocks[i];
      if (block.boolProp("recordManip")) {
        var node = block.getTemplateRowNode();
        if (node) node.parentNode.removeChild(node);
      }
    }
  };
};
function ProcessRecordIterator(block) {
  this.block = block;
  this.index = -1;
  this.rowNode = null;
  this.recordNode = null;
  this.nodes = new Array();
  this.init = function() {
    var rootNode = OMgr.getChildNode(block.node,"TBODY");
    if (rootNode && rootNode.hasChildNodes) {
      for (var i = 0; i < rootNode.childNodes.length; i++) {
        var node = rootNode.childNodes[i];
        if (node.nodeType == 1 && !OMgr.getAttribute(node,"mo:template")) {
          this.nodes[this.nodes.length] = node;
        }
      }
    }
  }
  this.init();
  this.top = function() {
    this.index = -1;
    this.rowNode = null;
    this.recordNode = null;
  };
  this.bottom = function() {
    this.index = this.nodes.length;
    this.rowNode = null;
    this.recordNode = null;
  };
  this.next = function() {
    if (this.nodes.length > 0) {
      this.index++;
      while (this.index < this.nodes.length) {
        this.rowNode = this.nodes[this.index];
        if (this.rowNode) {
          var node = PMgr.getContainedBlockNode(this.rowNode);
          if (node) {
            this.recordNode = node;
            return true;
          }
        }
        this.index++;
      }
    }
    this.rowNode = null;
    this.recordNode = null;
    return false;
  };
  this.previous = function() {
    if (this.nodes.length > 0) {
      this.index--;
      while (this.index >= 0) {
        this.rowNode = this.nodes[this.index];
        if (this.rowNode) {
          var node = PMgr.getContainedBlockNode(this.rowNode);
          if (node) {
            this.recordNode = node;
            return true;
          }
        }
        this.index--;
      }
    }
    this.rowNode = null;
    this.recordNode = null;
    return false;
  };
  this.getRecord = function() {
    if (this.recordNode) {
      return OMgr.getObject(this.recordNode);
    }
    return null;
  };
  this.getRecordNode = function() {
    return this.recordNode;
  };
  this.getRowNode = function() {
    return this.rowNode;
  };
  this.getIndex = function() {
    return this.index;
  };
};
function ProcessBlock(node) {
  this.base = MoreMotionObject;
  this.base(node);
  this.isProcessBlock = true;
  this.id = "1"; 
  this.setId = function(id) {
    this.id = id + "";
    this.prefix = "pf_" + id + "_";
  };
  this.init = function() {
    if (this.boolProp("recordManip")) {
      this.prepareTemplateRecord();
    }
  };
  this.getForm = function() {
    return PMgr.getEnclosingForm(this.node);
  };
  this.getRecord = function(index) {
    var x = 0;
    var parentNode = OMgr.getChildNode(this.node,"TBODY");
    if (parentNode && parentNode.hasChildNodes) {
      for (var i = 0; i < parentNode.childNodes.length; i++) {
        var node = parentNode.childNodes[i];
        if (node.nodeType == 1 && !OMgr.getAttribute(node,"mo:template")) {
          var n = PMgr.getContainedBlockNode(node);
          if (n && ++x == index) return OMgr.getObject(n);
        }
      }
    }
    return null;
  };
  this.getRecordIterator = function() {
    var itr = new ProcessRecordIterator(this);
    if (this.boolProp("recordManip")) itr.recordManip = true;
    return itr;
  };
  this.getFirstRecord = function() {
    return this.getRecord(1);
  };
  this.getLastRecord = function() {
    var parentNode = OMgr.getChildNode(this.node,"TBODY");
    if (parentNode && parentNode.hasChildNodes) {
      for (var i = parentNode.childNodes.length - 1; i >= 0; i--) {
        var node = parentNode.childNodes[i];
        if (node.nodeType == 1 && !OMgr.getAttribute(node,"mo:template")) {
          var n = PMgr.getContainedBlockNode(node);
          if (n) return OMgr.getObject(n);
        }
      }
    }
    return null;
  };
  this.setStatusFieldName = function(elm) {
       elm.name = "px_" + this.id + "_recstat";
  };
  this._hasInnerPB = null;
  this.hasInnerPB = function() {
       if (this.isInnerPB) return false;
    if (this._hasInnerPB == null) {
       this._hasInnerPB = OMgr.findChildNode(this.node, null, "mo:type", "ProcessBlock") ? true : false;
    }
    return this._hasInnerPB;
  };
  this.validate = function(acc,isInnerPB) {
    this.isInnerPB = isInnerPB;
    if (isInnerPB) this.setPBInfo(acc);
    var rpp = acc ? acc.rpps[this.name] : null;
    if (rpp) {
      if (this.checkSelectedModified(rpp) == false) {
        return false;
      }
    }
    var itr = this.getRecordIterator();
    var i = 0;
    while (itr.next()) {
      var r = itr.getRecord();
      r.block = this;
      if (acc) {
        if (i == 0) acc.parentRecNum.push(i);
        else acc.parentRecNum.set(i);
      }
      if (r.validate(acc) == false) return false;
      i++;
    }
  };
  this.clear = function() {
    var itr = this.getRecordIterator();
    while (itr.next()) {
      itr.getRecord().clear();
    }
  };
  this.processAllSelections = function(check) {
    var color = this.props.selectionColor;
    var itr = this.getRecordIterator();
    while (itr.next()) {
      itr.getRecord().checkRecord(check, color);
    }
  };
  this.setWarnColor = function() {
    var firstElm = null;
    var color = this.props.warnColor;
    var itr = this.getRecordIterator();
    while (itr.next()) {
      var node = itr.getRecordNode();
      if (color) {
        node.style.backgroundColor = color;
      }
      if (firstElm == null) {
        firstElm = OMgr.getChildNode(node,"input","_selected");
      }
    }
    if (firstElm) firstElm.focus();
  };
  this.removeWarnColor = function() {
    var color = this.props.warnColor;
    if (!color) return;
    var itr = this.getRecordIterator();
    while (itr.next()) {
      var node = itr.getRecordNode();
      node.style.backgroundColor = null;
    }
  };
  this.checkSelectedModified = function(rpp) {
    var onlyOneSelectedCheck = rpp == "OnlyOneSelected";
    var atLeastOneSelectedCheck = rpp == "AtLeastOneSelected";
    var atLeastOneModifiedCheck = rpp == "AtLeastOneModified";
    if (onlyOneSelectedCheck || atLeastOneSelectedCheck || atLeastOneModifiedCheck) {
      var selectionCount = 0;
      var modifiedCount = 0;
      var itr = this.getRecordIterator();
      while (itr.next()) {
        var rs = itr.getRecord().getRecordStatus();
        if (rs.isSelected) selectionCount++;
        if (rs.isModified()) modifiedCount++;
        itr.getRecordNode().style.backgroundColor = "";
      }
      if (onlyOneSelectedCheck && selectionCount == 0) {
        alert(OMgr.resource("NO_RECORD_SELECTED"));
        this.setWarnColor();
        return false;
      }
      if (onlyOneSelectedCheck && selectionCount > 1) {
        alert(OMgr.resource("ONLY_ONE_RECORD_CAN_BE_SELECTED"));
        this.setWarnColor();
        return false;
      }
      if (atLeastOneSelectedCheck && selectionCount == 0) {
        alert(OMgr.resource("NO_RECORD_SELECTED"));
        this.setWarnColor();
        return false;
      }
      if (atLeastOneModifiedCheck && modifiedCount == 0) {
        alert(OMgr.resource("NO_RECORD_MODIFIED"));
        this.setWarnColor();
        return false;
      }
    }
    return true;
  };
  this.copyRecord = function(fromRecordNumber, beforeRecordNumber) {
    if (this.templateNode == null) return false;
    if (!this.normal) {
      alert(OMgr.resource("RECORD_MANIPULATION_NOT_ALLOWED"));
      return null;
    }
    var sourceNode = null;
    if (fromRecordNumber) {
      var sourceRec = this.getRecord(fromRecordNumber);
      sourceNode = sourceRec.getRowNode();
    } else {
      sourceNode = this.templateNode;
      fromRecordNumber = "t";
    }
    var clonedNode = sourceNode.cloneNode(true);
    clonedNode.style.display = "block";
    var newRecordNumber = this.getRecordSequence();
    this.changeElementIds(clonedNode,fromRecordNumber,newRecordNumber);
    var beforeNode = null;
    if (beforeRecordNumber) {
      var beforeRec = this.getRecord(beforeRecordNumber);
      beforeNode = beforeRec.getRowNode();
    }
    var targetNode = this.getDOMNode().insertBefore(clonedNode, beforeNode);
    this.templateRecord.clone(newRecordNumber);
    var nr = new ProcessRecord(this,newRecordNumber);
    if (fromRecordNumber == "t") nr.clear();
    return nr;
  };
  this.removeAllRecords = function() {
    var itr = this.getRecordIterator();
    while (itr.next()) {
      var node = itr.getRowNode();
      node.parentNode.removeChild(node);
    }
    if (WinMgr.isGecko) this.node.innerHTML = this.node.innerHTML;
  };
  this.addRecord = function() {
    var node = this.getTemplateRowNode();
    if (node) {
      var newNode = node.parentNode.appendChild(node.cloneNode(true));
      newNode.style.display = "block"; 
      newNode.removeAttribute("mo:template");
      OMgr.initialize(newNode);
      var recordNode = OMgr.findChildNode(newNode,null,"mo:type","ProcessRecord",7);
      if (recordNode) return OMgr.getObject(recordNode);
    }
    return null;
  }
  this.setRecordNumbers = function(fields) {
    fields = fields.split(",");
    var itr = this.getRecordIterator();
    var recnum = 0;
    while (itr.next()) {
       recnum++;
       var r = itr.getRecord();
       for (var i = 0; i < fields.length; i++) {
               var f = r.getField(fields[i]);
               if (f && f.setRecordNumber) {
                       f.setRecordNumber(recnum);
               }
       }
    }
  };
  this.getTemplateRowNode = function() {
    var parentNode = OMgr.getChildNode(this.node,"TBODY");
    if (parentNode && parentNode.hasChildNodes) {
      for (var i = 0; i < parentNode.childNodes.length; i++) {
        var node = parentNode.childNodes[i];
        if (node.nodeType == 1) {
          if (PMgr.getContainedBlockNode(node)) {
            return node;
          }
        }
      }
    }
    alert(OMgr.resource("TEMPLATE_RECORD_MISSING",this.name));
    return null;
  };
  this.prepareTemplateRecord = function() {
    var node = this.getTemplateRowNode();
    if (node) {
      node.style.display = "none";
      node.setAttribute("mo:template","true");
    } else {
      alert(OMgr.resource("CANNOT_PREPARE_TEMPLATE_RECORD"));
      return null;
    }
  };
  this.setPBInfo = function(acc) {
    if (!acc.pbinfos) acc.pbinfos = new Array();
    if (acc.pbinfos[this.name]) return;
    var s = this.id + ";";
    var prec = this.getRecord(1);
    if (prec) {
      var fields = prec.getFields();
      for (var i = 0; i < fields.length; i++) {
        if (i > 0) s += ",";
        var f = fields[i];
        if (f.getProcessFieldNames) {
               s += f.getProcessFieldNames(",");
        } else {
               if (f.elm && f.elm.type == "checkbox") s += "c:";
          s += f.name;
        }
      }
    }
    if (acc.forAjax) {
      acc.add("_pbinfo_" + this.name, s);
    } else {
      var pbinfo = this.getForm().createHidden("_pbinfo_" + this.name);
      pbinfo.value = s;
    }
    acc.pbinfos[this.name] = true;
  };
};
function RecordStatus(elm) {
  this.modifiedFields = "";
  this.isSelected = false;
  this.parentRecNum = "";
  this.elm = elm;
  var value = elm.value;
  if (value) {
    var values = value.split(";");
    this.modifiedFields = values[0];
    this.isSelected = values[1] == "true";
    this.parentRecNum = values[2];
  }
  this.addModifiedField = function(fieldName) {
    if (!this.modifiedFields) this.modifiedFields = fieldName;
    else {
      var s = " " + this.modifiedFields + " ";
      if (s.indexOf(fieldName) == -1) this.modifiedFields += " " + fieldName;
    }
  };
  this.removeModifiedField = function(fieldName) {
    if (!this.modifiedFields) return;
    if (this.modifiedFields.indexOf(fieldName) == -1) return;
    if (this.modifiedFields == fieldName) { this.modifiedFields = ""; return; }
    var fields = this.modifiedFields.split(" ");
    var buf = "";
    for (var i = 0; i < fields.length; i++) {
      if (fields[i] != fieldName) {
        if (buf) buf += " ";
        buf += fields[i];
      }
    }
    this.modifiedFields = buf;
  };
  this.setUnModified = function() {
    this.modifiedFields = "";
  };
  this.isModified = function() {
    return this.modifiedFields != "";
  };
  this.toString = function() {
    return this.modifiedFields + ";" + (this.isSelected ? "true" : "") + ";" + this.parentRecNum;
  };
  this.save = function() {
    var value = this.toString();
    this.elm.value = value == ";;" ? "" : value;
  };
};
 function ProcessRecord(node) {
  this.base = MoreMotionObject;
  this.base(node);
  this.isProcessRecord = true;
  this.blockId = OMgr.getAttribute(node,"mo:blockId");
  this.getSelectionElement = function() {
    return OMgr.getChildNode(this.node,"input","__selection");
  };
  this.getRecordStatusElement = function() {
       if (!this._rse) {
               var insertNode = null;
       var elms = this.node.getElementsByTagName("input");
       if (!elms.length) elms = [elms];
       for (var i = 0; i < elms.length; i++) {
               var elm = elms[i];
               insertNode = elm.parentNode;
               if (elm.name.startsWith("px_") && elm.name.endsWith("_recstat")) {
                       this._rse = elm;
                       break;
               }
       }
       if (!this._rse) {
                   var elm = OMgr.createElement("INPUT", "px_recstat");
                   elm.type = "hidden";
                   if (!insertNode) insertNode = OMgr.getChildElement(this.node,"td");
                   insertNode.appendChild(elm);
                   this._rse = elm;
       }
       }
    return this._rse;
  };
  this.getRecordStatus = function() {
    return new RecordStatus(this.getRecordStatusElement());
  };
  this.isModified = function() {
    return this.getRecordStatus().isModified();
  };
  this.isSelected = function() {
    return this.getRecordStatus().isSelected;
  };
  this.block = null;
  this.getBlock = function() {
    if (!this.block) this.block = PMgr.getEnclosingBlock(this.node);
    return this.block;
  };
  this.getInnerBlock = function(blockName) {
    var node = OMgr.findChildNode(this.node,"type:ProcessBlock","mo:name",blockName);
    if (node) return OMgr.getObject(node);
    return null;
  };
  this.getField = function(name) {
    var fnode = OMgr.findChildNode(this.node,null,"mo:name",name);
    if (fnode) {
      return OMgr.getObject(fnode);
    }
    return null;
  };
  this.getFields = function() {
    var fields = new Array();
    this._collectFields(fields, this.node);
    return fields;
  };
  this._collectFields = function(fields, parentNode) {
    for (var i = 0; i < parentNode.childNodes.length; i++) {
      var node = parentNode.childNodes[i];
      if (node.nodeType == 1) {
        var attr = OMgr.getAttribute(node,"mo:field");
        if (attr) {
          var f = OMgr.getObject(node);
          if (f) fields[fields.length] = f;
        }
        if (node.hasChildNodes && !OMgr.getAttribute(node,"mo:blockId")) {
          this._collectFields(fields, node);
        }
      }
    }
  };
  this.getPrevious = function() {
    var node = this.getRowNode().previousSibling;
    while (node && node.nodeType == 1) {
      if (!OMgr.getAttribute(node,"mo:template")) {
        var recordNode = OMgr.findChildNode(node,null,"mo:type","ProcessRecord");
        if (recordNode) {
          return OMgr.getObject(recordNode);
        }
      }
      node = node.previousSibling;
    }
    return null;
  };
  this.getNext = function() {
    var node = this.getRowNode().nextSibling;
    while (node && node.nodeType == 1) {
      if (!OMgr.getAttribute(node,"mo:template")) {
        var recordNode = OMgr.findChildNode(node,null,"mo:type","ProcessRecord");
        if (recordNode) {
          return OMgr.getObject(recordNode);
        }
      }
      node = node.nextSibling;
    }
    return null;
  };
  this.getRecordIndex = function() {
    var x = 0;
    var rowNode = this.getRowNode();
    var parentNode = rowNode.parentNode;
    for (var i = 0; i < parentNode.childNodes.length; i++) {
      var node = parentNode.childNodes[i];
      if (node.nodeType == 1 && !OMgr.getAttribute(node,"mo:template")) {
        if (OMgr.findChildNode(node,null,"mo:type","ProcessRecord")) {
          x++;
          if (rowNode == node) return x;
        }
      }
    }
    return -1;
  };
  this._setSelectedStatus = function(checked) {
    var me = this.getModifiedElement();
    if (!me) return;
    me.value = checked + "|" + me.value.after("|");
  };
  this._checkRecord = function(checked, color) {
    if (checked) {
      this.node.style.backgroundColor = color || this.getBlock().props.selectionColor;
    } else {
      this.node.style.backgroundColor = "";
    }
    var recstat = this.getRecordStatus();
    if (recstat) {
      recstat.isSelected = checked;
      recstat.save();
    }
  };
  this.selectRecord = function(checked, color) {
    this.checkRecord(checked,color);
  };
  this.checkRecord = function(checked, color) {
    var e = this.getSelectionElement();
    if (e && e.disabled != true) {
      e.checked = checked;
      this._checkRecord(checked,color);
    }
  };
  this.remove = function() {
    var node = this.getRowNode();
    node.parentNode.removeChild(node);
  };
  this.moveTop = function() {
    var parentNode = this.getRowNode().parentNode;
    for (var i = 0; i < parentNode.childNodes.length; i++) {
      var node = parentNode.childNodes[i];
      if (node.nodeType == 1) {
        var recordNode = OMgr.findChildNode(node,null,"mo:type","ProcessRecord");
        if (recordNode) {
          parentNode.insertBefore(parentNode.removeChild(this.getRowNode()),node);
          return this;
        }
      }
    }
  };
  this.moveUp = function() {
    var node = this.getBlock().getRowNode();
    var rec = this.getPrevious();
    if (rec) {
      var pnode = node.parentNode;
      pnode.insertBefore(pnode.removeChild(node),rec.getRowNode());
      return this;
    }
  };
  this.moveDown = function() {
    var node = this.getRowNode();
    var rec = this.getNext();
    if (rec) {
      rec = rec.getNext();
      var pnode = node.parentNode;
      if (rec) {
        pnode.insertBefore(pnode.removeChild(node),rec.getRowNode());
      } else {
        pnode.appendChild(pnode.removeChild(node));
      }
      return this;
    }
  };
  this.moveBottom = function() {
    var parentNode = this.getRowNode().parentNode;
    parentNode.appendChild(parentNode.removeChild(this.getRowNode()));
    return this;
  };
  this.setVisible = function(value) {
    var rowNode = this.getRowNode();
    if (rowNode) rowNode.style.display = value == true ? "block" : "none";
  };
  this.isVisible = function(){
    var rowNode = this.getRowNode();
    return rowNode && rowNode.style.display != "none";
  };
  this.clone = function() {
    var rowNode = this.getRowNode();
    var nextRecord = this.getNext();
    var newNode = null;
    if (nextRecord) {
      newNode = rowNode.parentNode.insertBefore(rowNode.cloneNode(true),nextRecord.getRowNode());
    } else {
      newNode = rowNode.parentNode.appendChild(rowNode.cloneNode(true));
    }
    if (newNode) {
      var recordNode = OMgr.findChildNode(newNode,null,"mo:type","ProcessRecord");
      if (recordNode) {
        var newRecord = OMgr.getObject(recordNode);
        this.cloneValues(this,newRecord);
        return newRecord;
      }
    }
  };
  this.cloneValues = function(r1, r2) {
    var fields = r1.getFields();
    for (var i = 0; i < fields.length; i++) {
      var f = fields[i];
      if (f.needsValueCloning) {
        r2.getField(f.name).setValue( f.getValue() );
      }
    }
  };
  this.setModified = function(fieldName,modified)  {
       if (modified == false) {
               this.setUnModified(fieldName);
               return;
       }
    var recstat = this.getRecordStatus();
    if (recstat) {
      recstat.addModifiedField(fieldName);
      recstat.save();
    }
  };
  this.setUnModified = function(fieldName) {
    var recstat = this.getRecordStatus();
    if (recstat) {
      if (fieldName) recstat.removeModifiedField(fieldName);
      else recstat.setUnModified();
      recstat.save();
    }
  };
  this.clear = function() {
    var fields = this.getFields();
    for (var i = 0; i < fields.length; i++) {
      var f = fields[i];
      if (f.clear) f.clear();
      if (f.isModified()) this.setModified(f.name);
      else this.setUnModified(f.name);
    }
    return this;
  };
  this.validate = function(acc) {
    var fields = this.getFields();
    for (var i = 0; i < fields.length; i++) {
      var f = fields[i];
      if (!acc || acc.validate) {
        if (f.validate) {
          if (f.validate(acc) == false) return false;
        }
      }
      if (acc && (acc.forAjax || acc.forSubmit)) {
       f.setSubmitPrefix(this.block.prefix);
               if (acc.forAjax) f.appendRequestParams(acc);
      }
    }
    var rse = this.block.isInnerPB || (acc && (acc.forAjax || acc.forSubmit)) ? this.getRecordStatusElement() : null;
    if (acc && this.block.isInnerPB) {
      var recstat = new RecordStatus(rse);
      if (recstat) {
        recstat.parentRecNum = acc.parentRecNum.peek(1);
        recstat.save();
      }
    }
    if (rse && acc && (acc.forAjax || acc.forSubmit)) {
       this.block.setStatusFieldName(rse);
       if (acc.forAjax) acc.add(rse.name,rse.value);
    }
    if (this.block.hasInnerPB()) {
      var innerBlocks = this.getInnerBlocks();
      if (innerBlocks) {
             for (var i = 0; i < innerBlocks.length; i++) {
               var b = innerBlocks[i];
               if (b.validate(acc,true) == false) return false;
             }
      }
    }
    return true;
  };
  this.getInnerBlocks = function() {
    var blocks = new Array();
    var b = OMgr.findChildObject(this.node,null,"mo:type","ProcessBlock");
    if (b == null) return null;
    blocks[0] = b;
    return blocks;
  };
  this.getRowNode = function() {
    return this.node.parentNode.parentNode;
  };
};
function ProcessField(node) {
  this.props = null;
  this.base = MoreMotionObject;
  this.base(node);
  this.isProcessField = true;
  this.elm = this.node;
  this.needsValueCloning = null;
  this.setValue = function(value) {
    this.node.value = value;
  };
  this.getValue = function() {
    return this.node.value;
  };
  this.clear = function() {
    if (this.node) {
      if (this.node.checked) {
        this.node.checked = false;
      } else {
        this.node.value = "";
      }
    }
  };
  this.setModified = function() {
    var r = this.getRecord();
    if (r) r.setModified(this.name,this.getValue() != this.getIValue());
  };
  this.isModified = function() {
    return this.getValue() == this.getIValue();
  };
  this.getElement = function() {
    return this.node;
  };
  this.getRecord = function() {
    return PMgr.getEnclosingRecord(this.node);
  };
  this.valHandler = function() {
    return this.props.valHandler || this.props.customValFunction;
  };
  this.validate = function() {
    var elm = this.node;
    if (this.boolProp("nonBlank") && this.checkValueIsAvailable(elm) == false) return false;
    if (this.props.maxLength && this.checkMaxLength(elm) == false) return false;
    if (this.props.isNumber && this.checkValueIsNumber(elm) == false) return false;
    if (this.props.validValues && this.checkHasValidValue(elm) == false) return false;
    if (this.valHandler() && this.runValidationHandler() == false) return false;
  };
  this.setSubmitPrefix = function(prefix) {
       if (this.selm) this.selm.name = prefix + this.name;
       else if (this.elm) this.elm.name = prefix + this.name;
  };
  this.appendRequestParams = function(acc) {
    if (this.selm) acc.add(this.selm.name,this.selm.value);
    else if (this.elm) acc.add(this.elm.name,this.elm.value);
  };
  this.focusTab = function() {
    try {
      TabMgr.focusEnclosingTab(this.node);
    } catch(e) {}
  };
  this.notify = function(elm, msgCode, msgArg1, msgArg2, msgArg3) {
    var ex = new Exception(msgCode, msgArg1, msgArg2, msgArg3);
    ex.elementToFocus = elm;
    ex.object = this;
    if (this.props.valErrorHandler) {
      var handler = new ErrorHandler(this.props.valErrorHandler,"valErrorHandler");
      try {
        handler.run(ex);
        return true;
      } catch (e) {
        if (!e.alert) {alert(e.message);}
      }
    }
    ex.alert();
    if (this.props.maxLength && elm.createTextRange) {
      var maxLength = this.props.maxLength * 1;
      var range = elm.createTextRange();
      range.moveStart("character", maxLength);
      range.moveEnd("character", elm.value.length + 1);
      range.select();
    } else if (maxLength && elm.setSelectionRange) {
      elm.setSelectionRange(maxLength, elm.value.length);
    } else {
      if (elm.select) elm.select();
    }
    return false;
  };
  this.runValidationHandler = function() {
  	var vhandler = this.valHandler();
    if (vhandler) {
      var handler = new EventHandler(vhandler,"valHandler");
      return handler.run(this);
    }
    return true;
  };
  this.checkValueIsAvailable = function(elmToValidate,elmToFocus) {
    var elm = elmToValidate || this.elm;
    if (elm.value != "") return true;
    if (this.notify(elmToFocus||elm, "CANNOT_BE_BLANK") == false) return false;
  };
  this.checkValueIsNumber = function(elmToValidate,elmToFocus) {
    var elm = elmToValidate || this.elm;
    if (elm.value == "") return true;
    if (!isNaN(elm.value)) return true;
    if (this.notify(elmToFocus||elm, "MUST_BE_NUMBER") == false) return false;
  };
  this.checkHasValidValue = function(elmToValidate,elmToFocus) {
    var elm = elmToValidate || this.elm;
    if (elm.value == "") return true;
    var vvals = this.props.validValues.split(";");
    var v = parseFloat(elm.value,10);
    for (var i = 0; i < vvals.length; i++) {
      var val = vvals[i];
        if (val.indexOf(":") > -1) {
        var ft = val.split(":");
        if (ft.length > 1) {
          var v1 = parseFloat(ft[0],10);
          var v2 = parseFloat(ft[1],10);
          if ( v >= v1 && v <= v2 ) {
            return true;
          }
        }
      } else {
        if (val == elm.value) {
          return true;
        }
      }
    }
    if (this.notify(elmToFocus||elm, "INVALID_VALUE", vvals) == false) return false;
  };
  this.runHandler = function(handlerPropName, obj) {
    var handlerName = this.props[handlerPropName];
    if (handlerName) {
      var handler = new EventHandler(handlerName, handlerPropName);
      return handler.run(obj || this);
    }
  };
};
function ProcessCommand(node) {
  this.props = null;
  this.base = MoreMotionObject;
  this.base(node);
  this.isProcessCommand = true;
};
function EditBox(node) {
  this.base = ProcessField;
  this.base(node);
  this.isEditBox = true;
};
function EditArea(node) {
  this.base = ProcessField;
  this.base(node);
  this.isEditArea = true;
  this.checkMaxLength = function(elmToValidate,elmToFocus) {
    var elm = elmToValidate || this.elm;
    if (elm.value == "") return true;
    var maxLength = this.props.maxLength * 1;
    if (elm.value.length <= maxLength) return true;
    if (this.notify(elmToFocus||elm, "MAX_LENGTH_EXCEEDED", maxLength) == false) return false;
  };
};
function HiddenBox(node) {
  this.base = ProcessField;
  this.base(node);
  this.isHiddenBox = true;
  this.validate = function() {};
};
function CheckBox(node) {
  this.base = ProcessField;
  this.base(node);
  this.isCheckBox = true;
  this.validate = function(index) {};
  this.setValue = function(value) {
    if (value.toBool) value = value.toBool();
    this.node.checked = value == true;
  };
  this.setRecordNumber = function(recnum) {
    this.elm.value = recnum;
  };
  this.getValue = function() {
    return "" + this.node.checked;
  };
  this.isModified = function() {
    return this.getIValue() == this.checked + "";
  };
  this.appendRequestParams = function(acc) {
       if (this.elm.checked) {
      acc.add(this.elm.name,this.elm.value);
       }
  };
};
function ComboBox(node) {
  this.base = ProcessField;
  this.base(node);
  this.isComboBox = true;
  this.needsValueCloning = true;
  this.init = function() {
    var iValue = this.getIValue();
    if (iValue) {
      PMgr.setInitialOption(this.node, iValue);
    }
  };
};
function ListBox(node) {
  this.base = ProcessField;
  this.base(node);
  this.isListBox = true;
  this.needsValueCloning = true;
  this.init = function() {
    var iValue = this.getIValue();
    if (iValue) {
      PMgr.setInitialOption(this.node, iValue);
    }
  }
};
function OptionGroup(node) {
  this.base = ProcessField;
  this.base(node);
  this.isOptionGroup = true;
  this.validate = function(index) {};
};
function TextBox(node) {
  this.base = ProcessField;
  this.base(node);
  this.base2 = TextNode;
  this.base2(node);
  this.isTextBox = true;
  this.ajaxRefreshHandler = function(rec,nodeName,attr) {
    if (!nodeName) nodeName = this.name;
    if (!attr) attr = "value";
    if (attr == "value") this.setValue("");
    else if (attr == "href") this.setHref("");
    if (rec) {
      if (!rec.owner.hasField(nodeName)) {
        throw new Exception("RESPONSE_FIELD_MISSING",nodeName);
      }
      if (attr == "value") this._setValue( rec.get(nodeName) );
      else if (attr == "href") this.setHref( rec.get(nodeName) );
    }
  };
};

