/*
    Logger: class for logging JavaScripts
    Author: Theo M. Gerrits (tmg)

    Dependencies: none

    JavaScript1.2

    Copyright (C) 2005 Ontwerpfontein
*/


// Constructor
function Logger(w, h, l)
{
    this.level = l;
    this.consoleWindow = null;
    this.indentLevel = 0;

    if (this.level > 0)
    {
        this.createConsoleWindow(w, h);
        this.clear();
    }
}


// Logger constants
Logger.prototype.DEBUG = 40;
Logger.prototype.INFO = 30;
Logger.prototype.WARN = 20;
Logger.prototype.ERROR = 10;
Logger.prototype.indentChars = "--";
Logger.prototype.DEBUGprefix = "DEBUG: ";
Logger.prototype.INFOprefix = "INFO: ";
Logger.prototype.WARNprefix = "WARNING: ";
Logger.prototype.ERRORprefix = "ERROR: ";


// Description     : build a string with the correct number of indent characters.
// Parameters      : none
// Returns         : the indent string
Logger.prototype.indent = function ()
{
    var s = "";
    for (var i = 0; i < this.indentLevel; i++)
        s += this.indentChars;

    return s;
}

// Description     : create the standard console output window.
// Parameters      : initial width and height of the console
// Returns         : void
Logger.prototype.createConsoleWindow = function (w, h)
{
    if (!this.consoleWindow || this.consoleWindow.closed)
        this.consoleWindow = window.open("", "ConsoleWindow", "width=" + w + ",height=" + h + ",status=no,toolbar=no,scrollbars=yes");
}

// Description     : clear the console.
// Parameters      : none
// Returns         : void
Logger.prototype.clear = function ()
{
    if (this.level > 0)
    {
        this.consoleWindow.document.close();
        this.consoleWindow.document.open();
        this.consoleWindow.document.write("<html>");
        this.consoleWindow.document.write("<head>");
        this.consoleWindow.document.write("<title>Log Console</title>");
        this.consoleWindow.document.write("</head>");
        this.consoleWindow.document.write("<body>");
        this.consoleWindow.document.body.style.fontFamily = "Arial, Helvetica, sans-serif";
        this.consoleWindow.document.body.style.fontSize = "10pt";
    }
}

// Description     : encodes special characters for HTML output.
// Parameters      : s: string to encode. If s is not a string, it will be converted to one.
// Returns         : the encoded string
Logger.prototype.htmlEncode = function (s)
{
    if (s)
    {
        s = "" + s;
        s = s.replace(/</g, "&lt;");
        s = s.replace(/>/g, "&gt;");
        s = s.replace(/\"/g, "&quot;");
        s = s.replace(/\n/g, "<br>");
        return s;
    }
    else
        return "undefined";
}

// Description     : log 1 line of information to the console.
// Parameters      : label: (optional) text to output
//                   varName: (optional) name of variable to output, this works only for window global variables
//                   style: (optional) style sheet definition
// Returns         : the logged message
Logger.prototype.log = function (label, varName, style)
{
    if (this.level > 0)
    {
        var message;

        // test explicitly for null, since the empty string evaluates as false
        if (label != null || varName != null)
            message = "- ";
        else
            message = "...undefined...";
        if (label)
            message += this.htmlEncode(label);
        if (varName)
        {
            if (label)
                message += ": ";
            if (typeof varName != "string")
            {
                alert("varName should be a string!");
            }
            else
            {
                var varValue = eval("this.consoleWindow.opener." + varName);
                message += varName + ": " + this.htmlEncode(varValue);
            }
        }

        if (style)
            this.consoleWindow.document.write("<span style=\"" + style + "\">" + message + "</span>");
        else
            this.consoleWindow.document.write(message);
        this.consoleWindow.document.write("<br>");

        return message;
    }
}

// log at level DEBUG
Logger.prototype.debug = function (label, varName)
{
    if (this.level >= this.DEBUG)
        return this.log(this.DEBUGprefix + label, varName);
}

// log at level INFO
Logger.prototype.info = function (label, varName)
{
    if (this.level >= this.INFO)
        return this.log(this.INFOprefix + label, varName);
}

// log a note at level INFO
Logger.prototype.note = function (label, varName)
{
    if (this.level >= this.INFO)
        return this.log(this.INFOprefix + label, varName, "font-weight:bold; color:Blue;");
}

// log at level WARN
Logger.prototype.warn = function (label, varName)
{
    if (this.level >= this.WARN)
        return this.log(this.WARNprefix + label, varName);
}

// log at level ERROR
Logger.prototype.error = function (label, varName)
{
    if (this.level >= this.ERROR)
        return this.log(this.ERRORprefix + label, varName, "font-weight:bold; color:Orange;");
}


// Description     : output a coordinate to the console.
// Parameters      : the coordinate x and y values
// Returns         : void
Logger.prototype.showPos = function (x, y)
{
    if (this.level > 0)
        this.info("(" + x + "," + y + ")");
}

// Description     : output a variable's contents completely to the console.
// Parameters      : label: a text label for the output
//                   v: the variable to output
//                   maxDepth: the number of inner object levels to show
// Returns         : void
// Remark          : don't dump window or document objects, since these contain self-references
Logger.prototype.dump = function (label, v, maxDepth)
{
    if (this.level > 0 && (maxDepth == null || maxDepth >= 0))
    {
        switch (typeof v)
        {
            case "function":
                var functionPrototype = v.toString();
                // NB: the string version of a function starts with a newline!
                functionPrototype = functionPrototype.substr(0, functionPrototype.indexOf("\n", 1));
                this.info(this.indent() + label + ": " + functionPrototype + " (" + typeof v + ")");
                break;
            case "object":
                label = this.indent() + label + " (" + typeof v + "):";
                if (!v)
                    label += " null";
                if (this.indentLevel == 0)
                    this.note(label);
                else
                    this.info(label);
                if (v && (maxDepth == null || maxDepth > 0))
                {
                    this.indentLevel++;
                    for (var prop in v)
                    {
                        // try block is needed since some properties do exist that cannot be accessed
                        // for example Image.textContent (!)
                        try
                        {
                            this.dump(prop, v[prop], (maxDepth != null) ? (maxDepth - 1) : null);
                        }
                        catch (e)
                        {
                            LOG.error(e);
                            LOG.error("when trying to dump: " + prop);
                        }
                    }
                    this.indentLevel--;
                }
                break;
            default:
                this.info(this.indent() + label + ": " + v + " (" + typeof v + ")");
                break;
        }
    }
}

// Description     : output an object's supported methods to the console.
// Parameters      : label: a text label for the output
//                   o: object
// Returns         : void
Logger.prototype.dumpMethods = function (label, o)
{
    if (this.level > 0)
    {
        label = this.indent() + label + ":";
        if (!o)
            label += " null";
        this.info(label);
        this.indentLevel++;
        for (var item in o)
        {
            if ((typeof (o[item])) == "function")
                this.dump(item, o[item]);
        }
        this.indentLevel--;
    }
}

// Switch logging on by setting the log level (3rd param) to a positive integer value
LOG = new Logger(800, 1000, 0);
