var api = {
  addEvent: function(obj, type, fn) {
    if (obj.addEventListener) {
      obj.addEventListener(type, fn, false);
    } else if (obj.attachEvent) {
      obj["e"+type+fn] = fn;
      obj[type+fn] = function() { obj["e"+type+fn](window.event); }
      obj.attachEvent("on"+type, obj[type+fn]);
    }
  },
  stopEvent: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },
  testDOM: function() {
    return (document.getElementById ||
            document.getElementsByTagName ||
            document.createElement);
  },
  map: function(fn, elems) {
    for (var i = 0; i < elems.length; i++) {
      fn(elems[i]);
    }
  },
  getElementNodes: function(node) {
    var a = [];
    while (node) {
      if (node.nodeType == 1) {
        a.push(node);
      }
      node = node.nextSibling;
    }
    return a;
  },
  getFirstChild: function(node) {
    return (node.firstChild.nodeType == 1) ?
      node.firstChild :
      api.getNextSibling(node.firstChild);
  },
  getLastChild: function(node) {
    return (node.lastChild.nodeType == 1) ?
      node.lastChild :
      api.getPreviousSibling(node.lastChild);
  },
  getPreviousSibling: function(node) {
    while (node = node.previousSibling) {
      if (node.nodeType == 1) {
        break;
      }
    }
    return node;
  },
  getNextSibling: function(node) {
    while (node = node.nextSibling) {
      if (node.nodeType == 1) {
        break;
      }
    }
    return node;
  },
  countPreviousSiblings: function(node) {
    var i = 0;
    while (node = node.previousSibling) {
      if (node.nodeType == 1) {
        ++i;
      }
    }
    return i;
  },
  getOffset: function(obj) {
    var offset = {x: obj.offsetLeft, y: obj.offsetTop};
    while(obj = obj.offsetParent) {
      offset.x += obj.offsetLeft;
      offset.y += obj.offsetTop;
    }
    return offset;
  },
  removeClassName: function(oldClass, elem) {
    var a = [];
    var classes = elem.className.split(" ");
    for (var i in classes) {
      if (classes[i] != oldClass) {
        a.push(classes[i]);
      }
    }
    elem.className = a.join(" ");
  },
  removeLastClassName: function(elem) {
    var classes = elem.className.split(" ");
    classes.pop();
    return classes.join(" ");
  },
  /*** getElementsByClassName 1.03 | Muffin Research Labs ***/
  getElementsByClassName: function(strClass, strTag, objContElm) {
    strTag = strTag || "*";
    objContElm = objContElm || document;
    var objColl = objContElm.getElementsByTagName(strTag);
    if (!objColl.length && strTag == "*" && objContElm.all) objColl = objContElm.all;
    var arr = new Array();
    var delim = strClass.indexOf("|") != -1  ? "|" : " ";
    var arrClass = strClass.split(delim);
    for (var i = 0, j = objColl.length; i < j; i++) {
      var arrObjClass = objColl[i].className.split(" ");
      if (delim == " " && arrClass.length > arrObjClass.length) continue;
      var c = 0;
      comparisonLoop:
      for (var k = 0, l = arrObjClass.length; k < l; k++) {
        for (var m = 0, n = arrClass.length; m < n; m++) {
          if (arrClass[m] == arrObjClass[k]) c++;
          if (( delim == "|" && c == 1) || (delim == " " && c == arrClass.length)) {
            arr.push(objColl[i]);
            break comparisonLoop;
          }
        }
      }
    }
    return arr;
  },
  getCursorPosition: function(event) {
    event = event || window.event;
    var coords = {x:0, y:0};
    if (event.pageX || event.pageY) {
      coords.x = event.pageX;
      coords.y = event.pageY;
    } else {
      var de = document.documentElement;
      var b = document.body;
      coords.x = event.clientX + (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0);
      coords.y = event.clientY + (de.scrollTop || b.scrollTop) - (de.clientTop || 0);
    }
    return coords;
  },
  getRelatedTarget: function(event, obj) {
    event = event || window.event;
    var relatedTarget = event.relatedTarget || event.toElement;
    while (relatedTarget && relatedTarget != obj) {
      relatedTarget = relatedTarget.parentNode;
    }
    return (relatedTarget == obj);
  }
}
