﻿/*
*	jQuery Debugger
*
*	Copyright (c) 2008 Petr Staníček (pixy@pixy.cz)
*	January 2009
*
*	usage:

var debug = new jQuery.debug( options ); // see var Prefs for options properties
debug.dump(x);

example:

var debug = new jQuery.debug({ posTo: {x:'right',y:'bottom'}, height:'150px',width:'150px' });
var myObj = { 'arr' : [1,2,3], cnt : 3, elm : document.createElement('DIV') };
debug.dump(myObj);	

*/


jQuery.extend({ debug: function(options) {

    // Properties

    var Prefs = jQuery.extend({}, {

        excludeFunctions: true,

        listDOM: null, 		// null | 'all' | 'props-only' | 'fn-only' | [ 'prop1', .. , 'propN' ]

        continuous: true,
        itemDivider: '<br>',
        maxParseDepth: 3,
        spacer: '&nbsp;&nbsp;',

        parent: 'body', 			// jQuery selector like 'body' or '#main-box'

        posTo: { x: 'left', y: 'top' }, // x : left|right, y : top|bottom
        x: '0px',
        y: '0px',
        zIndex: 10000,
        overflow: 'auto',
        width: '150px',
        height: '300px',
        whiteSpace: 'nowrap',
        font: '11px/1.1 monospace',
        padding: '5px',
        background: '#333',
        color: '#6c3',
        labelColor: '#786'

    }, options);


    // Methods

    this.dump = function(x, label) {
        var s = '';
        if (label) s += fLbl(label);
        if (x != undefined) s += formatObj(x);
        this.out(s);
    }

    this.out = function(s) {
        if (!this.Box) this.createBox();
        if (Prefs.continuous) jQuery(this.Box).prepend(s + Prefs.itemDivider);
        else jQuery(this.Box).html(s);
    }

    this.createBox = function() {
        this.Box = document.createElement('DIV');
        jQuery(Prefs.parent).prepend(this.Box);
        jQuery(this.Box).css({
            'position': 'fixed',
            'z-index': Prefs.zIndex,
            'overflow': Prefs.overflow,
            'white-space': Prefs.whiteSpace,
            'width': Prefs.width,
            'height': Prefs.height,
            'font': Prefs.font,
            'padding': Prefs.padding,
            'background': Prefs.background,
            'color': Prefs.color
        }).css(Prefs.posTo.x, Prefs.x).css(Prefs.posTo.y, Prefs.y);
    }

    // Private

    function formatObj(obj) {
        return parse(obj, 1);
    }


    function fArr(arr, lQuo, rQuo, depth) {
        var p = '', br = '<br>';
        for (var i = 0; i < depth; i++) p += Prefs.spacer;
        return lQuo + br + p + arr.join(',' + br + p) + br + p + rQuo;
    }
    function fLbl(s) {
        return '<span style="color:' + Prefs.labelColor + '">' + s + ':</span> '
    }
    function parse(obj, depth, propList) {
        if (obj === null) return '<i>null</i>';
        else if (jQuery.isFunction(obj)) return '<i>Function</i>';
        else switch (typeof obj) {
            case undefined: return '<i>undefined</i>'; break;
            case 'number':
            case 'boolean':
                return obj.toString(); break;
            case 'string':
                return '"' + obj.replace(/"/g, '&quot;') + '"'; break;
            case 'function':
            case 'object':
                var s, oType = 0;
                if (obj.ownerDocument != undefined) {
                    s = '<i>DOM_object</i>';
                    oType = 1;
                }
                else if (obj['jquery'] != undefined) {
                    s = '<i>jQuery object</i>';
                    oType = 2;
                }
                if (oType > 0 && Prefs.listDOM && depth < Prefs.maxParseDepth) {
                    var i, l, k, arr = [];
                    if (typeof Prefs.listDOM == 'object' && Prefs.listDOM.concat != undefined) {
                        for (i = 0, l = Prefs.listDOM.length; i < l; i++) {
                            k = Prefs.listDOM[i];
                            arr.push(fLbl(k) + parse(obj[k], depth + 1));
                        }
                    }
                    else {
                        var isFn, what = 0;
                        if (Prefs.listDOM == 'props-only') what = 1;
                        if (Prefs.listDOM == 'fn-only') what = 2;
                        for (k in obj) {
                            isFn = jQuery.isFunction(obj[k]);
                            if (what == 0 || (what == 1 && !isFn) || (what == 2 && isFn)) arr.push(fLbl(k) + parse(obj[k], depth + 1));
                        }
                    }
                    s += ': ' + fArr(arr, '{', '}', depth);
                }
                if (oType > 0) return s;
                if (depth >= Prefs.maxParseDepth) return '{...}';
                var k, arr = [];
                for (k in obj) if (!Prefs.excludeFn || !jQuery.isFunction(obj[k])) arr.push(fLbl(k) + parse(obj[k], depth + 1));
                return fArr(arr, '{', '}', depth);
                break;
            default:
                return '<i>undefined</i>'; break;
        }
    }


}

});


