var AJZLocations = function() {
	if(!AJZLocations.config.map || !AJZLocations.config.img) {
		throw "AJZLocations not configured!";
	}
	var preview = createPreview();
	var overlay = createOverlay();
	var visible = false;
	var eventData = {};
	var that = this; // Used to call member functions within helper functions .. ;)
	
	$A($(AJZLocations.config.map).areas).each(function(it){
		it.href="javascript:;";
		Event.observe(it, 'mouseover', function(event){
			var image = $(AJZLocations.config.img);
			var offset = image.positionedOffset();
			var scroll = image.cumulativeScrollOffset();
			var pos = image.viewportOffset();
			if(Prototype.Browser.Opera){
				pos.left -= scroll.left;
				pos.top -= scroll.top;
			}
			preview.clickPosition = { 'left': event.pointerX() - scroll.left, 'top': event.pointerY() - scroll.top };
			preview.position.left = offset.left + preview.clickPosition.left - pos.left;
			preview.position.top = offset.top + preview.clickPosition.top - pos.top;
			AJZLocations.showLocationPreview(this.title||this.alt);
		});
		Event.observe(it, 'mouseout', function(event){
			AJZLocations.hideLocationPreview(this.title||this.alt);
		});
		Event.observe(it, 'click', function(event){
			AJZLocations.showLocation(this.title||this.alt);
			return false;
		});
	});
	
	function createPreview() {
		// Create preview element ..
		var preview = new Element('div',{'id': 'preview'});
		preview.style.position = 'absolute';
		preview.setData = function(locationID) {
			var conf = AJZLocations.config.locations[locationID];
			preview.locationID = locationID;
			if(!preview.displayElements.images[locationID]){
				preview.displayElements.images[locationID] = new Element('img',{'src': conf[4]});
				preview.displayElements.images[preview.locationID].observe('load', function(){
					preview.displayElements.images[preview.locationID].orgSize =  {'width': this.width, 'height': this.height};
					preview.updatePosition();
				});
			}
			preview.appendChild(preview.displayElements.images[locationID]);
			this.updatePosition();
		}
		preview.updatePosition = function() {
			var positionX = this.position.left;
			var positionY = this.position.top;
			if(positionX && positionY) {
				var width = 0;
				var height = 0;
				if(this.displayElements.images[preview.locationID].orgSize) {
					width = this.displayElements.images[preview.locationID].orgSize.width;
					height = this.displayElements.images[preview.locationID].orgSize.height;
					if(AJZLocations.config.position) {
						var image = $(AJZLocations.config.img);
						var offset = image.positionedOffset();
						positionY = offset.top + AJZLocations.config.position.top;
						positionX = offset.left + AJZLocations.config.position.left;
					} else {
						var viewport = document.viewport.getDimensions();
						var offset = {'left': preview.clickPosition.left, 'top': preview.clickPosition.top, 'right': viewport.width-preview.clickPosition.left, 'bottom': viewport.height-preview.clickPosition.top, }
						if(offset.bottom>height+70){
							positionY += 50;
							positionX = this.setXOffset(positionX, width, offset);
						} else if(offset.top>height+70){
							positionY = positionY - 50 - height;
							positionX = this.setXOffset(positionX, width, offset);
						} else if(offset.right>width+70){
							positionX += 50;
							positionY -= height/2;
						} else if(offset.left>width+70){
							positionX = positionX - width - 50;
							positionY -= height/2;
						} else {
							//no free place -> resize?
							positionX -= width/2;
							positionY += 50;
						}
					}
					this.show();
				} else {
					this.hide();
				}
				this.setStyle({
				  'left': positionX+'px',
				  'top': positionY+'px',
				  'width': width+'px',
				  'height': height+'px'
				});
			} else {
				this.hide();
			}
		}
		preview.setXOffset = function(positionX, width, offset){
			if(offset.left<width/2 && offset.right>width+20){
			} else if(offset.left<width && offset.right>width/2+20){
				positionX -= width/2;
			} else if(offset.left>width+20 && offset.right<width/2) {
				positionX -= width;
			} else {
				positionX -= width/2;
			}
			return positionX;
		}
		preview.position = {};
		preview.displayElements = {};
//		preview.displayElements.title = new Element('span').addClassName('title').update('title');
//		preview.appendChild(preview.displayElements.title);

		preview.displayElements.images = [];
		return preview;
	}
	
	function createOverlay() {
		// Create content element ..
		var content = new Element('div',{'id': 'overlay_content', 'class': 'locations'});
		
		var closeLink = new Element('a',{'href': 'JavaScript:;', 'title': 'Close'});
		closeLink.addClassName('close_link');
		closeLink.appendChild(new Element('span').update('X'));
		closeLink.observe('click', function(e) {
			that.setVisible(false);
			Event.stop(e);
		});
		content.appendChild(closeLink);
		
		// Create Info Container ..
		var infoContainer = createInfoContainer();
		content.appendChild(infoContainer);
		// Create Navigation ..
		var navigation = createNavigation();
		content.appendChild(navigation);
		// Create overlay and add content ..
		var overlay = new Element('div',{'id': 'overlay'});
		overlay.updatePosition = function() {
			// Get "Window"-height/width ..
			var vpHeight = overlay.getHeight();
			var vpWidth = overlay.getWidth();
			// Calculate new size for overlay content ..
			var maxHeight = 600;
			var maxWidth = 800;
			var newHeight = vpHeight>maxHeight ? maxHeight : vpHeight;
			var newWidth = vpWidth>maxWidth ? maxWidth : vpWidth;
			content.style.height = newHeight + 'px';
			content.style.width = newWidth + 'px';
			content.style.marginTop = Math.round((vpHeight - newHeight) / 2) + 'px';
			content.style.marginLeft = Math.round((vpWidth - newWidth) / 2) + 'px';
			// Scale content ..
			overlay.info_container.updateSize();
		}
		overlay.setData = function(locationId) {
			this.info_container.setInfos(AJZLocations.config.locations[locationId]);
			this.navigation.update(locationId);
		}
		overlay.appendChild(content);
		// Create "shortcuts" ..
		overlay.content_panel = content;
		overlay.info_container = infoContainer;
		overlay.navigation = navigation;
		return overlay;
	}
	
	function createInfoContainer() {
		var infoContainer = new Element('div').addClassName('location_container');
//		var infoContainer = new Element('div').addClassName('info_container');
//		infoContainer.setAttribute('style', 'left: 30px; padding-left: 0px;');
		infoContainer.setInfos = function(data) {
			this.style.visibility = 'hidden';
			this.removeAll();
			this.displayElements.colLeft.removeAll();
			this.displayElements.colMiddle.removeAll();
			this.displayElements.colRight.removeAll();
			if(data){
				//update and append title
				this.displayElements.title.update(data[0]);

				if(data[2].length>0){
					//update links
//					var links = new Element('ul');
					this.displayElements.links.removeAll();
//					data[2].each();
					var c = data[2].length;
					for(var i=0; i<c; i++) {
//						links.appendChild(new Element('li').update(data[2][i]));
						this.displayElements.links.appendChild(new Element('li').update(data[2][i]));
					}
//					this.displayElements.links.removeAll();
//					this.displayElements.links.appendChild(links);
					
					if(data[3]) {
						//append image
						this.appendChild(this.displayElements.image);
					}
					this.displayElements.colLeft.appendChild(this.displayElements.title);
					//append links to left col
					this.displayElements.colMiddle.appendChild(this.displayElements.links);
				} else if(data[3]) {
					//append image to left col
					this.displayElements.colLeft.appendChild(this.displayElements.image);
					this.displayElements.colRight.appendChild(this.displayElements.title);
				}
				
				this.loadimage.removeAttribute('width',0);
				this.loadimage.removeAttribute('height',0);
				this.loadimage.removeAttribute('src', 0);
				this.displayElements.image.setAttribute('width',0);
				this.displayElements.image.setAttribute('height',0);
				this.displayElements.image.removeAttribute('src', 0);
				this.displayElements.image.setAttribute('src','about:blank');
				if(data[3]) {
					//update image
					this.loadimage.setAttribute('src', data[3]);
				}
				
				this.removeClassName('h_layout');
				this.removeClassName('v_layout');
				
				//update and append text
				this.displayElements.text.update(data[1]);
				if(this.displayElements.colLeft.childNodes.length==0){
					this.appendChild(this.displayElements.text);
				} else {
					this.displayElements.colRight.appendChild(this.displayElements.text);
					this.appendChild(this.displayElements.colLeft);
					if(this.displayElements.colMiddle.childNodes.length>0){
						this.addClassName('h_layout');
						this.appendChild(this.displayElements.colMiddle);
					} else {
						this.addClassName('v_layout');
					}
					this.appendChild(this.displayElements.colRight);
				}
				this.updateSize();
			}
			this.style.visibility = '';
		}
		infoContainer.updateSize = function() {
			this.displayElements.image.src = this.loadimage.src;
			this.updateImageSize(this.displayElements.image);
		}
		infoContainer.updateImageSize = function(img) {
			if(img.src) {
				// Update image size ..
				if(this.displayElements.colMiddle.childNodes.length>0){
					img.resize(this.getWidth(), 2000);
				} else {
					img.resize(this.getWidth()/2, this.getHeight());
				}
			}
		}
		// Create & Add Texts/Info ..
		infoContainer.displayElements = {};
		infoContainer.displayElements.title = new Element('h1');
		
		infoContainer.loadimage = new Element('img');
		infoContainer.loadimage.observe('load', function() {
			if(this.width || this.height){
				infoContainer.displayElements.image.originalSize[this.src] = 
				this.originalSize[this.src] = {'width': this.width, 'height': this.height};
				infoContainer.updateImageSize(this);
				infoContainer.displayElements.image.style.visibility = 'visible';
				infoContainer.displayElements.image.src = this.src;
				infoContainer.displayElements.image.width = this.width;
				infoContainer.displayElements.image.height = this.height;
				infoContainer.displayElements.image.style.visibility = '';
			} else {
				infoContainer.displayElements.image.originalSize = {};
			}
		});
		infoContainer.displayElements.image = new Element('img').addClassName('image');
		infoContainer.loadimage.originalSize = 
		infoContainer.displayElements.image.originalSize = {};
		infoContainer.loadimage.resize =
		infoContainer.displayElements.image.resize = function resizeImageFnc(maxWidth, maxHeight) {
			if(this.originalSize && this.originalSize[this.src]) {
				var width = this.originalSize[this.src].width;
				var height = this.originalSize[this.src].height;
				var destWidth = maxWidth > width ? width : maxWidth-20;
				var destHeight = maxHeight > height ? height : maxHeight-20;
				var factor = Math.min(destHeight / height, destWidth / width);
				this.width = Math.round(width * factor);
				this.height = Math.round(height * factor);
			}
		}
		infoContainer.displayElements.text = new Element('div').addClassName('text');
		infoContainer.displayElements.links = new Element('ul').addClassName('links');
		infoContainer.displayElements.colLeft = new Element('div').addClassName('colLeft');
		infoContainer.displayElements.colMiddle = new Element('div').addClassName('colMiddle');
		infoContainer.displayElements.colRight = new Element('div').addClassName('colRight');
		infoContainer.removeAll = infoContainer.displayElements.links.removeAll = infoContainer.displayElements.colLeft.removeAll =
		infoContainer.displayElements.colMiddle.removeAll = infoContainer.displayElements.colRight.removeAll = function() {
			var next, toRemove = this.firstChild;
			while(toRemove) {
				next = toRemove.nextSibling;
				this.removeChild(toRemove);
				toRemove = next;
			}
		}
		return infoContainer;
	}
	
	function createNavigation() {
		var navigation = new Element('div');
		navigation.className = 'navigation';
		navigation.backLink = new Element('a',{'href': 'JavaScript:;'}).addClassName('prev_link').update('&lt;&lt;');
		navigation.appendChild(navigation.backLink);
		navigation.nextLink = new Element('a',{'href': 'JavaScript:;'}).addClassName('next_link').update('&gt;&gt;');
		navigation.appendChild(navigation.nextLink);
		
		navigation.backLink.observe('click', update);
		navigation.nextLink.observe('click', update);
		
		function update() {
			// 'this' refers to the element, the action was invoked (-> the link) ..
			if(this.current_locationId>=0) {
				that.loadLocation(this.current_locationId);
			}
			this.blur();
		}
		
		navigation.update = function(locationId) {
			if(locationId>0) {
				this.setBackLink(locationId-1);
			} else {
				this.setBackLink(-1);
			}
			if(locationId<AJZLocations.config.locations.length-1) {
				this.setNextLink(locationId+1);
			} else {
				this.setNextLink(-1);
			}
		}
		navigation.setBackLink = function(locationId) {
			updateLink(this.backLink, locationId);
		}
		navigation.setNextLink = function(locationId) {
			updateLink(this.nextLink, locationId);
		}
		
		function updateLink(link, locationId) {
			link.current_locationId = locationId;
			if(!AJZLocations.config.locations[locationId]) {
				link.title = '';
				link.style.visibility = 'hidden';
			} else {
				link.title = AJZLocations.config.locations[locationId][0];
				link.style.visibility = 'visible';
			}
		}
		
		return navigation;
	}
	
	this.loadLocation = function(locationID) {
		if(locationID>=0) {
			overlay.setData(locationID);
		}
	}
	this.loadLocationPreview = function(locationID){
		if(	locationID>=0 &&
			preview.locationName != AJZLocations.config.locations[locationID][0]	) {
			preview.locationName = AJZLocations.config.locations[locationID][0];
			$(AJZLocations.config.parent).appendChild(preview);
			preview.setData(locationID);
		}
	}
	this.hideLocationPreview = function(locationName) {
		if(preview.locationName==locationName){
			preview.locationName = '';
			preview.removeChild(preview.lastChild);
			$(AJZLocations.config.parent).removeChild(preview);
		}
	}
	
	this.setVisible = function(state) {
		if(visible!=state) {
			visible = state;
			if(visible) {
				// Add to document body ..
				document.body.appendChild(overlay);
				overlay.updatePosition();
				// Add listener for window resizing ..
				Event.observe(window, 'resize', resizeCallback);
				// Add click-listener observing clicks in background ..
				Event.observe(document, 'mousedown', closeOverlay);
			} else {
				Event.stopObserving(document, 'mousedown', closeOverlay);
				Event.stopObserving(window, 'resize', resizeCallback);
				document.body.removeChild(overlay);
				window.location.hash = '#';
			}
		}
	}
	
	function resizeCallback() {
		if(visible) {
			overlay.updatePosition();
		}
	}
	
	function closeOverlay(e) {
		var element = Event.element(e);
		var current = element;
		if(element && element.tagName == 'HTML') {
			// If user clicks on scrollbars -> don't hide overlay ..
			return;
		}
		while(current) {
			if(current==overlay.content_panel) {
				// Click was on content panel ...
				return;
			}
			current = current.parentNode
		}
		// Consume event / stop further propagation ...
		Event.stop(e);
		that.setVisible(false);
	}
}

AJZLocations.showLocation = function(locationName) {
	if(this.instance) {
		var c = AJZLocations.config.locations.length;
		for(var i=0; i<c; i++){
			if(AJZLocations.config.locations[i][0]==locationName){
				this.instance.setVisible(true);
				this.instance.loadLocation(i);
				return;
			}
		}
	}
}

AJZLocations.showLocationPreview = function(locationName) {
	if(this.instance) {
		var c = AJZLocations.config.locations.length;
		for(var i=0; i<c; i++){
			if(AJZLocations.config.locations[i][0]==locationName){
				this.instance.loadLocationPreview(i);
				return;
			}
		}
	}
}

AJZLocations.hideLocationPreview = function(locationName) {
	if(this.instance) {
		this.instance.hideLocationPreview(locationName);
	}
}

AJZLocations.config = {};

// Attach onload handler ...
Event.observe(window, 'load', function() {
	AJZLocations.instance = new AJZLocations();
});
