var MONICONFIG2TREEDATA_XML_INDENT = '';
var MONICONFIG2TREEDATA_XML_ATTR_PREFIX = 'xml_';
/**
 * If obj.nodeName exists, checks that it matches node.nodeName.
 * @return false nodeName does not match.
 */
function __moniconfig2treedata_addXmlNodeNameAndAttributes(obj, node) {
  var i;
  var attr;
  if (obj.nodeName) {
    if (obj.nodeName != node.nodeName) {
      return false;
    }
  } else {
    obj.nodeName = node.nodeName;
  }
  for (i = 0; i < node.attributes.length; i++) {
    attr = node.attributes[i];
    eval('obj.' + MONICONFIG2TREEDATA_XML_ATTR_PREFIX + attr.name + '=attr.value');
  }
  return true;
}

function __moniconfig2treedata_deleteXmlAttributes(obj) {
  for (p in obj) {
    if (p.startsWith(MONICONFIG2TREEDATA_XML_ATTR_PREFIX)) {
      eval('delete obj.' + p);
    }
  }
}

/**
 * Processes only attributes whose name starts with
 * MONICONFIG2TREEDATA_XML_ATTR_PREFIX.
 */
function __moniconfig2treedata_toXmlNodeOpen(obj, indent) {
  var attr;
  var res = indent + '<' + obj.nodeName;
  for (a in obj) {
    if (a.startsWith(MONICONFIG2TREEDATA_XML_ATTR_PREFIX)) {
      res += ' ' + a.substring(MONICONFIG2TREEDATA_XML_ATTR_PREFIX.length) + '="' + eval('obj.' + a) + '"';
    }
  }
  res += '>\n';
  return res;
}

function __moniconfig2treedata_toXmlNodeClose(obj, indent) {
  var res = indent + '</' + obj.nodeName + '>\n';
  return res;
}

function __moniconfig2treedata_toXmlNodeOpenAndClose(obj, indent) {
  var attr;
  var res = indent + '<' + obj.nodeName;
  for (a in obj) {
    if (a.startsWith(MONICONFIG2TREEDATA_XML_ATTR_PREFIX)) {
      res += ' ' + a.substring(MONICONFIG2TREEDATA_XML_ATTR_PREFIX.length) + '="' + eval('obj.' + a) + '"';
    }
  }
  res += '/>\n';
  return res;
}

/**
 * @param toXmlFunc function to convert children to xml string.
 */
function __moniconfig2treedata_toXmlChildren(arr, indent, toXmlFunc, descendantsNodeNames) {
  var i;
  var res = '';
  if (descendantsNodeNames) {
    res = indent;
    for (i = 0; i < descendantsNodeNames.length; i++) {
      res += '<' + descendantsNodeNames[i] + '>\n';
    }
  }
  for (i = 0; i < arr.length; i++) {
    res += toXmlFunc(arr[i], indent);
  }
  if (descendantsNodeNames) {
    i = descendantsNodeNames.length;
    while (i) {
      i--;
      res += indent + '</' + descendantsNodeNames[i] + '>\n';
    }
  }
  return res;
}

/**
 * Returns an array of objects representing current node's descendants. The
 * current node is that pointed by the treewalker. The descendants to process
 * are selected with traverseChildNames.
 * The object representing the descendant must define:
 * -a constructor with no parameters
 * -a method parse(treewalker) where treewalker points to the node to parse;
 *  returns false on error
 * If traverseChildNames is defined, then descendants whose name is not in this
 * array are ignored.
 * @param childParseFunc xml children nodes parse function. Receives a
 * treewalker and returns the parsed object or null on error.
 * @traverseChildNames null or undefined to process all children; otherwise,
 * an array containing descendants' node names containing the nodes to process
 * (only one node with names in this array allowed).
 * @return array of elements representing node's descendants (empty array if
 * no child processed) or null on error.
 */
function __moniconfig2treedata_parseDescendants(treewalker, childParseFunc, traverseChildNames) {
  var obj;
  var node;
  var parentNode = treewalker.currentNode;
  var res = new Array();
  if (traverseChildNames) {
    var i = 0;
    while (i < traverseChildNames.length) {
      node = treewalker.firstChild();
      while (node) {
        if (node.nodeName == traverseChildNames[i]) {
          i++;
          break;
        }
        node = treewalker.nextSibling();
      }
      if (!node) {
        break;
      }
    }
    if (!node) {
      return res;
    }
  }
  if (!treewalker.firstChild()) {
    return res;
  }
  do {
    obj = childParseFunc(treewalker);
    if (null == obj) {
      return null;
    }
    res.push(obj);
  } while (treewalker.nextSibling());
  treewalker.currentNode = parentNode;
  return res;
}

function __moniconfig2treedata_clearMeasure(monimeasure) {
  //Each magnitude has a specific nodeName
  monimeasure.checkAlarm = false;
  monimeasure.checkPrealarm = false;
  monimeasure.name = '----';
}
function __moniconfig2treedata_parseMeasure(treewalker) {
  var res = new Object();
  var node = treewalker.currentNode;
  if (!node) {
    return null;
  }
  __moniconfig2treedata_clearMeasure(res);
  if (!__moniconfig2treedata_addXmlNodeNameAndAttributes(res, node)) {
    return null;
  }
  res.name = node.nodeName;
  res.checkAlarm = res.xml_alarm ? true : false;
  res.checkPrealarm = res.xml_prealarm ? true : false;
  var children = __moniconfig2treedata_parseDescendants(treewalker, __moniconfig2treedata_parseMeasure);
  if (!children) {
    return null;
  }
  if (0 != children.length) {
    res.children = children;
  }
  return res;
}
function __moniconfig2treedata_toXmlMeasures(monimeasure, indent) {
  var res;
  if (!monimeasure.children) {
    res = __moniconfig2treedata_toXmlNodeOpenAndClose(monimeasure, indent);
  } else {
    res = __moniconfig2treedata_toXmlNodeOpen(monimeasure, indent);
    res += __moniconfig2treedata_toXmlChildren(
      monimeasure.children,
      indent + MONICONFIG2TREEDATA_XML_INDENT,
      __moniconfig2treedata_toXmlMeasures,
      monimeasure.descendantsNodeNames,
    );
    res += __moniconfig2treedata_toXmlNodeClose(monimeasure, indent);
  }
  return res;
}

function __moniconfig2treedata_clearChannel(monichannel) {
  monichannel.nodeName = 'CHANNEL';
  monichannel.descendantsNodeNames = ['MEASURES'];
  monichannel.children = new Array();
}
function __moniconfig2treedata_parseChannel(treewalker) {
  var res = new Object();
  var node = treewalker.currentNode;
  if (!node) {
    return false;
  }
  __moniconfig2treedata_clearChannel(res);
  if (!__moniconfig2treedata_addXmlNodeNameAndAttributes(res, node)) {
    return null;
  }
  var children = __moniconfig2treedata_parseDescendants(treewalker, __moniconfig2treedata_parseMeasure, res.descendantsNodeNames);
  if (!children) {
    return false;
  }
  if (0 != children.length) {
    res.children = children;
  }
  return res;
}
function __moniconfig2treedata_toXmlChannel(monichannel, indent) {
  var res = __moniconfig2treedata_toXmlNodeOpen(monichannel, indent);
  if (monichannel.children) {
    res += __moniconfig2treedata_toXmlChildren(
      monichannel.children,
      indent + MONICONFIG2TREEDATA_XML_INDENT,
      __moniconfig2treedata_toXmlMeasures,
      monichannel.descendantsNodeNames,
    );
  }
  res += __moniconfig2treedata_toXmlNodeClose(monichannel, indent);
  return res;
}

function moniconfig2treedata_clear(moniconfig) {
  __moniconfig2treedata_deleteXmlAttributes(moniconfig);
  moniconfig.nodeName = 'MONI_CONFIG';
  moniconfig.descendantsNodeNames = ['CHANNELS'];
  moniconfig.treeData = new Array();
}
/**
 * @return the parsed object or null on error.
 */
function moniconfig2treedata_parse(xmldocument) {
  var node;
  var res = new Object();
  moniconfig2treedata_clear(res);
  var collection = xmldocument.getElementsByTagName(res.nodeName);
  if (1 != collection.length) {
    return null;
  }
  node = collection[0];
  if (!__moniconfig2treedata_addXmlNodeNameAndAttributes(res, node)) {
    return null;
  }
  var whatToShow = 1 << (Node.ELEMENT_NODE - 1);
  var treewalker = xmldocument.createTreeWalker(node, whatToShow, null);
  var treedata = __moniconfig2treedata_parseDescendants(treewalker, __moniconfig2treedata_parseChannel, res.descendantsNodeNames);
  if (!treedata) {
    return null;
  }
  if (0 != treedata.length) {
    res.treeData = treedata;
  }
  return res;
}

function moniconfig2treedata_toXml(moniconfig) {
  var res = '<?xml version="1.0" encoding="utf-8"?>\n';
  res += __moniconfig2treedata_toXmlNodeOpen(moniconfig, '');
  res += __moniconfig2treedata_toXmlChildren(
    moniconfig.treeData,
    MONICONFIG2TREEDATA_XML_INDENT,
    __moniconfig2treedata_toXmlChannel,
    moniconfig.descendantsNodeNames,
  );
  res += __moniconfig2treedata_toXmlNodeClose(moniconfig, '');
  return res;
}
