if (!("console" in window) || !("firebug" in console)) 
{
	(
		function()
		{
			window.console = 
			{
				log: function(){logFormatted(arguments, "");},
				
				debug: function(){logFormatted(arguments, "debug");},
				
				info: function(){logFormatted(arguments, "info");},
				
				warn: function(){logFormatted(arguments, "warning");},
				
				error: function(){logFormatted(arguments, "error");},
				
				assert: function(truth, message)
				{
					if (!truth)
					{
						var	args	=	[];
						for (var i = 1; i < arguments.length; ++i)
							args.push(arguments[i]);

						logFormatted(args.length ? args : ["Assertion Failure"], "error");
						throw message ? message : "Assertion Failure";
					}
				},
				
				dir: function(object)
				{
					var	html	=	[];
					var	pairs	=	[];
					for (var name in object)
					{
						try {pairs.push([name, object[name]]);}catch (exc){}
					}

					pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });

					html.push('<table>');
					for (var i = 0; i < pairs.length; ++i)
					{
						var	name	=	pairs[i][0];
						var	value	=	pairs[i][1];

						html.push('<tr>', '<td class="propertyNameCell"><span class="propertyName">', escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
						appendObject(value, html);
						html.push('</span></td></tr>');
					}
					html.push('</table>');

					logRow(html, "dir");
				},

				dirxml: function(node)
				{
					var	html	=	[];

					appendNode(node, html);
					logRow(html, "dirxml");
				},

				group: function(){logRow(arguments, "group", pushGroup);},
				
				groupEnd: function(){logRow(arguments, "", popGroup);},
				
				time: function(name){timeMap[name] = (new Date()).getTime();},

				timeEnd: function(name)
				{
					if (name in timeMap)
					{
						var	delta	=	(new Date()).getTime() - timeMap[name];
						logFormatted([name+ ":", delta+"ms"]);
						delete timeMap[name];
					}
				},

				count: function(){this.warn(["count() not supported."]);},
				
				trace: function(){this.warn(["trace() not supported."]);},
				
				profile: function(){this.warn(["profile() not supported."]);},
				
				profileEnd: function(){},
				
				clear: function(){consoleBody.innerHTML = "";},
				
				open: function(){toggleConsole(true);},
				
				close: function()
				{
					if (frameVisible)
						toggleConsole();
				}
			};
 
			// ********************************************************************************************
			var	consoleFrame	=	null;
			var	consoleBody	=	null;
			var	commandLine	=	null;

			var	frameVisible	=	false;
			var	messageQueue	=	[];
			var	groupStack	=	[];
			var	timeMap		=	{};

			var	clPrefix	=	">>> ";

			var	isFirefox	=	navigator.userAgent.indexOf("Firefox") != -1;
			var	isIE		=	navigator.userAgent.indexOf("MSIE") != -1;
			var	isOpera		=	navigator.userAgent.indexOf("Opera") != -1;
			var	isSafari	=	navigator.userAgent.indexOf("AppleWebKit") != -1;
			// ********************************************************************************************

			function toggleConsole(forceOpen)
			{
				frameVisible	=	forceOpen || !frameVisible;
				if (consoleFrame)
					consoleFrame.style.visibility	=	frameVisible ? "visible" : "hidden";
				else
					waitForBody();
			}

			function focusCommandLine()
			{
				toggleConsole(true);
				if (commandLine)
					commandLine.focus();
			}

			function waitForBody()
			{
				if (document.body)
					createFrame();
				else
					setTimeout(waitForBody, 200);
			}    

			function createFrame()
			{
				if (consoleFrame)
					return;
	        
				window.onFirebugReady	=	function(doc)
				{
					window.onFirebugReady	=	null;

					var	toolbar	=	doc.getElementById("toolbar");
					toolbar.onmousedown	=	onSplitterMouseDown;

					commandLine	=	doc.getElementById("commandLine");
					addEvent(commandLine, "keydown", onCommandLineKeyDown);

					addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);

					consoleBody	=	doc.getElementById("log");
					layout();
					flush();
				}

				var	baseURL	=	getFirebugURL();

				consoleFrame	=	document.createElement("iframe");
				consoleFrame.setAttribute("src", baseURL + "/firebug.html");
				consoleFrame.setAttribute("frameBorder", "0");
				consoleFrame.style.visibility	=	(frameVisible ? "visible" : "hidden");    
				consoleFrame.style.zIndex	=	"2147483647";
				consoleFrame.style.position	=	"fixed";
				consoleFrame.style.width	=	"100%";
				consoleFrame.style.left		=	"0";
				consoleFrame.style.bottom	=	"0";
				consoleFrame.style.height	=	"200px";
				document.body.appendChild(consoleFrame);
			}
	    
			function getFirebugURL()
			{
				var	scripts	=	document.getElementsByTagName("script");
				for (var i = 0; i < scripts.length; ++i)
				{
					if (scripts[i].src.indexOf("firebug.js") != -1)
					{
						var	lastSlash	=	scripts[i].src.lastIndexOf("/");
						return scripts[i].src.substr(0, lastSlash);
					}
				}
			}
		    
			function evalCommandLine()
			{
				var	text	=	commandLine.value;
				//commandLine.value	=	"";

				logRow([clPrefix, text], "command");

				var	value;
				try{value = eval(text);}catch (exc){}

				console.log(value);
			}
	    
			function layout()
			{
				var	toolbar	=	consoleBody.ownerDocument.getElementById("toolbar");
				var	height	=	consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
				consoleBody.style.top		=	toolbar.offsetHeight + "px";
				consoleBody.style.height	=	height + "px";

				commandLine.style.top		=	(consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
			}
		    
			function logRow(message, className, handler)
			{
				if (consoleBody)
					writeMessage(message, className, handler);
				else
				{
					messageQueue.push([message, className, handler]);
					waitForBody();
				}
			}
		    
			function flush()
			{
				var	queue	=	messageQueue;
				messageQueue	=	[];

				for (var i = 0; i < queue.length; ++i)
					writeMessage(queue[i][0], queue[i][1], queue[i][2]);
			}

			function writeMessage(message, className, handler)
			{
				var	isScrolledToBottom	= consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;

				if (!handler)
					handler	=	writeRow;

				handler(message, className);

				if (isScrolledToBottom)
					consoleBody.scrollTop	=	consoleBody.scrollHeight - consoleBody.offsetHeight;
			}
		    
			function appendRow(row)
			{
				var	container	=	groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
				container.appendChild(row);
			}

			function writeRow(message, className)
			{
				var row = consoleBody.ownerDocument.createElement("div");
				row.className = "logRow" + (className ? " logRow-"+className : "");
				row.innerHTML = message.join("");
				appendRow(row);
			}

			function pushGroup(message, className)
			{
				logFormatted(message, className);

				var groupRow = consoleBody.ownerDocument.createElement("div");
				groupRow.className = "logGroup";
				var groupRowBox = consoleBody.ownerDocument.createElement("div");
				groupRowBox.className = "logGroupBox";
				groupRow.appendChild(groupRowBox);
				appendRow(groupRowBox);
				groupStack.push(groupRowBox);
			}

			function popGroup()
			{
				groupStack.pop();
			}
			// ********************************************************************************************

			function logFormatted(objects, className)
			{
				var html = [];

				var format = objects[0];
				var objIndex = 0;

				if (typeof(format) != "string")
				{
					format = "";
					objIndex = -1;
				}

				var parts = parseFormat(format);
				for (var i = 0; i < parts.length; ++i)
				{
					var part = parts[i];
					if (part && typeof(part) == "object")
					{
						var object = objects[++objIndex];
						part.appender(object, html);
					}
					else
						appendText(part, html);
				}

				for (var i = objIndex+1; i < objects.length; ++i)
				{
					appendText(" ", html);

					var object = objects[i];
					if (typeof(object) == "string")
						appendText(object, html);
					else
						appendObject(object, html);
				}

				logRow(html, className);
			}

			function parseFormat(format)
			{
				var parts = [];

				var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;    
				var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};

				for (var m = reg.exec(format); m; m = reg.exec(format))
				{
					var type = m[8] ? m[8] : m[5];
					var appender = type in appenderMap ? appenderMap[type] : appendObject;
					var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);

					parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
					parts.push({appender: appender, precision: precision});

					format = format.substr(m.index+m[0].length);
				}

				parts.push(format);

				return parts;
			}

			function escapeHTML(value)
			{
				function replaceChars(ch)
				{
					switch (ch)
					{
						case "<":
							return "&lt;";
						case ">":
							return "&gt;";
						case "&":
							return "&amp;";
						case "'":
							return "&#39;";
						case '"':
							return "&quot;";
					}
					return "?";
				};
				return String(value).replace(/[<>&"']/g, replaceChars);
			}

			function objectToString(object)
			{
				try
				{
					return object+"";
				}
				catch (exc)
				{
					return null;
				}
			}

			// ********************************************************************************************
			function appendText(object, html)
			{
				html.push(escapeHTML(objectToString(object)));
			}

			function appendNull(object, html)
			{
				html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
			}

			function appendString(object, html)
			{
				html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)), '&quot;</span>');
			}

			function appendInteger(object, html)
			{
				html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
			}

			function appendFloat(object, html)
			{
				html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
			}

			function appendFunction(object, html)
			{
				var reName = /function ?(.*?)\(/;
				var m = reName.exec(objectToString(object));
				var name = m ? m[1] : "function";
				html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
			}
		    
			function appendObject(object, html)
			{
				try
				{
					if (object == undefined)
						appendNull("undefined", html);
					else if (object == null)
						appendNull("null", html);
					else if (typeof object == "string")
						appendString(object, html);
					else if (typeof object == "number")
						appendInteger(object, html);
					else if (typeof object == "function")
						appendFunction(object, html);
					else if (object.nodeType == 1)
						appendSelector(object, html);
					else if (typeof object == "object")
						appendObjectFormatted(object, html);
					else
						appendText(object, html);
				}
				catch (exc)
				{
				}
			}
		        
			function appendObjectFormatted(object, html)
			{
				var text = objectToString(object);
				var reObject = /\[object (.*?)\]/;

				var m = reObject.exec(text);
				html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
			}
		    
			function appendSelector(object, html)
			{
				html.push('<span class="objectBox-selector">');

				html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
				if (object.id)
					html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
				if (object.className)
					html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');

				html.push('</span>');
			}

			function appendNode(node, html)
			{
				if (node.nodeType == 1)
				{
					html.push('<div class="objectBox-element">', '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');

					for (var i = 0; i < node.attributes.length; ++i)
					{
						var attr = node.attributes[i];
						if (!attr.specified)
							continue;

						html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),'</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),'</span>&quot;')
					}

					if (node.firstChild)
					{
						html.push('&gt;</div><div class="nodeChildren">');

						for (var child = node.firstChild; child; child = child.nextSibling)
							appendNode(child, html);

						html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">', 
						node.nodeName.toLowerCase(), '&gt;</span></div>');
					}
					else
						html.push('/&gt;</div>');
				}
				else if (node.nodeType == 3)
				{
					html.push('<div class="nodeText">', escapeHTML(node.nodeValue),'</div>');
				}
			}

			// ********************************************************************************************
		    
			function addEvent(object, name, handler)
			{
				if (document.all)
					object.attachEvent("on"+name, handler);
				else
					object.addEventListener(name, handler, false);
			}
		    
			function removeEvent(object, name, handler)
			{
				if (document.all)
					object.detachEvent("on"+name, handler);
				else
					object.removeEventListener(name, handler, false);
			}
		    
			function cancelEvent(event)
			{
				if (document.all)
					event.cancelBubble = true;
				else
					event.stopPropagation();        
			}

	//    function onError(msg, href, lineNo)
	//    {
	//        var html = [];
	//        
	//        var lastSlash = href.lastIndexOf("/");
	//        var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
	//        
	//        html.push(
	//            '<span class="errorMessage">', msg, '</span>', 
	//            '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
	//        );
	//        
	//        logRow(html, "error");
	//    };

			function onKeyDown(event)
			{
				if (event.keyCode == 123 || (event.keyCode == 88 && event.ctrlKey))
				{
					toggleConsole();
					console.log("location --> " + self.location.href);
				}
				else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey && (event.metaKey || event.ctrlKey))
					focusCommandLine();
				else
					return;

				cancelEvent(event);
			}

			function onSplitterMouseDown(event)
			{
				if (isSafari || isOpera)
					return;

				addEvent(document, "mousemove", onSplitterMouseMove);
				addEvent(document, "mouseup", onSplitterMouseUp);

				for (var i = 0; i < frames.length; ++i)
				{
					addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
					addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
				}
			}
		    
			function onSplitterMouseMove(event)
			{
				var win = document.all ? event.srcElement.ownerDocument.parentWindow: event.target.ownerDocument.defaultView;

				var clientY = event.clientY;
				if (win != win.parent)
					clientY += win.frameElement ? win.frameElement.offsetTop : 0;

				var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
				var y = height - clientY;

				consoleFrame.style.height = y + "px";
				layout();
			}
		    
			function onSplitterMouseUp(event)
			{
				removeEvent(document, "mousemove", onSplitterMouseMove);
				removeEvent(document, "mouseup", onSplitterMouseUp);

				for (var i = 0; i < frames.length; ++i)
				{
					removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
					removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
				}
			}
		    
			function onCommandLineKeyDown(event)
			{
				if (event.keyCode == 13)
					evalCommandLine();
				else if (event.keyCode == 27)
					commandLine.value = "";
			}
		    
		//    window.onerror = onError;
			addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
		    
			if (document.documentElement.getAttribute("debug") == "true")
				toggleConsole(true);

		}
	)();
}
