/**
  * @author Hannes Lau <office@hanneslau.de>
  */

var menu;
var loader;
var scroller;
var contentContainer;
var lightboxHelper;

var windowOnLoadFired = false;
var dojoOnLoadFired = false;



/*
 * While navigating pages with the AJAX menu, the current 
 * state (the URL of the page retreived with AJAX) 
 * is stored in location.hash .
 * w
 * To allow bookmarking of these states we need to forward
 * the user to the URL in the hash, if there is one.
 */
if(location.hash) {
	location.replace(unescape(location.hash.substr(1)));
}


// the part of the URL, which is common to all pages
var staticURL = window.location.protocol + "//" + window.location.hostname + "/";



/*
 *	Initialize the AJAX interface after all images are loaded 
 *	and dojo is initialized
 */
dojo.addOnLoad(function() {
	// console.debug('dojo onLoad fired');
	if(windowOnLoadFired) initialize();
	dojoOnLoadFired = true;
})

window.onload = function() { 
	// console.debug('window onLoad fired');
	if(dojoOnLoadFired) initialize();
	windowOnLoadFired = true
}




function initialize() {	
	// console.debug('initialize called');
	
	// dojo style
	document.body.className = "tundra";	
	
	menu = new Menu();
	loader = new Loader();	
	scroller = new Scroller();
	contentContainer = new ContentContainer();
	lightboxHelper = new LightboxHelper();

	lightboxHelper.init();
	menu.init();
	scroller.init();
	contentContainer.init();	
	

	// register the controllers event handlers
	dojo.subscribe("/Menu/Clicked", this, pageRequestURL);
	dojo.subscribe("/Scroller/DraggedRight", this, pageRequestPrev);
	dojo.subscribe("/Scroller/DraggedLeft", this, pageRequestNext);	
	
	
	// initialize the first state of the browsers history
	var initialURL = window.location.href;
	var initialState = {
		back: function() { pageRequestURL(initialURL, true); }
	};
	dojo.back.setInitialState(initialState);
	
	
	// console.debug('initialized');
	preload();
}




/*
 * Controller
 */
function pageRequestNext() {
	var url = menu.getNextURL();
	pageRequestURL(url);
}
function pageRequestPrev() {
	pageRequestURL(menu.getPrevURL());
}

function pageRequestURL(url, noHistory) {
	// console.debug('Controller: pageRequest '+url);
	
	scroller.startSpin();
	
	// load the requested page
	loader.load(url, pageLoaded);

	if(!noHistory) {
		// add an entry to browser history to enable the back button
		dojo.back.addToHistory({ 
			back: function() { pageRequestURL(url, true); },
			forward: function() { pageRequestURL(url, true); },			
			changeUrl: url.substr(staticURL.length)
		});
	}
}

function pageLoaded(url, title, content, keyvisual) {
	// replace the keyvisual; replace the content
	// console.debug('Controller: page loaded, ')
	scroller.replace(
		keyvisual, 
		function() { 		// callback
			contentContainer.replace(content); 
			document.title = title;
			menu.setCurrent(url);
			
			preload();
		} 
	) || (window.location.href = url);
}

function preload() {
	// console.debug('Controller: Preload: called');
	loader.load(menu.getNextURL(), function() {});
	loader.load(menu.getPrevURL(), function() {});
}





function LightboxHelper() {
	var lightboxes = Array();
	var preloaders = Array();
	var nextGroupNo = 0;
	var initialized = false;

	this.nextGroup = function() {
		nextGroupNo++;
	}

	this.init = function() {
		initialized = true;
	}

	/*
	 * create lightbox for this image and add an 
	 * attribute to the image which allows it to
	 * address the lightbox later. 
	 */
	this.addLightbox = function(imgNode, imgSrc, caption) {
		if(!initialized) {
			alert('lightboxHelper used uninitialized. break');
			return;
		}
		
		var lb = new hadi.Lightbox(
			{ 
				href: imgSrc,
				group: nextGroupNo,
				title: caption
			},
			imgNode
		);
			
		lb.startup();
		lb.disable();
		lightboxes.push(lb);
		
		imgNode.setAttribute('lightboxI',lightboxes.length-1);
		imgNode.title = "";
	}
	
	this.callLightbox = function() {
		lightboxes[this.getAttribute('lightboxI')].show();
	}
}





function Scroller() {
	var fps = 30;
	var cycleSpeed = Math.ceil(1000/fps);
	
	var activeContainers = Array();
	
	var keyvisual;
	var keyvisualWidth;
	var nextImgContainerNo = 0;
	
	var currentSpeed;
	
	// cruise
	var cruiseTimer;
	var cruiseBreakAcceleration = -1;
	var defaultSpeed = 1;
	var defaultDirection = -1;
	
	// drag
	var dragHandle;
	var dragLastX;
	var stopDragMouseUpHandle;
	var stopDragMouseOutHandle;
	var spinThreshold = 5;	
	var lastMove = 0;
	var lastMoveTimestamp = 0;
	
	// spin
	var spinTimer;
	var spinTarget;
	var spinDirection;
	var spinCallback;
	var spinSpeed = 60;
	var spinAcceleration = 2;
	var breakDistance = 600;
	
	// tooltip
	var tooltip;
	var tooltipDelay = 1000; // 1s
	var tooltipImgSrc = "fileadmin/templates/projekte/img/tooltip.gif";
	
		
	this.init = function() {
		// locate keyvisual
		keyvisual = document.getElementById('keyvisual');
		keyvisualWidth = keyvisual.offsetWidth;
		
		var imgContainer = document.getElementById('initialImgContainer');
		
		if(imgContainer.innerHTML) {
			imgContainer.deleted = false;
			activeContainers.push(imgContainer);		
		} else {
			// console.error('Scroller: Init: The innerHTML property of the initial imgContainer is empty');
			return false;
		}
		
		// add tooltip
		tooltip = new Tooltip(
			tooltipImgSrc, 
			keyvisual,
			tooltipDelay,
			false // do not attach tooltip to pointer
		);
		
		
		/*
		 * add handlers to the keyvisual
		 */
		keyvisual.onmousedown = function(e) {
			/*
			 * this is the first click to the keyvisual,
			 * later clicks will be handled by handlers
			 * added by the D&D functions. 
			 */
			// hlau fix: tooltip stays enabled permanently
			// tooltip.disablePermanent(); // user seems to know what he is doing.. maybe
			keyvisualStartDrag(e); // drag
			return false; // disable browsers d&d
		}
		
		
		/*
		 * add dblclick lightboxes to all images in the container
		 */
		lightboxHelper.nextGroup();		 
		for(var i=0; i<imgContainer.childNodes.length; i++) {
			var anchorNode = imgContainer.childNodes[i];
			var imgNode = anchorNode.childNodes[0];
			var href = unescape(anchorNode.href.match(/file=(.*?)\&/)[1]);
			
			lightboxHelper.addLightbox(imgNode,href,document.title);
			imgNode.ondblclick = lightboxHelper.callLightbox;
			
			
			imgContainer.replaceChild(imgNode,anchorNode);
		}
		
		currentSpeed = defaultSpeed*defaultDirection;
		startCruise();
	}

	/*
	 * Update the position of all imgContainers in the keyvisual
	 * create new imgContainers and append them if neccessary.
	 */
	function redraw() {
		var move = Array();
		
		for(var i=0; i< activeContainers.length; i++) {
			var imgContainer = activeContainers[i];
			
			// skip deleted image containers, TODO: splice
			if(imgContainer.deleted) {
				continue;
			}
			
			var x = imgContainer.offsetLeft;
			
			
			/*
				Make sure the keyvisual is always filled with images:
				if the imgContainer is leaving the keyvisual and there is no 
				successor / predecessor, add one. 
			*/
			if(
				imgContainer.l == null				
				&& currentSpeed > 0  
				&& x > 0 
			)  {
				var imgContainerLeft = imgContainer.cloneNode(true);
				imgContainerLeft.style.width = imgContainer.offsetWidth+"px";				
				append(imgContainer,imgContainerLeft,true);
			}
			if(
			   	imgContainer.r == null
				&& currentSpeed < 0 			   
				&& x + imgContainer.offsetWidth < keyvisualWidth
			) {	
				var imgContainerRight = imgContainer.cloneNode(true);
				imgContainerRight.style.width = imgContainer.offsetWidth+"px";
				append(imgContainer,imgContainerRight,false);
			}
			
			/*
				delete imgContainer in case it left the keyvisual
				if its still in, update its position
			*/
			if( 
				(currentSpeed > 0 && x > keyvisualWidth) // right
				|| (currentSpeed < 0 && x < -imgContainer.offsetWidth) // left
			) {
				// no -> trash
				deleteImageContainer(imgContainer);
			} else {
				// yes -> update position
				imgContainer.newPos = x+currentSpeed;
				move.push(imgContainer);
			}
		}
		

		for(i=0; i<move.length; i++) {
			move[i].style.left = move[i].newPos+"px";
		}
	}	

	
	/*
	 * replaces the current image series (imgcontainer)
	 * by appending a new one and spinning towards it
	 */
	this.replace = function(newImgContainer, callback) {
		// console.debug('Scroller: Replace: called');
		
		var imgContainer = null;
		// find an active imgContainer
		for(i=activeContainers.length-1; i>=0; i--) {
			imgContainer = activeContainers[i];
			if(!imgContainer.deleted) {
				break;
			}
		}
		if(!imgContainer) {
			// console.error('Scroller: Replace: No active image container');
			return false;
		}
		
		if(currentSpeed > 0) {
			// find the leftmost imgContainer
			while(imgContainer.l) {
				imgContainer = imgContainer.l;
			}
			
			// append new container
			append(imgContainer, newImgContainer, true);
		} else {
			while(imgContainer.r) {
				imgContainer = imgContainer.r;
			}
			append(imgContainer, newImgContainer, false);
		}
				
		target = newImgContainer;
		spinTo(target, callback);
		
		return true;
	}
	
	
	function append(imgContainer,newImgContainer, left) {
		
		
		newImgContainer.id = 'imgContainer_' + nextImgContainerNo++;
		
		keyvisual.appendChild(newImgContainer);
		
		for(var i=0; i<newImgContainer.childNodes.length; i++) {
			newImgContainer.childNodes[i].ondblclick = lightboxHelper.callLightbox;
		}

		if(!newImgContainer.offsetWidth) {
			alert('empty image container');
			return false;
		}


		var x;	
		if(left) {
			x = imgContainer.offsetLeft-newImgContainer.offsetWidth;
			
			imgContainer.l = newImgContainer;
			newImgContainer.r = imgContainer;
			newImgContainer.l = null;
		} else {
			x = imgContainer.offsetWidth + imgContainer.offsetLeft;
			
			imgContainer.r = newImgContainer;
			newImgContainer.l = imgContainer;
			newImgContainer.r = null;
		}	

		newImgContainer.style.left = x+"px";
		newImgContainer.deleted = false;
		activeContainers.push(newImgContainer);
		return x;

	}
		
	function deleteImageContainer(imgContainer) {
		imgContainer.deleted = true;
	
		keyvisual.removeChild(imgContainer);
		if(imgContainer.l) imgContainer.l.r = null;
		if(imgContainer.r) imgContainer.r.l = null;
	}
	



	/* 
	 * SPIN
	 */
	function spin() {
		var distance;
		var distanceAbs;
		
		var currentSpeedAbs = Math.abs(currentSpeed);		
		var newSpeedAbs;
		
		// do we have to slow down yet?
		var slowdown = false;
		if(spinTarget) {
			
			// calc distance to target
			if(spinDirection > 0) {
				// moving right: align target and keyvisual right
				distance = keyvisualWidth - spinTarget.offsetWidth - spinTarget.offsetLeft;
			} else {
				// moving left: align target and keyvisual left
				distance = spinTarget.offsetLeft;
			}
			distanceAbs = Math.abs(distance);

			if(distanceAbs < breakDistance) {
				// YES, we need to slow down
				slowdown = true;

				// stop when target reached
				if(distanceAbs < 1) {
					currentSpeed = spinDirection*defaultSpeed;
					// console.debug('Scroller: Spin: Target reached.');
					stopSpin();
					return;
				}

				// slow down to be on default speed when distance==0
				var accelerationAbs = (Math.pow(currentSpeed,2) - Math.pow(defaultSpeed,2)) / (2 * (-distanceAbs));
				newSpeedAbs = Math.max(currentSpeedAbs+accelerationAbs, defaultSpeed);		
			}			
		} 
		
		if(!slowdown) {
			// NO, no need to slow down yet

			// break/accelerate to spinSpeed
			newSpeedAbs = Math.max(
				currentSpeedAbs - spinAcceleration,
				Math.min(
					currentSpeedAbs + spinAcceleration, 
					spinSpeed
				)
			);			
		}
		
		currentSpeed = spinDirection*newSpeedAbs;
		redraw();
	}
	
	function stopSpin() {
		window.clearInterval(spinTimer);
		spinTimer = null;
		spinTarget = null;

		startCruise();
		keyvisual.onmousedown = keyvisualStartDrag;
		spinCallback();
	}
	

	this.startSpin = function() {
		// console.debug('Scroller: startSpin');
		
		if(!spinTimer) {
			spinDirection = currentSpeed > 0?1:-1;
			
			keyvisual.onmousedown = function() { return false; };
			stopCruise();
			spinTimer = window.setInterval(spin, cycleSpeed);
		}
	}

	function spinTo(target, callback) {
		// console.debug('Scroller: spinTo');
		
		spinTarget = target;
		spinCallback = callback;
		
		if(!spinTimer) {
			
			keyvisual.onclick = null;
			
			stopCruise();
			spinTimer = window.setInterval(spin, cycleSpeed);
		}
	}	
	
	
	
	/*
	 * Drag
	 */ 
	function keyvisualMouseMove(e) {
		if(!e) e=window.event // ie; 
		
		/*
		 *	drag the keyvisual with the mouse movement;
		 *	request the next/prev page if the user spins fast enough
		 */
		currentSpeed = e.clientX - dragLastX;
		redraw();
		dragLastX = e.clientX;
		
		lastMoveTimestamp = new Date().getTime();
		
		return false;
	}
	
	function keyvisualStartDrag(e) {
		if(!e) e=window.event; // IE
		
		// stop cruise
		stopCruise();
		currentSpeed = 0
	
		// remember the mouse coordinate
		dragLastX = e.clientX;

		// disable tooltip
		// hlau fix: tooltip stays enabled permanently
		// tooltip.disablePermanent();
	
		// start dragging
		keyvisual.onmousemove = keyvisualMouseMove;
		keyvisual.onmouseup = keyvisualMouseUp;
		keyvisual.onmouseout = keyvisualMouseOut;
			
		// prevent broser d&d
		return false;
	}
	
	
	function isChildOf(childCandidate, container) {
		while(childCandidate) {
			if(childCandidate == container) return true;
			childCandidate = childCandidate.parentNode;
		}
		return false;
	}
	
	function keyvisualMouseOut(e) {
		if(!e) e=window.event; // IE
		
		/*
		 * check if the mouse left the keyvisual
		 * or just one of the contained elements
		 */
		targetElement = e.relatedTarget || e.toElement;
			
		if(isChildOf(targetElement,keyvisual)) {
			// the mouse did not leave the keyvisual => ignore.. 
			return;
		};
				
		keyvisualStopDrag();
		var directionStr = (currentSpeed > 0)?"Right":"Left"
		dojo.publish("/Scroller/Dragged"+directionStr);		
	}
	
	
	function keyvisualMouseUp(e) {
		keyvisualStopDrag();
		if(!e) e=window.event; // IE
		
		timeSinceLastMove = (new Date()).getTime() - lastMoveTimestamp;
		if(timeSinceLastMove > 50) {
			/*
			 the last registered mouse movement is quite long ago, so the mouse
			 must be resting and the real speed is 0
			*/
			currentSpeed = 0;
		}
		
		// start spinning if images were dragged fast enough
		if(Math.abs(currentSpeed) > spinThreshold) {
			// start spinning
			var directionStr = (currentSpeed > 0)?"Right":"Left"
			dojo.publish("/Scroller/Dragged"+directionStr);
		} 
	}
	
	
	function keyvisualStopDrag() {
		keyvisual.onmouseup = null;
		keyvisual.onmouseout = null;
		keyvisual.onmousemove = null;

		if(currentSpeed == 0) {
			currentSpeed = defaultDirection*defaultSpeed;
		}
	
		// cruise with currentSpeed
		startCruise();
	}
	
	
	
	/*
	 * CRUISE
	 */
	function cruise() {
		if(currentSpeed < 0) {
			currentSpeed = Math.min(-defaultSpeed, currentSpeed - cruiseBreakAcceleration);
		} else {
			currentSpeed = Math.max(defaultSpeed, currentSpeed + cruiseBreakAcceleration);
		}
		
		
		redraw(); 
	}
	
	function startCruise() {
		if(!cruiseTimer) {
			redraw();
			cruiseTimer = setInterval(cruise, cycleSpeed);
		}
	}

	function stopCruise() {
		window.clearInterval(cruiseTimer);
		cruiseTimer = null;
	}
}



function Tooltip(imageSrc, parentNode, showDelay, moveToPointer) {
	// create tooltip node
	var tooltipNode = document.createElement('img');
	var tooltip = this;
	var delay = showDelay;
	var timer;
	var enabled = true;
	var toPointer = moveToPointer;
	
	tooltipNode.src = imageSrc;
	tooltipNode.className = "tooltip";
	if(toPointer) {
		dojo.body().appendChild(tooltipNode);
	} else {
		parentNode.appendChild(tooltipNode);
	}
	
	// add handlers to the parent node
	parentNode.onmousemove = function(e) { 
		tooltip.enable();
		// hlau fix: tooltip stays enabled permanently
		// tooltip.showDelayed(e);
	};
	parentNode.onmouseover = function() {
		tooltip.enable();
	}
	parentNode.onmouseout = function() {
		// hlau fix: tooltip stays enabled permanently
		// tooltip.disable();
	}
	
	/**
	  * enable the tooltip
	  */
	this.enable = function(e) {
		enabled = true;
	}
	
	/**
	  * disable the tooltip
	  */
	this.disable = function(e) {
		enabled = false;
	}
	
	
	/**
	  * disable the tooltip permanently
	  */
	this.disablePermanent = function(e) {
		if(timer) {
			window.clearTimeout(timer);
			timer = null;
		}
		
		// remove handlers
		parentNode.onmousemove = null;
		this.hide();
	}
	
	
	this.showDelayed = function(e) {
		if(!e) e=window.event; // ie
		var x=e.clientX+10; 
		var y=e.clientY+10;

		if(toPointer) {
			this.setOffset(x,y);
		}
		// start timer to show tooltip
		var tooltipReference = this;
		if(!timer) {
			timer = window.setTimeout(
				function() {
					tooltipReference.show();
				},
				delay
			);			
		}

		// add handler to hide tooltip and restart timer on mouse move
		parentNode.onmousemove = function(e) {
			tooltipReference.restart(e);
		}
	}
	
	this.restart = function(e) {
		this.hide();
		
		// cancel timer, if there is one.. 
		if(timer) {
			window.clearTimeout(timer);
			timer = null;
		}

		// update position, restart
		this.showDelayed(e);
	}
	
	this.show = function() {
		if(enabled) {
			tooltipNode.style.visibility = "visible";
		} 
	}
	
	this.hide = function() {
		tooltipNode.style.visibility = "hidden";		
	}
	
	this.setOffset = function(x,y) {
		tooltipNode.style.left = x+"px";
		tooltipNode.style.top = y+"px";
	}
}




function Menu() {
	var menuItems = Array();
	var currentMenuItemI = 0;
	
	
	this.getNextURL = function() {
		var nextMenuItemI = (parseInt(currentMenuItemI)+1) % menuItems.length;
		var nextURL = (menuItems[nextMenuItemI]).href;
		return nextURL;
	}
	this.getPrevURL = function() {
		var menuItemI = (parseInt(currentMenuItemI)-1);
		if(menuItemI < 0) menuItemI = menuItems.length-1;
		var url = (menuItems[menuItemI]).href;
		return url;		
	}
	
	function getIndexByHref(href) {
		for(menuItemsI in menuItems) {
			if(menuItems[menuItemsI].href == href) {
				return menuItemsI;
			}
		}
		return null;
	}
	
	
	/*
	 * Find all product links and add onclick event handlers to them
	 */
	this.init = function() {
		var cols = dojo.byId('subSubMenu').childNodes;
		for(var colI=0; colI<cols.length; colI++) {
			links = cols[colI].childNodes;
			for(var linksI=0; linksI<links.length; linksI++) {
				productLink = links[linksI];
				if(productLink.href) {
					productLink.onclick = function() {
						this.blur();
						dojo.publish('/Menu/Clicked',[this.href]);
						return false;
					}

					menuItems.push(productLink);	
				}	
			}	
		}


		// determeni the index of the active menu item in the menuitems array
		currentMenuItemI = getIndexByHref((dojo.query('.subSubMenuItem_act')[0]).href)
	}
	
	this.setCurrent = function(url) {
		var menuItemI = getIndexByHref(url);
		var menuItem = menuItems[menuItemI];
		
		
		// switch the active menu item
		// old one gets inactive
		var currentMenuItem = menuItems[currentMenuItemI];
		if(currentMenuItem) currentMenuItem.className = "subSubMenuItem";

		// new one turns active
		if(menuItem) {
			menuItem.className = "subSubMenuItem_act";
			currentMenuItemI = menuItemI;
		}
	}	
}





function Loader() {
	var content = Array();
	var imgContainer = Array();
	var pagetitle = Array();

	function LoadJob(targetURL, callback) {
		// console.debug('Loader: LoadJob: started');
		
		var targetURL = targetURL;
		var callback = callback;
		
		var imgNodes = Array();
		var nImg2Load;
		var nImgLoaded = 0;
		
		var loadCheckTimer;
		
		
		/*
		 * get the html code of the page to load and parse it.
		 * If there is any trouble point the browser directly 
		 * to the new page (fallback)
		 */
		dojo.xhrGet({
			url: targetURL,
			load: function(data){	parse(data); },
			error: function(msg) { 
				// console.error('Loader: Loadjob: xhrGet failed. '+msg);
				window.location.href = targetURL; 
			}
		});
	
		
		/*
		 * Seperate the HTML code for the content element, title and keyvisual.
		 * preload all images comprised by the keyvisual. 
		 */
		function parse(data) {
			// console.debug('Loader: Loadjob: parser');
			
			/*
			 * Content
			 */
			var newContentHTML = data.match(/<!--TYPO3SEARCH_begin-->[\s\S]*<!--TYPO3SEARCH_end-->/);
			content[targetURL] = newContentHTML;
			
			var title = data.match(/<title>(.*)<\/title>/)[1];
			pagetitle[targetURL] = title;
			
			
			/* 
			 * Images 
			 */
			// get the image container
			var newImgContainerHTML = data.match(/<div id="initialImgContainer" class="imgContainer">([\s\S]*?)<\/div>/)[1];
			
			/*
			 *	look for 
			 *		[1] the image src 
			 * 		[2] the path of the full size image hidden in typos click-enlarge link
			 */
			var imgRegExp = (/<a href="index.php\?eID=tx_cms_showpic\&amp;file=(.*?)\&.*?".*?><img src="(.*?)".*?>/g);
			
			// preload and lightbox every image, call finish when all images are loaded
			lightboxHelper.nextGroup();
			var result;	
			while( result = imgRegExp.exec(newImgContainerHTML) ) {
				var imgSrc = result[2];
				var imgNode = document.createElement('img');
				
				// console.debug('Loader: Loadjob: Parser: creating imageNode for '+imgSrc);
				imgNode.src = imgSrc;

				lightboxHelper.addLightbox(imgNode, unescape(result[1]), title);
				imgNodes.push(imgNode);
			}
			
			// console.debug('Loader: Loadjob: Parser: '+imgNodes.length+' imageNodes created.');
			
			loadCheckTimer = window.setInterval(checkLoaded, 1000);
			checkLoaded();
		}
	
	
		// check if all the images are loaded, if so call finish()
		function checkLoaded() {
			for(var i=0; i<imgNodes.length; i++) {
				if(!imgNodes[i].complete) {
					return false;
				}
			}
			
			window.clearInterval(loadCheckTimer);			
			// console.debug('Loader: Loadjob: checkLoaded: all images loaded.');
			finish();
			return true;
		}
		
		
		/*
		 * create the new node for the keyvisual container and 
		 * finish the job by returning it and the content HTML 
		 * to the original caller
		 */
		function finish() {
			// console.debug('Loader: Loadjob: finish');
			
			var newImgContainerNode = document.createElement('div');
			newImgContainerNode.className = 'imgContainer';
			
			for(var i=0; i<imgNodes.length; i++) {
				newImgContainerNode.appendChild(imgNodes[i]);
			}
	
			imgContainer[targetURL] = newImgContainerNode;
			callback(targetURL, pagetitle[targetURL], content[targetURL], newImgContainerNode.cloneNode(true) );
		}
	}


	this.load = function(targetURL, callback) {
		// console.debug('Loader: load '+targetURL);
		
		// check if we already have the information cached
		if(imgContainer[targetURL]) {
			// yes -> deliver from cache
			// console.debug('Loader: load: page in cache, returning');
			
			callback(targetURL, pagetitle[targetURL], content[targetURL], imgContainer[targetURL].cloneNode(true) );
			return true;
		}
		
		
		// no -> load it
		new LoadJob(targetURL, callback);
		return true;
	}
}



function ContentContainer() {
	var fadeSpeed = 80;	
	var contentNode;

	this.init = function() {
		// find the content section
		contentNode = dojo.byId('content');
	}

	/* 
	 * Replace the pages content with the newly received data 
	 */	
	this.replace = function(newContentHTML) {			
		// fadeout
		var anim = dojo.fadeOut({ 
			node: "content",
			duration: fadeSpeed
		});
				
		// after fadeout is complete: replace; fadein
		dojo.connect(anim,"onEnd",function() {
			contentNode.innerHTML = newContentHTML;
			dojo.fadeIn({
				node:contentNode, 
				duration: fadeSpeed
			}).play();
		});
				
		// start replacement
		anim.play();	
	}
}

