/*
  Utility functions for the general element handling and the Document Object Model
*/

require("/o2www/js/util.js");

// returns absolute left and top coordinates for a given element
function elementGeometry(elm) {
  if( !elm ) return null;
  var x=0, y=0, width=elm.offsetWidth, height=elm.offsetHeight;
  while( elm.offsetParent ) {
    x += elm.offsetLeft;
    y += elm.offsetTop;
    elm = elm.offsetParent;
  }
  return {left:x, top:y, width:width, height:height, right:x+width, bottom:y+height};
}

// returns coordinates of a window (frame or iframe) relative to the browser top left corner (currently mozilla only)
function windowOffset(win) {
  var x=0, y=0;
  while( win.parent && win!=win.top ) {
    x += win.frameElement.offsetLeft - win.pageXOffset;
    y += win.frameElement.offsetTop  - win.pageYOffset;;
    win = win.parent;
  }
  return {left:x, top:y};
}

function o2GetComputedStyle(elm, attr) {
  if (attr === "width") {
    if (typeof(elm.offsetWidth) !== "undefined") {
      return elm.offsetWidth;
    }
  }
  else if (attr === "height") {
    if (typeof(elm.offsetHeight) !== "undefined") {
      return elm.offsetHeight;
    }
  }
  else if (attr === "left" || attr === "top") {
    if (elm.offsetParent) {
      var x = 0, y = 0;
      var tmpElm = elm;
      while (tmpElm.offsetParent) {
        x += tmpElm.offsetLeft;
        y += tmpElm.offsetTop;
        tmpElm = tmpElm.offsetParent;
      }
      return attr === "left" ? x : y;
    }
  }
  else if (attr === "bottom") {
    return o2GetComputedStyle(elm, "top") + o2GetComputedStyle(elm, "height");
  }
  else if (attr === "right") {
    return o2GetComputedStyle(elm, "left") + o2GetComputedStyle(elm, "width");
  }
  if (window.getComputedStyle) {
    return window.getComputedStyle(elm, null)[attr];
  }
  if (elm.currentStyle) {
    return elm.currentStyle[attr];
  }
  alert("Couldn't get computed style for " + attr);
}

/* Equivalent to the DOM method insertBefore */
function insertAfter(newElement, targetElement) {
  if (!targetElement) {
    return alert("insertAfter: No target element given");
  }
  var parent = targetElement.parentNode;
  if (parent.lastChild == targetElement) {
    parent.appendChild(newElement);
  }
  else {
    parent.insertBefore(newElement, targetElement.nextSibling);
  }
}

function replaceNode(oldNode, newNode) {
  var nextNode = getNextElement(oldNode, true);
  if (nextNode) {
    return oldNode.parentNode.insertBefore(newNode, nextNode);
  }
  var previousNode = getPreviousElement(oldNode, true);
  if (previousNode) {
    return insertAfter(newNode, previousNode);
  }
  var parent = oldNode.parentNode;
  parent.removeChild(oldNode);
  parent.appendChild(newNode);
}

/* Searches siblings to the right for the first node of type element (nodeType == 1) - and returns it */
function getNextElement(node, textNodeIsOkToo) {
  if (!node.nextSibling) {
    return false;
  }
  node = node.nextSibling;
  if (node.nodeType == 1  ||  (textNodeIsOkToo && node.nodeType == 3)) {
    return node;
  }
  return getNextElement(node);
}

/* Searches siblings to the left for the first node of type element (nodeType == 1) - and returns it */
function getPreviousElement(node, textNodeIsOkToo) {
  if (!node.previousSibling) {
    return false;
  }
  node = node.previousSibling;
  if (node.nodeType == 1  ||  (textNodeIsOkToo && node.nodeType == 3)) {
    return node;
  }
  return getPreviousElement(node);
}

/* canBeSelf == doesn't have to be ancestor
   tagNames can also be just one tagName as a string */
function getClosestAncestorByTagName(elm, tagNames, canBeSelf) {
  if (typeof(tagNames)  === "string") {
    tagNames = [ tagNames ];
  }
  if (typeof(canBeSelf) === "undefined") {
    canBeSelf = true; // Default is true
  }
  if (canBeSelf  &&  isInArray(elm.tagName, tagNames, true)) {
    return elm;
  }
  while (elm.parentNode) {
    elm = elm.parentNode;
    if (!elm || !elm.tagName) {
      return null;
    }
    if (isInArray(elm.tagName, tagNames, true)) {
      return elm;
    }
  }
  return null;
}
