// "Namespace"-Objekt "ibb"
if (typeof ibb == "undefined")
    var ibb = new Object();

ibb.debugCount = 0;
ibb.debug = function (winname) {
    this.winname = winname;
    this.cookiename = "ibb.debug.win."+winname+"-test6";
    this.id = ibb.debugCount;
    this.label = null;
    this.style = "";
    this.window = null;
    this.elemid = null;
    this.elem = null;
    this.level = 0;
    this.parent = null;
    this.active = false;
    this.isIE = (navigator.plugins && navigator.mimeTypes &&
		 navigator.mimeTypes.length) ? false : true;
    this.winPos = new ibb.window ([0,0,600,400]);
    ibb.debugCount ++;
};
ibb.debugStyles = new Array (
    "color:#009900;background-color:#ddffdd;", // grün
    "color:#0000dd;background-color:#eeeeff;", // blau
    "color:#777700;background-color:#ffffdd;", // gelb
    "color:#aa0000;background-color:#ffeeee;", // rot
    "color:#0088dd;background-color:#ddffff;", // hellblau
    "color:#996600;background-color:#ffeecc;"  // orange
);

ibb.debug.prototype = {

    // Hilfsfunktion: Attribute eines Objekts als Baumstruktur ausgeben
    //
    // recurse: 0=nein, n=maxTiefe, -1=unbegrenzt
    //
    trDumpObjectRec: function (ParentTr, Obj, recurse, Path, Done, DoneNames) {
	var type, val, objref, Msg;
	var Attribs = new Array();
	for (var Attrib in Obj)
	    Attribs.push (Attrib);
	Attribs.sort(function (a, b) {
	    var al = a.toLowerCase();
	    var bl = b.toLowerCase();
	    return (al < bl) ? -1 : (al == bl) ? 0 : 1;
	});
	for (var a=0; a<Attribs.length; a++) {
	    var Attrib = Attribs[a];
	    var AddNode = true;
	    try {
		objref = isNaN(Attrib) ? "."+Attrib : "["+Attrib+"]";
		
		Path.push(Path.length > 0 ? objref : Attrib);

		Msg = Path.join("");
		
		eval ("val = String(Obj"+objref+");");
		eval ("typ = typeof Obj"+objref+";");
		Msg += " [" + typ + "]";
		if (typ=="object") {
		  if (recurse) {
		    var found = false;
		    eval ('found = (Obj == Obj'+objref+');');
		    if (found) {
			Msg += " (self)";
		    } else {
			var found = false;
			var i;
			for (i=0; i<Done.length; i++) {
			    eval ('found = (Done[i] == Obj'+objref+');');
			    if (found) break;
			}
			if (found)
			    Msg += " (siehe "+DoneNames[i]+")";
		    }
		    if (!found) {
			var Tr = new GtiTree (true, Msg, Path.join(""), "", ParentTr.IsOpen, true, null);
			ParentTr.AppendNode (Tr);
			AddNode = false;
			Done.push(Obj);
			DoneNames.push(Path.join(""));
			this.indent();
			eval ('this.trDumpObjectRec (Tr,Obj'+objref+',recurse-1,Path,Done,DoneNames)');
			this.unindent();
		    }
		  } else {
		    // Msg bleibt gleich
		  }
		} else if (typ == "string") {
		    Msg += " = \"" + val + "\"";
		} else if (typ != "function" /* sonst wird's bei FF zu viel ... */)
		    Msg += " = " + val;
	    } catch (e) {
		Msg += " " + e.name+": "+e.message;
	    }
	    if (AddNode)
		ParentTr.AppendNode (new GtiTree (true, Msg, Path.join(""), "", false, true, null));
	    Path.pop();
	}
    },

    // Attribute eines Objekts als Baumstruktur ausgeben
    //
    trDumpObject: function (Obj, recurse, isOpen) {
	if (typeof GtiTree == "undefined") {
	    alert ("Die aufgerufene Funktion erfordert\
		    \ndie Einbindung der Datei \"tree.js\"!");
	    return;
	}
	var Tr = new GtiTree (true, "Obj", "Obj", "", isOpen, true, null);
	Tr.IsLast = true;
	var Path = new Array();
	var Done = new Array();
	var DoneNames = new Array();
	var r = recurse ? recurse : 0;
	this.trDumpObjectRec (Tr, Obj, r, Path, Done, DoneNames);
	Tr.Display(this.elem);
    },
    
    // Hilfsfunktion: Attribute eines Objekts auflisten
    //
    // recurse: 0=nein, n=maxTiefe, -1=unbegrenzt
    //
    dumpObjectRec: function (Obj, recurse, Path, Done, DoneNames) {
	var type, val, objref, Msg;
	var Attribs = new Array();
	for (var Attrib in Obj)
	    Attribs.push (Attrib);
	Attribs.sort(function (a, b) {
	    var al = a.toLowerCase();
	    var bl = b.toLowerCase();
	    return (al < bl) ? -1 : (al == bl) ? 0 : 1;
	});
	for (var a=0; a<Attribs.length; a++) {
	    try {
		objref = isNaN(Attrib) ? "."+Attrib : "["+Attrib+"]";
		
		Path.push(Path.length > 0 ? objref : Attrib);

		Msg = Path.join("");
		
		eval ("val = String(Obj"+objref+");");
		eval ("typ = typeof Obj"+objref+";");
		Msg += " [" + typ + "]";
		if (typ=="object") {
		  if (recurse) {
		    var found = false;
		    eval ('found = (Obj == Obj'+objref+');');
		    if (found)
			this.writeLine (Msg+" (self)");
		    else {
			var found = false;
			var i;
			for (i=0; i<Done.length; i++) {
			    eval ('found = (Done[i] == Obj'+objref+');');
			    if (found) break;
			}
			if (found)
			    this.writeLine (Msg+" (siehe "+DoneNames[i]+")");
		    }
		    if (!found) {
			this.writeLine (Msg);
			Done.push(Obj);
			DoneNames.push(Path.join(""));
			this.indent();
			eval ('this.dumpObjectRec (Obj'+objref+',recurse-1,Path,Done,DoneNames)');
			this.unindent();
		    }
		  } else {
		    this.writeLine (Msg);
		  }
		} else if (typ == "string") {
		    if ((Attrib == "innerHTML") || (Attrib == "textContent"))
			this.writeLine(Msg + " = ...");
		    else
			this.writeLine(Msg + " = \"" + val + "\"");
		} else if (typ != "function" /* sonst wird's bei FF zu viel ... */)
		    this.writeLine(Msg + " = " + val);
	    } catch (e) {
		this.writeLine(Msg + " " + e.name+": "+e.message);
	    }
	    Path.pop();
	}
    },

    // Attribute eines Objekts auflisten
    //
    dumpObject: function (Obj, recurse) {
	var Path = new Array();
	var Done = new Array();
	var DoneNames = new Array();
	var r = recurse ? recurse : 0;
	this.dumpObjectRec (Obj, r, Path, Done, DoneNames);
    },
    
    storePos: function (win) {
	this.winPos.updateCoords(win);
	var str = this.winPos.toString();
	ibb.Tools.setCookieString(this.cookiename,str);
    },

    scrollDown: function () {
	if (this.elem)
	    this.window.scrollTo(0,this.elem.scrollHeight);
    },

    // Optional: elemid = ID eines Tags in das die Debug-Ausgaben geschrieben
    //				werden sollen.
    //			null: eigenes Fenster öffnen
    //			existierende ID: in dieses Element schreiben
    //			nichtex. ID: Div-Tag mit angeg. ID anlegen
    //
    activate: function (flag, elemid) {
	this.active = flag;
	this.elemid = elemid;
    },

    init: function () {
	this.active = true;
	if (!this.window) {
	    if (this.parent) {

		// Wenn das Debug-Objekt ein Parent-Objekt hat, kümmert sich
		// dieses um das Initialisieren der Ausgabe

		if (! this.parent.init ()) {
		    this.active = false;
		    return false;
		}
		this.window = this.parent.window;
		this.elem = this.parent.elem;
	
		if (this.style) 
		  if (this.style.length)
		    ibb.Tools.addStyle (this.window, ".d"+this.id+" {"+this.style+"}");

	    } else if (this.elemid) {

		// kein Parent vorhanden, elemid gesetzt: angegebenes Element
		// im aktuellen Fenster suchen oder ggf. anlegen

		this.window = window;
		this.elem = document.getElementById (this.elemid);
		if (! this.elem) {
		    this.elem = document.createElement("div");
		    document.getElementsByTagName("body")[0].appendChild(this.elem);
		}
	    } else {

		// kein Parent vorhanden, kein elemid gesetzt: Window öffnen

		var WinMsg = "\""+this.winname+"\"";
		if (this.label)
		    WinMsg += " für "+this.label;

		// Fensterposition aus Cookie übernehmen. Bei Fehlern bleibt
		// die Default-Position erhalten, so dass weiter unten die
		// Offsets zwischen gesetzten und erhaltenen Koordinaten
		// berechnet werden können
		var str = ibb.Tools.getCookieString(this.cookiename);
		var winPosOk = this.winPos.fromString (str);
		//alert ("fromString \""+str+"\" = "+ (winPosOk ? "ok" : "not ok"));

		var winParams = "dependent=yes,resizable=yes,scrollbars=yes,status=yes,"+this.winPos.paramString();
		this.window = window.open("about:blank",this.winname,winParams);
		if (!this.window) {
		    alert ("Das Debug-Fenster "+WinMsg+" konnte nicht geöffnet werden!");
		    this.active = false;
		    return false;
		}
		try {
		    // Aus gesetzten und abgefragten Koordinaten Offsets errechnen
		    this.winPos.calcOffset(this.window);
		    this.window.document.open();
		} catch (e) {
		    alert ("Es kann nicht auf das Debug-Fenster "+WinMsg+" zugegriffen werden!\n"+
				"Bitte schließen Sie das geöffnete Fenster, so dass es beim\n"+
				"nächsten Versuch erneut geöffnet werden kann.");
		    this.window = null;
		    this.active = false;
		    return false;
		}
		// Inhalt muss dynamisch ins Fenster geschrieben werden. Die
		// Verwendung einer HTML-Datei führt zu Problemen:
		// MSIE: window.open() kehrt zurück, bevor die geladene Seite
		//       aufgebaut ist ==> this.elem kann erst nach einer
		//       gewissen Verzögerung ermittelt werden, sonst erhält
		//       man einen Nullpointer als Ergebnis
		// FF:   this.elem wird sofort korrekt zurückgeliefert, aber
		//       der Seitenaufbau erfolgt verzögert - und überschreibt
		//       die bis dahin bereits erzeugten Debug-Ausgaben.
		this.window.document.write ('\
			<html><head><title>' + this.winname + '</title> \
			<style type="text/css"> \
			 elem  {margin:0;} \
			 .main {/*white-space:nowrap;*/color:#666666;} \
			 .d0   {} \
			</style> \
			<script type="text/javascript">\n<!-- \n \
			var MasterObj = null; \
			function setMaster (Obj) {MasterObj = Obj;} \
			function closeWin () {MasterObj.storePos(window);} \n // --> \n \
			</script> \
			</head><elem onblur="closeWin()"><div class="main"></div></elem></html>');
		this.window.document.close();
		this.window.setMaster(this);

		this.elem = this.window.document.getElementsByTagName("div")[0];
		//alert (this.label+": elem="+this.elem);
	    }
	}
	return true;
    },

    writeNode: function (node) {
	if (!this.active)
	    return;
	if (! this.init ())
	    return;

	if (! this.elem) {
	    alert (this.label+": kein elem für \""+node+"\"");
	    return;
	}
	with (this.window.document) {
	    // span-Tag mit Zeilenumbruch statt div-Tag verwenden, da FF sonst
	    // die Hintergrundfarbe nur bis zum rechten Fensterrand zeichnet.
	    var Bl = createElement("span");

	    if (this.isIE) {
		Bl.className = "d"+this.id;
		Bl.style.paddingLeft = String(this.level)+"em";
	    } else {
		var At = createAttribute("class");
		At.nodeValue = "d"+this.id;
		Bl.setAttributeNode(At);

		var St = createAttribute("style");
		St.nodeValue = "padding-left:"+String(this.level)+"em;";
		Bl.setAttributeNode(St);
	    }
	    
	    if (this.label)
		Bl.appendChild(createTextNode("["+this.label+"] "));

	    Bl.appendChild(createTextNode(node));
	    Bl.appendChild(createElement("br"));
	    this.elem.appendChild(Bl);
	}
    },

    writeLine: function (text, indent) {
	if (indent < 0)
	    this.unindent();
	if (text)
	    this.writeNode (text);
	if (indent > 0)
	    this.indent();
	this.scrollDown();
    },

    writeLines: function (headline, texts) {
	if (!this.active)
	    return;
	if (! this.init ())
	    return;

	if (headline)
	    this.writeNode (headline);
	if (texts.length > 0) {
	    var L = this.label;
	    this.label = null;
	    this.level ++;
	    for (var i=0; i<texts.length; i++)
		if (texts[i])
		    this.writeNode(texts[i]);
	    this.level --;
	    this.label = L;
	}
	this.scrollDown();
    },

    indent: function () {
	this.level ++;
    },

    unindent: function () {
	if (this.level > 0)
	    this.level --;
    },

    add: function (label, style) {
	var obj = new ibb.debug (this.winname);
	obj.label = label;
	obj.parent = this;
	obj.active = this.active;
	obj.winname = this.winname;
	// Angegebenen style verwenden (Leerstring für leeren Style); falls
	// nicht angegeben (null) immer einen der vorgegebenen Styles verwen-
	// den. id-1 verwenden, damit erstes mit "add" zugefügtes Objekt den
	// 1. Array-Eintrag verwendet.
	obj.style = style ? style : ibb.debugStyles[(obj.id-1) % ibb.debugStyles.length];
	return obj;
    }
};

if (typeof ibb.Debug == "undefined")
    ibb.Debug = new ibb.debug ("ibbdebug");


