/*
UI Log 1.1 by Ari N. Karp, September 2008
using mooTools v.1.11, and a mooTools extension.

Blog: theuiguy.blogspot.com

You are free to use at will, just at least visit my blog and tell me
1. if you are using it and how (for curiosity sake)
2. some feedback on how you changed, enhanced, or minimized it. 

I believe in sharing code to the community, so if you feel the same, then
please share your changes with me to help make the UI a better place.

For help on this, please visit theuiguy.blogspot.com and I will get back asap.
*/
var log = function(){
	return log = {
		start : function(options){
			/* 
				the following are settings that should be changed with caution			
			*/
			this.minimumHeight = 80;
			this.panelButtons = [];
			this.shrinkHeight = 22;
			this.toggleDuration = 300;			
			/* 	
				the following are options with reasonable defaults
				options.position = placement on the screen, 1-4, top, bottom, left, right
				options.pS = pixel snap. amount of pixels from edge needed to trigger a snap;	
				options.pT = pixel threshold. amount of pixels from any other side needed to trigger a snap. (make this smaller)	
				options.modifyAmount = amount you want to change the height when making taller or shorter.
			*/
			this.minimized = options.minimized;
			this.snap = options.snap;
			this.opacity = options.opacity || 1;			
			this.outerPadding = options.outerPadding || 2; 
			this.innerPadding = options.innerPadding || 2;
			this.pS = options.pixelSnap || 100; 
			this.pT = options.pixelThreshhold || 50; 
			this.position = options.position || 2;	
			this.modifyAmount = options.modifyAmount || 50;		
			this.logOutputWidth = Math.max(100,options.width) || 570;
			this.logOutputHeight = Math.max(this.minimumHeight,options.height) || 400;		
			/* 
				the following help diminish circular references 
			*/
			this.logContainer = "logContainer";
			this.controlPanel = "controlPanel";
			this.logWrapper = "uiLog";
			/* 
				the following establish the log itself 
			*/
			this.controlWrapper = {
				initialize : function(){
					this.panel = new Element("div",{
						id : 'controlPanel',
						'class' : 'controlPanel',
						'events' : {
							'mousedown' : function(event){
								log.logPanel.container.makeDraggable({droppables: [document.firstChild], container: false});	
							},
							'mouseup' : function(event){								
								if(log.snap){
									var target = (window.ie) ? event.srcElement : event.target;
									var coords = target.getCoordinates();										
									if(coords.top < log.pS && coords.bottom < (document.body.clientHeight - log.pT) && coords.left > log.pT && coords.right < (document.body.clientWidth - log.pT)) log.positionLog(1); // top												
									if(coords.top > log.pT && coords.bottom > (document.body.clientHeight - log.pS) && coords.left > log.pT && coords.right < (document.body.clientWidth - log.pT)) log.positionLog(2); // bottom
									if(coords.top > log.pT && coords.bottom < (document.body.clientHeight - log.pT) && coords.left < log.pS && coords.right < (document.body.clientWidth - log.pT)) log.positionLog(3); // left
									if(coords.top > log.pT && coords.bottom < (document.body.clientHeight - log.pT) && coords.left > log.pT && coords.right > (document.body.clientWidth - log.logPanel.container.offsetWidth)) log.positionLog(4); // right								
								}
							}
						}					
					}).injectBefore(log.logPanel.uiLog);	
					/* Right now the enter left side is draggable.
					this.grabberButton = new Element("div",{
						id : 'grabberButton',
						title : 'move log',
						'class' : 'controlButton grabber',
						'events' : {
							'mousedown' : function(event){
								event.cancelBubble = false;
							}	
						}
					}).inject(this.panel); 		
					*/					
					this.toggleDisplayButton = new Element("div",{
						id : 'toggleDisplayButton',
						title : 'toggle the display of the log',
						'class' : 'controlButton hide',
						'events' : {
							'mousedown' : function(event){
								event.cancelBubble = true;								
								if(this.hidden === false || this.hidden === undefined){
									this.setClass('controlButton show');
									log.hideUiLog(true);
									this.hidden = true;
								}else{
									this.setClass('controlButton hide');
									log.showUiLog();
									this.hidden = false;
								}								
							}	
						}
					}).inject(this.panel);
					this.makeTallerButton = new Element("div",{
						id : 'makeTallerButton',
						title : 'make log taller',
						'class' : 'controlButton dimensions taller',
						'events' : {
							'mousedown' : function(event){
								if(event) event.cancelBubble = true;
								log.changeLogHeight(true);
							}
						}
					}).inject(this.panel);
					log.panelButtons.push('makeTallerButton'); 		
					this.makeShorterButton = new Element("div",{
						id : 'makeShorterButton',
						title : 'make log shorter',
						'class' : 'controlButton dimensions shorter',
						'events' : {
							'mousedown' : function(event){
								if(event) event.cancelBubble = true;
								log.changeLogHeight(false);
							}	
						}
					}).inject(this.panel); 	
					log.panelButtons.push('makeShorterButton'); 																									
					this.clearButton = new Element("div",{
						id : 'clearButton',
						title : 'clear log',
						'class' : 'controlButton clear',
						'events' : {
							'mousedown' : function(event){
								event.cancelBubble = true;
								log.clearUiLog();
							}	
						}
					}).inject(this.panel);
					log.panelButtons.push('clearButton'); 					
					/*
					if(window.ie){
						this.clipboardButton = new Element("div",{
							id : 'clipboardButton',
							title : 'add to clipboard',
							'class' : 'controlButton clipboard',
							'events' : {
								'mousedown' : function(event){
									event.cancelBubble = true;
									window.clipboardData.setData('Text',log.logPanel.uiLog.getText());
								}	
							}
						}).inject(this.panel);					
					}
					*/
				}			
			};
			this.logPanel = {
				initialize : function(){
					this.container = new Element("div",{
						id : 'logContainer',
						'class' : 'logContainer',	
						'events' : {
							'mousedown' : function(event){
								event.cancelBubble = true;								
							}					
						}								
					}).inject(document.body);
					this.uiLog = new Element("div",{
						id : 'uiLog',
						'class' : 'uiLog',
						'events' : {
							'mousedown' : function(event){
								event.cancelBubble = true;								
							}						
						}					
					}).inject(this.container);										
				}					
			};
			this.logPanel.initialize();	
			this.controlWrapper.initialize();								
			this.started = true;
			this.initLog();		
			window.setTimeout(function(){ // For opera, which renders *too* fast.					
				log.setDimensions(!log.minimized,false);
				if(log.minimized){
					log.hideUiLog(false);
				}else{					
					log.positionLog(log.position);	
				}
			},0);	
			log._routines();		
		},
		setDimensions : function(show,animate){		
			var controlWidth = log.controlWrapper.panel.offsetWidth;	
			$(this.logContainer).style.width = (this.logOutputWidth + controlWidth) + "px";			
			$(this.logWrapper).style.paddingLeft = this.innerPadding + "px";			
			$(this.logWrapper).style.height = this.logOutputHeight + "px";		
			if(animate){
				var expand = new Fx.Style($(this.logWrapper), 'width', {duration: this.toggleDuration, transition: Fx.Transitions.Expo.easeInOut});
				expand.start(this.logOutputWidth - controlWidth);
			}else{
				$(this.logWrapper).style.width =  (this.logOutputWidth - controlWidth)+ "px";	
			}
			$(this.controlPanel).style.height = this.logOutputHeight + "px";
			if(show && $(this.logContainer).style.visibility !== "visible") $(this.logContainer).style.visibility = "visible";			
			$(this.logWrapper).style.filter = "alpha(opacity="+ (this.opacity * 100) +")"; 
			$(this.logWrapper).style.opacity = this.opacity;	
		},
		changeLogHeight : function(increase){			
			var modifyHeightWrapper = new Fx.Style($(this.logWrapper), 'height', {duration: this.toggleDuration, transition: Fx.Transitions.Expo.easeInOut});		
			var modifyHeightPanel = new Fx.Style($(this.controlPanel), 'height', {duration: this.toggleDuration, transition: Fx.Transitions.Expo.easeInOut});				
			if(increase){				
				modifyHeightWrapper.start($(this.logWrapper).clientHeight + this.modifyAmount);
				modifyHeightPanel.start($(this.logWrapper).clientHeight + this.modifyAmount);
			}else{
				modifyHeightWrapper.start(Math.max(this.minimumHeight,($(this.logWrapper).clientHeight - this.modifyAmount)));
				modifyHeightPanel.start(Math.max(this.minimumHeight,($(this.logWrapper).clientHeight - this.modifyAmount)));
			}			
			window.setTimeout(function(){
				log.logOutputHeight = $(log.logWrapper).clientHeight;
				$(log.logContainer).style.height = $(log.logWrapper).clientHeight;
				log.positionLog();
			},this.toggleDuration+1);
		},
		initLog : function(){
			this.updateLogClock();
			this.xDate = new Date();
			$(this.logWrapper).innerHTML += this.updateLogClock() + "<em>Log started</em>" + "<br>";			
			//log.out("<em>Log started (DOM Rendered) in: </em>");
		},
		clearUiLog : function(){
			$(this.logWrapper).innerHTML = "";
			this.initLog();
		},
		showUiLog : function(){			
			window.setTimeout(function(){
				$(log.logWrapper).style.overflowY = "auto";				
				log.setDimensions(false,true);
				log.positionLog();
				$each(log.panelButtons, function(button, index){
				$(button).style.display = "block";
				},log);
			},(this.toggleDuration+1));
		},	
		hideUiLog : function(animate){
			$each(this.panelButtons, function(button, index){
				$(button).style.display = "none";
			},this);			
			if(animate){
				var collapse1A = new Fx.Style($(this.logWrapper), 'width', {duration: this.toggleDuration, transition: Fx.Transitions.Circ.easeOut});
				var collapse1B = new Fx.Style($(this.logWrapper), 'height', {duration: this.toggleDuration, transition: Fx.Transitions.Circ.easeOut});
				var collapse2 = new Fx.Style($(this.controlPanel), 'height', {duration: this.toggleDuration, transition: Fx.Transitions.Circ.easeOut});					
				var startValue = (window.ie) ? 1 : 0;
				collapse1A.start(startValue);
				collapse1B.start(this.shrinkHeight);	
				collapse2.start(this.shrinkHeight);	
			}else{								
				$(log.logWrapper).style.width = "0px";
				$(log.logWrapper).style.height = log.shrinkHeight;
				$(log.controlPanel).style.height = log.shrinkHeight;				
			}
			$(this.logWrapper).style.overflow = "hidden";
			$(this.logWrapper).style.paddingLeft = "0px";			
			window.setTimeout(function(){
				$(log.logContainer).style.left = log.outerPadding + "px";	
				$(log.logContainer).style.top = ((document.body.clientHeight - log.shrinkHeight) - log.outerPadding) + "px"; 
				if($(log.logContainer).style.visibility !== "visible") $(log.logContainer).style.visibility = "visible";			
			},(this.toggleDuration+1));
		},
		positionLog : function(position){			
			this.position = (position === undefined) ? this.position : position;
			if(!this.position){ // start in the middle left if not snapping and therefore not positioning.
				$(this.logContainer).style.left =  this.outerPadding + "px";	
				$(this.logContainer).style.top = ((parseInt(document.body.clientHeight,10) / 2) - (($(this.logContainer).clientHeight)/ 2)) + "px";
				return;
			}	
			try{
				switch(this.position){
					case "top": 
					case 1: 
						$(this.logContainer).style.left = ((parseInt(document.body.clientWidth,10) / 2) - (($(this.logContainer).offsetWidth)/ 2)) + "px";		
						$(this.logContainer).style.top =  this.outerPadding + "px";	
					break;	
					case "bottom": 
					case 2: 
						$(this.logContainer).style.left = ((parseInt(document.body.clientWidth,10) / 2) - (($(this.logContainer).offsetWidth)/ 2)) + "px";							
						$(this.logContainer).style.top = ((document.body.clientHeight - $(this.logContainer).offsetHeight) - this.outerPadding) + "px";
					break;		
					case "left": 
					case 3: 
						$(this.logContainer).style.left = this.outerPadding + "px";							
						$(this.logContainer).style.top = ((parseInt(document.body.clientHeight,10) / 2) - (($(this.logContainer).offsetHeight)/ 2)) + "px";
					break;			
					case "right": 
					case 4:
						$(this.logContainer).style.left = ((document.body.clientWidth - $(this.logContainer).clientWidth) - this.outerPadding) + "px";													
						$(this.logContainer).style.top =  ((parseInt(document.body.clientWidth,10) / 2) - (($(this.logContainer).offsetWidth)/ 2)) + "px";
					break;										
				}
			}catch(e){};
		},	
		updateLogClock : function(){	
			var tDate = new Date();				
			this.currentClock = tDate;
			return "[" + this._formatDate(tDate,"dd-MM-yy hh:mm:ss:iii") + "] \>\> ";	
		},	
		out : function(m){
			window.setTimeout(function(){log._out(m)},0); 
		},
		_out : function(m){
			if(this.started){
				$(this.logWrapper).innerHTML += this.updateLogClock() + m + " <span class='log'>(" +  (this.currentClock - this.xDate) + ")</span> ms" + "<br>";
				this.xDate = new Date();
			}
		},		
		_addZero : function(vNumber,millis){			
			if(millis){
				vNumber = (vNumber.toString().length === 2) ? "0" + vNumber : vNumber;
				vNumber = (vNumber.toString().length === 1) ? "00" + vNumber : vNumber;
				return vNumber
			}else{
				return ((vNumber < 10) ? 0 : "") + vNumber;
			}
		},	
		_formatDate : function(vDate, vFormat){ 
			var vDay = this._addZero(vDate.getDate());
			var vMonth = this._addZero(vDate.getMonth()+1);
			var vYearLong = this._addZero(vDate.getFullYear());
			var vYearShort = this._addZero(vDate.getFullYear().toString().substring(3,4));
			var vYear  = (vFormat.indexOf("yyyy")>-1?vYearLong:vYearShort); 
			var vHour = this._addZero(vDate.getHours());
			var vMinute	= this._addZero(vDate.getMinutes());
			var vSecond	= this._addZero(vDate.getSeconds());
			var vMillis	= this._addZero(vDate.getMilliseconds(),true);
			var vDateString	 = vFormat.replace(/dd/g, vDay).replace(/MM/g, vMonth).replace(/y{1,4}/g, vYear);
			vDateString	= vDateString.replace(/hh/g, vHour).replace(/mm/g, vMinute).replace(/ss/g, vSecond).replace(/iii/g, vMillis);
			return vDateString;
		},
		_routines : function(){
			this.suite1 = {
				iteration1 : function(){
					log.clearUiLog();
						for(i=0;i<50;i++){
							log.out("iteration: " + i + " <b>some very minor html output</b>")
						}
					log.out("Iteration 1 finished. (logged 50 entries.)")									
				},
				iteration2 : function(){
					log.clearUiLog();
						for(i=0;i<500;i++){
							var el = new Element("div").inject(document.body);
							el.remove();
						}
					log.out("Iteration 2 finished. (Added and removed 500 empty divs.)")									
				}								
			}
			this.suite2 = {
				show1 : function(){
					log.clearUiLog();																											
					log.out("<a href='http://wwww.google.com' target=new>Google example (image)</a>")
					log.out("<img src='http://www.google.com/intl/en_ALL/images/logo.gif'>")
					log.out("Show 1 finished.")
				},
				show2 : function(){
					log.clearUiLog();																											
					log.out("<a href='http://wwww.google.com' target=new>Google example (in iframe)</a>")
					log.out("<iframe src='http://www.google.com' frameborder=0 width=" + $(log.logWrapper).clientWidth + " height=200></iframe>")
					log.out("Show 2 finished.")
				}
			}	
		}	
	}	
}();

