xb = {};

/* Dumps an object in tree format, recurse specifiec the the number of objects
 * to recurse, compress is a boolean that can uncompress (true) the output
 * format, and level is the number of levels to intitialy indent (only useful
 * internally.)  A sample dumpObject (o, 1) is shown below.
 *
 * + parent (object)
 * + users (object)
 * | + jsbot (object)
 * | + mrjs (object)
 * | + nakkezzzz (object)
 * | *
 * + bans (object)
 * | *
 * + topic (string) 'ircclient.js:59: nothing is not defined'
 * + getUsersLength (function) 9 lines
 * *
 */
xb.dumpObject =
function dumpObject (o, recurse, compress, level)
{
    if (typeof o == "string" || o instanceof String)
    {
        if (o.length > 2000)
        {
            return o.substr(0, 500) + "''... " + o.length +
                " chars";
        }

        return o;
    }

    var s = "";
    var pfx = "";

    if (typeof recurse == "undefined")
        recurse = 0;
    if (typeof level == "undefined")
        level = 0;
    if (typeof compress == "undefined")
        compress = true;

    for (var i = 0; i < level; i++)
        pfx += (compress) ? "| " : "|  ";

    var tee = (compress) ? "+ " : "+- ";

    for (i in o)
    {
        var t;
        try
        {
            t = typeof o[i];

            switch (t)
            {
                case "function":
                    var sfunc = String(o[i]).split("\n");
                    if (sfunc[2] == "    [native code]")
                        sfunc = "[native code]";
                    else
                        sfunc = sfunc.length + " lines";
                    s += pfx + tee + i + " (function) " + sfunc + "\n";
                    break;

                case "object":
                    s += pfx + tee + i + " (object) " + o[i] + "\n";
                    if (!compress)
                        s += pfx + "|\n";
                    if ((i != "parent") && (recurse))
                        s += xb.dumpObject(o[i], recurse - 1,
                                           compress, level + 1);
                    break;

                case "string":
                    if (o[i].length > 2000)
                        s += pfx + tee + i + " (" + t + ") ``" +
                            o[i].substr(0, 500) + "''... " + o[i].length +
                            " chars\n";
                    else
                        s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
                    break;

                default:
                    s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
            }
        }
        catch (ex)
        {
            s += pfx + tee + i + " (exception) " + ex + "\n";
        }

        if (!compress)
            s += pfx + "|\n";

    }

    s += pfx + "*\n";

    return s;

}

/* turn a js date object into a sql date string.  time zones are ignored. */
xb.jsdate2sql =
function jsd2sql(jsdate, secs)
{
    var rv = "";
    var zpad = function(v) { return xb.lpad(v, 2, "0"); };

    rv = jsdate.getFullYear() + "-" +
        zpad(jsdate.getMonth() + 1) + "-" +
        zpad(jsdate.getDate()) + " " +
        zpad(jsdate.getHours()) + ":" +
        zpad(jsdate.getMinutes());

    if (secs)
        rv += ":" + zpad(jsdate.getSeconds());

    return rv;
}

/* left pad a string out to length, using the character ch */
xb.lpad =
function xb_lpad(str, length, ch)
{
    ch = ch || " ";

    if (typeof str != "string")
        str = String(str);

    var curlen = str.length;
    var pad = "";
    for (var i = 0; i < length - curlen; ++i)
        pad += ch;

    return pad + str;
}

// 2008-10-05: Clean out non-document node children.
xb.cleanDom =
function xb_cleandom(n) {

  var x = n.firstChild;

  while (x) {
    //alert("type: " + xb.dumpObject(x));
    if (x.nodeType != 1) {
      var dead = x;
      x = dead.nextSibling;
      n.removeChild(dead);
    } else {
      x = x.nextSibling;
    }
  }
}

// 2008-10-09: Clear all children.
xb.clearDom =
function xb_cleardom(n) {

  var x = n.firstChild;

  while (n.firstChild) {
      n.removeChild(n.lastChild);
  }
}

xb.isArray =
function xb_isArray(obj) {
    return obj.constructor == Array;
}


xb.getPos =
function xb_getPos(o) {
  var pos = {};
  var leftX = 0;
  var leftY = 0;
  if(o.offsetParent) {
    while(o.offsetParent) {
      leftX += o.offsetLeft;
      leftY += o.offsetTop;
      o = o.offsetParent;
    }
  } else if(o.x) {
    leftX += o.x;
    leftY += o.y;
  }
  pos.x = leftX;
  pos.y = leftY;
  return pos;
};


// //-----------------------------------------------------
// getWindowDimensions : function () {
// var out = {};
// if (window.pageXOffset) {
// 	out.scrollX = window.pageXOffset;
// 	out.scrollY = window.pageYOffset;
// } else if (document.documentElement) {
// 	out.scrollX = document.body.scrollLeft + document.documentElement.scrollLeft; 
// 	out.scrollY = document.body.scrollTop + document.documentElement.scrollTop;
// } else if (document.body.scrollLeft >= 0) {
// 	out.scrollX = document.body.scrollLeft;
// 	out.scrollY = document.body.scrollTop;
// }

// if (document.compatMode == "BackCompat") {
//   out.width = document.body.clientWidth;
// 	out.height = document.body.clientHeight;
// } else {
// 	out.width = document.documentElement.clientWidth;
// 	out.height = document.documentElement.clientHeight;
// }
// return out;
// },

xb.getElementFromEvent =
function (evt) {
  if (!evt)
    evt = window.event;
  return ((evt.target) ? evt.target : evt.srcElement);
};


xb.getMousePosFromEvent =
function (evt) {
  if (!evt)
    evt = window.event;

  var pos = {};

  if (evt.pageX) {
    pos.x = evt.pageX;
    pos.y = evt.pageY;
  } else if (evt.clientX) {
    pos.x = evt.clientX + document.body.scrollLeft
    + document.documentElement.scrollLeft;
    pos.y = evt.clientY + document.body.scrollTop
    + document.documentElement.scrollTop;
  }

  return pos;
}
