/**
 * Rivet Software Inc.
 *
 * @copyright Copyright � 2006-2007 Rivet Software, Inc. All rights reserved.
 *
 */

/**
 * Utility function to emulate the functionality of getElementsByTagName
 *
 * @param {Object} searchClass
 * @param {Object} node
 * @param {Object} tag
 * @return {array}
 */
function getElementsByClassName(searchClass, node, tag) {
    var classElements = new Array();
    if ( node == null )
        node = document;
    if ( tag == null )
        tag = '*';
    var els = node.getElementsByTagName(tag);
    var elsLen = els.length;
    var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
    for (i = 0, j = 0; i < elsLen; i++) {
        if ( pattern.test(els[i].className) ) {
            classElements[j] = els[i];
            j++;
        }
    }

    return classElements;
}

/**
 * HeroDetective
 *
 * �2006 Hero Development
 * Program Design by LCValentine
 * Created:  2007-02-03
 * Created:  2007-02-03
 **/

var inspector = {
    hideNative:true,    
    sorting:'type',
	typeMap:{
		'boolean'  : 'bools',
		'function' : 'funcs',
		'number' : 'numbers',
		'object' : 'objects',
		'string' : 'strings'
	},

	init: function( obj, objDoc ){
		var path = '';

		if( typeof obj != 'object' ){
			switch( typeof obj ){
				case 'string':
					if( obj.substr( 0, 5 ) == '_obj_' ){
						path = obj.substr( 6 );
						obj  = this.obj;
						break;
					}else if( obj.substr( 0, 9 ) == '_lastObj_' ){
						obj  = this.lastObj;
						break;
					}

					if( !confirm( "String: "+obj+"\n\nThe object provided is a string.\nDo you want to inspect the element with this ID if it exists?" ) ){
						return;
					}

					if( objDoc == undefined ){
						obj = this.$( obj, objDoc );
					}else{
						obj = this.$( obj );
					}

					if( obj === false ){
						alert( "Object not found.  Change your command to\n'_inspect( 'id', document );'" );
						return;
					}

					break;
				case 'number':
					alert( "The object provided is the number '" + obj + "'" );
					break;
				default:
					alert( typeof obj );
					return;
			}
		}else if( !obj ){
		    alert( 'empty object' );
		    return;
		}

		if( path != '' ){
			var props = path.split( '.' );

			for( var i = 0; i < props.length; i++ ){
				obj = obj[props[i]];
			}
		}

		if( this.obj ){
			this.lastObj = this.obj;
		}

		this.obj = obj;

		if( objDoc ){
    		this.objDoc = objDoc;
		}

		this.dig();
	},

	dig:function(){
		this.load();

		var obj = this.obj;
		var str = '';

		if( obj ){
    		str += this.getHere();
		}

        if( this.lastObj ){
            str += '<a href="javascript:void(0);" onclick="inspector.init( \'_lastObj_\' );">Back</a>';
        }

		str += "\n"+'<table border="1" cellpadding="1" cellspacing="0">';

		switch( this.sorting ){
			case 'type':
				for( prop in this.typeMap ){
                    if( this[ this.typeMap[prop] ] ){
    				    str += '<tr><td class="th" colspan="2">Items of type <u>'+prop+'</u></td></tr>';
    					str += this.getProps( this[ this.typeMap[prop] ] );
                    }
				}
			break;
			case 'name':
				str += '<tr><td class="th" colspan="2">All properties (alphabetical)</td></tr>';
				str += this.getProps( this.props );
			break;
		}

		str += "\n"+'</table>';

		this.toWin( str );
	},

    domName:function( obj ){
        var modifier = obj.name ? '[' + obj.name + ']' : '';
        modifier += obj.id ? '#' + obj.id : '';
        modifier += obj.className ? '.' + obj.className : '';

        return modifier;
    },

	getHere:function(){
        var e = false;

		var link = '_obj_';
		var obj = this.obj;
		var locationStr = '';
		var text = '';

        var tagName = '';
		var tempStr = '';

		while( tagName != 'BODY' ){
            tagName = obj.tagName ? obj.tagName : '';
			text = tagName + this.domName( obj );

			if( text == '' ){
			    text = obj.nodeName;
			    e = true;
			}

			tempStr = ' &gt; <a href="javascript:void(0);" onclick="inspector.init( \''+link+'\' );">'+text+'</a>';

			if( e ){
			    tempStr += ' <a class="warning" href="javascript:void(0);" onclick="inspector.e( \'iDOM\', window );">!</a> ';
			    e = false;
			}

			locationStr = tempStr + locationStr;

			link += '.parentNode';

			if( obj.parentNode ){
    			obj = obj.parentNode;
			}else{
			    break;
			}
		}

		return 'You are here ' + locationStr + '<br /><br />';
	},

	getProps:function( key ){
		var keys = key.length;
		var obj = this.obj;
		var prop, val;
		var str = '';
        var found = false;

        var show = true;

		for( var i = 0; i < keys; i++ ){
			if( key[i] == 'domConfig' ||
			    key[i] == 'globalStorage' ){
				continue;
			}

			prop = key[i];
            val  = obj[prop];

            if( val ){
                if( this.hideNative &&
                    typeof val == 'function' &&
                    val.toString().indexOf( '[native code]' ) != -1 ){
                    continue;
                }

    			if( prop == 'innerHTML' || prop == 'textContent' || prop == 'xml' ){
    				val = val.replace( /</g, '&lt;' );
    				val = val.replace( />/g, '&gt;' );
    				val = val.replace( /\n/g, '<br />' );
                    val = val.replace( /\n/g, '<br>' );
    			}
			}else if( val == null || val == '' ){
				val = '<i>null</i>';
			}else{
                continue;
            }

			str += "\n"+'<tr>';
			str += "\n"+'	<td valign="top"><b>'+prop+'</b></td>';

			switch( typeof val ){
				case 'boolean':
					str += "\n"+'	<td>'+val+"</td>";
					break;
				case 'function':
					str += "\n"+'	<td>'+val+"</td>";
					break;
				case 'number':
					str += "\n"+'	<td class="num">'+val+"</td>";
					break;
				case 'object':
					str += "\n"+'	<td><a href="javascript:void(0);" onclick="inspector.init( \'_obj_.'+prop+'\' );">'+val;

					if( obj[prop] && obj[prop].length ){
						str += ' {'+ obj[prop].length +'}';
					}

					str += "</td>";
					break;
				case 'string':
					str += "\n"+'	<td class="str">'+val+"</td>";
					break;
			    default:
                    alert( 'typeOf '+( typeof val ) );
			}

			str += "\n"+'</tr>';
		}

		return str;
	},

	load:function(){
		var obj = this.obj;

		this.props = [];

		this.bools = [];
		this.funcs = [];
		this.numbers = [];
		this.objects = [];
		this.strings = [];

		var type;
		var mapped;

		for( var prop in obj ){
			if( prop == 'domConfig' ){
				continue;
			}

			type = typeof obj[prop];
			mapped = this.typeMap[ type ];

			if( mapped == undefined ){
			    continue;
			}

			this[mapped][ this[mapped].length ] = prop;
			this.props[ this.props.length ] = prop;
		}

		for( prop in this.typeMap ){
		    if( this[ this.typeMap[prop] ] ){
    			this[ this.typeMap[prop] ].sort();
		    }
		}

		this.props.sort();
	},

	toWin:function( winBody ){
		if( this.win == undefined ){
			this.win = window.open();
		}

		this.win.document.open();
		this.win.document.write( this.winHead + winBody + this.winFoot );
		this.win.document.close();

        this.win.inspector = this;
	},

	utils:function(){
		var obj = this.obj

		var str = '';

		if( obj.parentNode ){
			str += '<a href="javascript:void(0);" onclick="inspector.init( \'_obj_.parentNode\' );">Up to parentNode</a><br /><br />';
		}else if( this.lastObj ){
			str += '<a href="javascript:void(0);" onclick="inspector.init( \'_lastObj_\' );">Up to parentNode</a><br /><br />';
		}

		return str;
	},

	e:function( code, win ){
	    var note = '';

	    switch( code ){
	        case 'iDOM':
	            note = "This element may not be the one you want.\n"+
	               "This element may be hidden (style=\"display: none;\") or \n"+
	               "your browser is 'seeing' an HTML comment.";
    	        break;
	    }

	    win.alert( note );
	},

	winHead:''+
		'<html>'+
		"\n"+'	<head>'+
		"\n"+'		<title>Object Inspector</title>'+
		"\n"+'		<style type="text/css">'+
		"\n"+'		body { background-color: #def; font-size: 0.8em; margin: 1em; }'+
		"\n"+'		a { color: blue; text-decoration: none; }'+
		"\n"+'		table { font-size: 1em; }'+
		"\n"+'		table, td { border: 1px solid #666; }'+
		"\n"+'		.num { color: red; }'+
		"\n"+'		.str { color: gray; }'+
		"\n"+'		.th { background-color: white; color: black; font-weight: bold; }'+
		"\n"+'      .warning { color: red; font-weight: bold; }'+
		"\n"+'		</style>'+
		"\n"+'	</head>'+
		"\n"+'	<body>',

	winFoot:''+
		"\n"+'	</body>'+
		"\n"+'</html>'
};

inspector.$ = function( id, objDoc ){
	if( objDoc != undefined && objDoc.getElementById( id ) ){
		return objDoc.getElementById( id );
	}else if( document.getElementById( id ) ){
		return document.getElementById( id );
	}

	return false;
};

var _inspect = function( obj, objDoc ){
    if( objDoc ){
    	inspector.init( obj, objDoc );
    }else{
    	inspector.init( obj );
    }
};

/** $Author:$ * $Date:$ * $Rev:$ **/