/**
Logasm, javascript logger
Copyright (C) 2008 Marc Breuer

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

<http://www.gnu.org/licenses/>
*/

var logasm;
var logasm_tag='s';
var logasm_ie_attributes = new Array('?','role','language','lang','id','hidefocus','dir','contenteditable','disabled','accesskey','tabIndex','cite','datetime','tabindex');

Array.prototype.inArray = function(s) {
	for(var i in this) if(this[i] === s) return true;
	return false;
}

//create html element with attributes and subelements
//my personal hack, not tested outside of logasm
Logasm.prototype.cr = function (e,att,d){
	if(att && att.id){
		var tmp = document.getElementById(att.id);
		if(tmp) e=tmp;
	} 
	if(e.split){
		e=document.createElement(e);
	}
	if(d){
		if(d.split){//text
			e.innerHTML=d;
		}else if(d.tagName){//html element
			e.appendChild(d);
		}else if(typeof d == 'object'){
			//array handling, rather hacky...
			if(d[0] && d[0].tagName && d[0].tagName.toLowerCase()!='tr'){
				//normal array, add elements as you would expect
				for(var i in d){
					if(d[i] && (typeof d[i] == 'object')){
						e.appendChild(d[i]);
					}
				}
			}else{
				//switching views, when moving elements from one place to the other
				//the iteration gets messed up, when an element is moved...
				//so restart until transfer is complete
				var done;
				do{
					done=false;
					for(var i in d){
						if(d[i] && (typeof d[i] == 'object')){
							e.appendChild(d[i]);
							done=true;
							break;
						}
					}
				}while(done);
			}
		}else{
			//alert('bad element '+d);
		}
	}else{
		//alert('nothing to add to '+e.tagName);
	}
	if(att){
		for(var i in att){
			if(i.charAt(0)=='o' && i.charAt(1)=='n'){
				if(i.toLowerCase()=='onclick' && e.tagName.toLowerCase()=='a'){
					e.setAttribute('href','javascript:'+att[i]);
				}
				attachEventCB(e,i.substr(2),isFunction(att[i])?att[i]:new Function('',att[i]));
			}else{
				e.setAttribute(i,att[i]);
				if(i=='className' && e.className!=att[i]){
					e.setAttribute('class',att[i]);
					e.removeAttribute('className');
				}
			}	
		}
	}
	return e;
}

Logasm.prototype.move = function(a,b){
	return this.cr(a,{},b.childNodes);
}

Logasm.prototype.insert = function(a,b){
	return this.cr(a,{},b);
}

Logasm.prototype.getTag = function(s){
	return document.getElementsByTagName(s);
}

Logasm.prototype.getID = function(s){
	var d = document.getElementById(s);
	if(!d) this.cr(document.body,{},this.cr('div',{id:s}));
	return d;
}

Logasm.prototype.endTag = function(txt){
	var pos = txt.search(/\<\/.*?\>/);
	if(pos<0) return txt;
	return txt;
}

Logasm.prototype.parse = function(txt){
	return txt;
}

Logasm.prototype.init_log = function(name){
	this.logs[name] = this.cr('tbody',{id:'log_'+name});
	this.insert(this.tabs,this.cr('div',{id:'tab_'+name,onclick:'logasm.show("'+name+'")'},name));
}

Logasm.prototype.time = function(t){
	var time = t ? new Date(t) : new Date();
	var s = time.getDate()+'.'+(time.getMonth()+1)+'.'+time.getFullYear()+' '+time.getHours()+':'+time.getMinutes()+':'+time.getSeconds();
	return s;
}

Logasm.prototype.add_line = function(base,atts,nodes){
	var tr = this.cr('tr',{});
	tr.title = this.time();
	var k=0;
	if(atts){
		for (var i = 0; i < atts.length; i++) {
			if(!atts[i].name || atts[i].value=='null') continue;
			if(atts[i].name=='style') continue;
			if(atts[i].name.indexOf('aria')>=0) continue;
			if(logasm_ie_attributes.inArray(atts[i].name.toLowerCase())) continue;
			if(atts[i].name=='class' || atts[i].name=='className') continue;
			if(atts[i].name=='title') tr.title += '>>'+atts[i].value; 
			else this.insert(tr,this.cr('td',{type:atts[i].name,className:('td'+(k++%2))},(atts[i].value?atts[i].value:'&nbsp;')));//+atts[i].name
		}
	}
	this.insert(tr,this.cr('td',{className:'data'},nodes));
	this.insert(base,tr);
}

Logasm.prototype.add = function(name,txt,atts){
	if(!name) name='_';
	if(!this.logs[name]) this.init_log(name);
	this.add_line(this.logs[name],atts,this.cr('div',{},this.parse(txt)));
}

Logasm.prototype.write = function(name,txt,atts){
	var anew=new Array();
	for(var i in atts){
		var tmp=new Object();
		tmp.name=i;
		tmp.value=atts[i];
		anew.push(tmp);
	}
	this.add(name,txt,anew);
	this.show(name,true);
}

Logasm.prototype.load = function(){
	var t = this.getTag(logasm_tag);
	while(t.length>0){
		if(!t[0]) continue;
		var name = t[0].className;
		if(!name) name='_';
		var atts = t[0].attributes;
		
		if(!this.logs[name]) this.init_log(name);
		
		this.add_line(this.logs[name],atts,t[0].childNodes);
		
		var p = t[0].parentNode;
		if(p) p.removeChild(t[0]);
	}
}

Logasm.prototype.show_first = function(){
	for(var i in this.logs){
		if(!isFunction(this.logs[i])) return this.show(i);
	}
}


//creates the content of the log from array of data
Logasm.prototype.show = function(name,force){
	if(!name) name='_';
	//make sure log exists
	if(!this.logs[name]) return;
	
	//transfer log data to shows <li>
	if(this.showing!=name){
		if(this.showing) this.move(this.logs[this.showing],this.output);
		this.move(this.output,this.logs[name]);
		//alert(this.output.childNodes.length);
		this.showing=name;
		var c = this.tabs.childNodes;
		for(var i=0;i<c.length;i++){
			c[i].className=(c[i].id=='tab_'+name)?'selected':'not';
		}
	}else if(force){
		this.move(this.output,this.logs[this.showing]);
	}
	this.logwrap.scrollTop = this.logwrap.scrollHeight;
}

//original intended to use "this" instead of "logasm"-instance, but "this" did not work...
Logasm.prototype.resizeStart = function(e){
	e=e||event;
    logasm.mouseX=e.clientX;
    logasm.mouseY=e.clientY;
    logasm.resizing=true;
    attachEventCB(document,'mouseup',logasm.resizeStop);
	attachEventCB(document,'mousemove',logasm.resizeDrag);
	attachEventCB(document,'mousedown',logasm.disabletext);
	logasm.hider.style.display='block';
	
	if(this.debug){
		logasm.write('logasm','*****init drag('+logasm.mouseX+','+logasm.mouseY+')*****',{});
		logasm.write('logasm','init size: '+logasm.group.style.width+','+logasm.logwrap.style.height,{});	
	}
    
	return false;
}

Logasm.prototype.resizeStop = function(e){
	logasm.resizing=false;
	detachEventCB(document,'mouseup',logasm.resizeStop);
	detachEventCB(document,'mousemove',logasm.resizeDrag);
	detachEventCB(document,'mousedown',logasm.disabletext);
	logasm.hider.style.display='none';
	if(this.debug) logasm.write('logasm','*****stop drag*****',{});
	return false;
}

Logasm.prototype.resizeDrag = function(e){
	if(logasm.resizing){
		var w=parseInt(logasm.group.style.width) - e.clientX + logasm.mouseX;
		var h=parseInt(logasm.logwrap.style.height) + e.clientY - logasm.mouseY;
		logasm.group.style.width = w+'px';
		logasm.group.style.height = h+'px';
		logasm.logwrap.style.width = w+'px';
		logasm.logwrap.style.height = h+'px';
		logasm.mouseX=e.clientX;
		logasm.mouseY=e.clientY;
		if(this.debug) logasm.write('logasm','resize: '+logasm.group.style.width+'/'+logasm.logwrap.style.height);
	}
}

Logasm.prototype.disabletext = function(e){
	return false
}


Logasm.prototype.hidelog = function(e){
	this.icon.style.display='block';
	this.group.style.display='none';
}

Logasm.prototype.showlog = function(e){
	this.icon.style.display='none';
	this.group.style.display='block';
}

function Logasm(debug){
	this.debug=debug;
	this.logs=new Array();
	this.shows=new Array();
	this.debug=true;
	this.showing='';
	
	//create output
	this.output=this.cr('tbody',{id:'logasm_output'});
	
	this.tabs  =this.cr('div',{id:'logasm_tabs'});
	this.insert(this.tabs,this.cr('div',{id:'logasm_hide',onclick:'logasm.hidelog()'},'X'));
	
	this.group =this.cr('div',{id:'logasm_group'},this.tabs);
	this.group.style.width='200px';
	this.group.style.height='300px';
	this.logwrap = this.cr('div',{id:'logasm_logwrap'},this.cr('table',{cellspacing:'0'},this.output));
	this.logwrap.style.width='200px';
	this.logwrap.style.height='300px';
	this.insert(this.group,this.logwrap);
	
	this.hider = this.cr('div',{id:'logasm_hider'});
	this.icon = this.cr('div',{id:'logasm_icon',onclick:'logasm.showlog()'});
	
	this.resizer = this.cr('div',{id:'logasm_resizer',onselectstart:"return false;",onmousedown:this.resizeStart},new Array(this.cr('div'),this.cr('a',{href:'http://logasm.com',target:'_blank'},'www.logasm.com')));
	this.insert(this.group,this.resizer);
	
	//add to document
	this.cr(document.body,{},new Array(this.group,this.hider,this.icon));
}

function initLogasm(){
	logasm = new Logasm(false);
	logasm.load();
	logasm.show_first();
	try{
		initLogasmMore();
	}catch(ex){}
}

function isFunction(o) {
	return typeof(o) == 'function' && (!Function.prototype.call || typeof(o.call) == 'function');
};

function attachEventCB(base,type,event,b){
	b=!!b;
	if (base.addEventListener) {
		base.addEventListener(type,event,b);
	} else if (window.attachEvent) {
		base.attachEvent('on'+type,event,b);
	}
}

function detachEventCB(el,event,func,b){
	b=!!b;
	if (el.removeEventListener){
		el.removeEventListener(event,func,b); 
	} else if (el.detachEvent){
		el.detachEvent('on'+event,func,b);
	}
}

attachEventCB(window,'load',initLogasm);