/** 
	COPYRIGHT QRED SOLUTIONS 2007-
	DO NOT EVEN CONSIDER COPYING!

 */

/* PeriodicalExecuter(takes millisecs) */

PeriodicalExecuterToggled = Class.create();
Object.extend(Object.extend(PeriodicalExecuterToggled.prototype, PeriodicalExecuter.prototype),
{
	initialize: function(callback, frequency) {
		this.callback = callback;
		this.frequency = frequency;
		this.currentlyExecuting = false;
		this.timer = null;
		this.registerCallback();
	},
	
	registerCallback: function() {
		this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency);
	},
	
	clearCallback: function() {
		clearInterval(this.timer);
		this.timer = null;
	},
	
	setFrequency: function(f) {
		this.frequency = f;
		if (this.timer != null) {
			this.clearCallback();
			this.registerCallback();
		}
	}
 });


Object.extend(Event, {

	wheel: function (event){
		var delta = 0;
		
		if (!event) event = window.event;
		
		if (event.wheelDelta) {
			delta = event.wheelDelta/120;
		
			if (window.opera)
				delta = -delta;
		
		} else if (event.detail) {
			delta = -event.detail/3;
		}
		return Math.round(delta); //Safari Round
	}

});

var QredMap = Class.create();

QredMap.prototype={

	initialize: function()
	{
		this.mapDrag=false;
		this.eventMouseMove=this.mouseMove.bindAsEventListener(this);
		this.eventMouseDown=this.mouseDown.bindAsEventListener(this);
		this.eventMouseUp=this.mouseUp.bindAsEventListener(this);
		this.eventMouseWheel=this.mouseWheel.bindAsEventListener(this);

	//	this.eventMouseWheel=this.mouseWheel.bindAsEventListener(this);

		this.pngFixOn=this._pngFixOn.bind(this);


		this.mapSizeX=3072;
		this.mapSizeY=3072;

		this.isIE=/MSIE/.test(navigator.userAgent);

		this.timerCheck=true;
		this.infoBubble=false;

		this.iePngFix=false;
		this.originX=0;
		this.originY=0;

		this.staticPath='http://www2.kerimaa.fi/mapfiles/';

		this.marking=false;
		this.slider=false;

		this.dirtyMap=true;			
		this.loadedImages=new Array();
		this.htmlStuff=Array();

		this.outerZoomLevel=1;

		this.zoomLevelArray=Array();
	},


	setZoomArray: function(arr)
	{
		this.zoomLevelArray=arr;
	},
	

	hideInfo: function()
	{
		this.infoBubble=false;
		$('infoBubble').style.display='none';
	},


	loadInfo: function(str)
	{
		this.infoBubble=true;			// Render bubble on mouseover
		$('infoBubble').style.left=(this.mouseX+6)+'px';	// Initial coords
		$('infoBubble').style.top=(this.mouseY+6)+'px';
		$('infoBubble').innerHTML=str;
		$('infoBubble').style.display='block';
	},


	addLinkCircle: function(x, y, text)
	{
		this.htmlStuff.push(new Array(x, y, text));
	},


	drawStuffLayer: function()
	{
		$('stuffLayer').innerHTML='';
		var index, value;
		var x, y;	

		for (index=0; index < this.htmlStuff.length; ++index) {
			value=this.htmlStuff[index];
		
			/* Map position to layer position 
			   1024 ==> 50% zoom, 256 256 256 256 */	
			
			x=(value[0]/this.mapSizeX*this.mapWidth) - (this.blockOffsetX*256) + this.imageOffsetX-12;	 
			y=(value[1]/this.mapSizeY*this.mapHeight)- (this.blockOffsetY*256) + this.imageOffsetY-12;
			
			var html='<div style="width: 160px; position: absolute; top: '+y+'px; left: '+x+'px;">'+value[2]+'</div';

			new Insertion.Bottom('stuffLayer', html);			

		}
		this.pngFix();		// Fix ie png problems 
	},


	setZoomLevel: function(outerZoomLevel)
	{	
		/* 1. UI zoomlevel
		   2. Map zoom level */
		this.hideInfo();			// Remove info bubble 

		if (outerZoomLevel<1) {
			outerZoomLevel=1;
		} else if (outerZoomLevel>=this.zoomLevelArray.length) {
			outerZoomLevel=this.zoomLevelArray.length;			
		}

		this.outerZoomLevel=outerZoomLevel;

		/* Do mappings */
		zoomLevel=this.zoomLevelArray[outerZoomLevel-1];

		this.debug(this.zoomLevel);

		this.zoomLevel=zoomLevel;
		this.mulX=1/(this.zoomLevel/100);
		this.mulY=1/(this.zoomLevel/100);

		this.mapWidth=(zoomLevel/100)*this.mapSizeX;
		this.mapHeight=(zoomLevel/100)*this.mapSizeY;	

		this.blockSizeRealX=this.mapSizeX*(zoomLevel/100);
		this.blockSizeRealY=this.mapSizeY*(zoomLevel/100);
	},


	zoom: function(zoomlevel)
	{
		this.timerCheck=false;
		this.drawSlider();
		this.setZoomLevel(zoomlevel);
		this.debug(this.originX+" "+this.originY);
		this.setCenter(this.originX, this.originY);
	},


	getZoomLevel: function()
	{
		return this.outerZoomLevel;
	},


	findPos: function(obj)
	{
		var curleft = curtop = 0;
		if (obj.offsetParent) {
			curleft = obj.offsetLeft
			curtop = obj.offsetTop
			while (obj = obj.offsetParent) {
				curleft += obj.offsetLeft
				curtop += obj.offsetTop
			}
		}
		return [curleft,curtop];
	},


	drawSlider: function()
	{
		/* Calc position */
		var height=100;
		var y;
		y=(this.outerZoomLevel-1)*8;

		$('zoomSlider').style.top=2+y+"px";
	},


	sliderUpdate: function()
	{
		var y;

		pos=this.findPos($('map'));
		mouse_pos_y=(this.mouseY-pos[1]);

		y=mouse_pos_y;

		if (y<3) {
			y=3;
		} else if (y>92) {
			y=92;
		}

		$('zoomSlider').style.top=y+'px';
	},


	sliderMouseDown: function(event)
	{
		this.startX=(this.mouseX);		// INITIAL COORDS 
		this.startY=(this.mouseY);	
		
		this.slider=true;
		Event.stop(event);
	},
	

	sliderMouseUp: function(event)
	{
		pos=this.findPos($('map'));
		mouse_pos_y=(this.mouseY-pos[1]);

		var z=Math.round((mouse_pos_y)/7);
		var vp;

		vp=this.viewPortCoordsToMapCoords(256, 256);

		this.setCenter(vp[0], vp[1]);

		this.debug(z);
		this.zoom(z);
		this.drawSlider();
		this.slider=false;			// Stop observing 
	},


	initMap: function()
	{
		Event.observe('zoomSlider', "mousedown", this.sliderMouseDown.bindAsEventListener(this) );
		new PeriodicalExecuterToggled(this.mapCheckEvent.bind(this), 100);
		this.timerCheck=true;		
	},


	mapCheckEvent: function()
	{
		if (this.timerCheck && this.dirtyMap) {
			this.reloadMap();
		}
	},


	mouseWheel: function(event)
	{
		this.timerCheck=false;
		var d=(Event.wheel(event));
		var mouse_pos_x, mouse_pos_y;

		var mappos=this.mouseCoordsToMapCoords();	// Current map pos 
		var dx, dy;
	
		this.cleanRegisters();

		pos=this.findPos($('map'));

		mouse_pos_x=(this.mouseX-pos[0]);
		mouse_pos_y=(this.mouseY-pos[1]);

		/* Compensate from viewport origo to mouse position => Zoom origo will be mouse centered */
		if (d>0) {
			this.zoomAdd();
		} else {
			this.zoomSub();
		}

		dx=mappos[0]+(-(mouse_pos_x-256)*this.mulX);
		dy=mappos[1]+(-(mouse_pos_y-256)*this.mulY);
	
		this.setCenter(Math.round(dx), Math.round(dy));
		this.cleanMap();
		Event.stop(event);
	},


	setCenter: function(x, y)
	{
		/* this is the new origin.  we know that blocks are loaded
			around the viewport. Calculate viewport offset
			-to real map.
			*/
		/* Center of viewport should be
			256, 256 
			1024, 1024 => Center of the map
		*/

		this.originX=x;			// Store current origin
		this.originY=y;

		this.timerCheck=false;		
		this.cleanRegisters();

		var vx, vy, rbx, rby, dx, dy;

		var vx=x/this.mapSizeX*(this.mapWidth/256);
 		var vy=y/this.mapSizeY*(this.mapWidth/256);

		var vpx=Math.floor(vx);
 		var vpy=Math.floor(vy);

		ltx=vpx-1;		// Specify drawing area 
		lty=vpy-1;

		rbx=vpx+1;
 		rby=vpy+1;

		this.blockOffsetX=Math.floor(vx);			// Where to draw first viewport blocks
   		this.blockOffsetY=Math.floor(vy);

		dx=vx-vpx;
		dy=vy-vpy;

		dx=1-dx;
		dy=1-dy;

		this.imageOffsetX=Math.round(((dx))*256); 
		this.imageOffsetY=Math.round(((dy))*256); 	

		for(y=lty;y<=rby;y++) {
			for(x=ltx;x<=rbx;x++) {
				this.loadBlock(x, y);
			}
		}
		this.drawSlider();
 	
		this.timerCheck=true;	
		this.drawStuffLayer();
	},


	mouseMove: function(event)
	{		
		this.mouseX=Event.pointerX(event);
		this.mouseY=Event.pointerY(event);
			

		/* Check out of bounds */
		if (!Position.within($('map'), this.mouseX, this.mouseY)) {
			map.hideInfo();
		}

		if (this.isIE) {
			this.mouseY-=4;
			this.mouseX-=3;
		}

		if (this.infoBubble) {
			$('infoBubble').style.left=(this.mouseX+6)+'px';
			$('infoBubble').style.top=(this.mouseY+6)+'px';
		}

		if (this.slider) {
			this.sliderUpdate();
		} else if (this.mapDrag) {
			this.dirtyMap=true;						// We should reload new blocks to map
			var x=(this.mouseX-this.startX); 		
			var y=(this.mouseY-this.startY);		
							
			$('mapDrag').style.left=this.mapDragX+x+'px';
			$('mapDrag').style.top=this.mapDragY+y+'px';
		}
		this.updateDataInfo();
		Event.stop(event);
	},


	mouseCoordsToMapCoords: function()
	{
		var mouse_pos_x, mouse_pos_y, x, y, ltx, lty, norm_x, norm_y;

		pos=this.findPos($('map'));
	
		mouse_pos_x=(this.mouseX-pos[0]);
		mouse_pos_y=(this.mouseY-pos[1]);

		x=-parseInt($('mapDrag').style.left);
		y=-parseInt($('mapDrag').style.top);

		/* In which block are we in... */
		ltx=(256*this.blockOffsetX-this.imageOffsetX+mouse_pos_x+x)/256;	
 		lty=(256*this.blockOffsetY-this.imageOffsetY+mouse_pos_y+y)/256;

		norm_x=ltx/ (this.mapWidth/256);
		norm_y=lty/(this.mapHeight/256);

		/* If we now in which block we are on */
 		//this.zoomCenter=new Array( norm_x);
		var new_x=Math.round(norm_x*this.mapSizeX);
		var new_y=Math.round(norm_y*this.mapSizeY);

		return new Array(new_x, new_y);
	},
	

	viewPortCoordsToMapCoords: function(vx, vy)
	{
		var x, y, ltx, lty, norm_x, norm_y;

		pos=this.findPos($('map'));

		x=-parseInt($('mapDrag').style.left);
		y=-parseInt($('mapDrag').style.top);

		/* In which block are we in... */
		ltx=(256*this.blockOffsetX-this.imageOffsetX+vx+x)/256;	
 		lty=(256*this.blockOffsetY-this.imageOffsetY+vy+y)/256;

		norm_x=ltx/ (this.mapWidth/256);
		norm_y=lty/(this.mapHeight/256);

		/* If we now in which block we are on */
 		//this.zoomCenter=new Array( norm_x);
		var new_x=Math.round(norm_x*this.mapSizeX);
		var new_y=Math.round(norm_y*this.mapSizeY);

		return new Array(new_x, new_y);
	},


	updateDataInfo: function()
	{
		//pos=this.mouseCoordsToMapCoords();
	},


	mouseDown: function(event)
	{
		if (this.marking) {

			/* Get coords */
			if (this.ieIe) {
			
			} else {
				$('mapDrag').style.cursor='-moz-grab';
			}

			coords=this.mouseCoordsToMapCoords();
			Event.stop(event);

			this.addLinkCircle(coords[0], coords[1],'<div style="border: 1px solid #f00; width: 50px; height: 50px">as</div>')

			this.drawStuffLayer();
			this.setCallback(coords);
			this.marking=false;
			return;
		}

		this.startX=(this.mouseX);		// INITIAL COORDS 
		this.startY=(this.mouseY);	
		
		this.mapDrag=true;	
	
		if (this.isIe) {
		
		} else {
			$('mapDrag').style.cursor='-moz-grabbing';
		}
		this.mapDragX=parseInt($('mapDrag').style.left);
		this.mapDragY=parseInt($('mapDrag').style.top);
	
		Event.stop(event);
	},


	reloadMap: function()
	{		
		var x=parseInt($('mapDrag').style.left);		// Dragged location 
		var y=parseInt($('mapDrag').style.top);				
	
		var rx=-x;
		var ry=-y;				
	
		/* Check 2 corner points */
		var dist=200;

		var smallest=new Array(-dist-this.imageOffsetX, -dist-this.imageOffsetY);		
		var largest=new Array((512+dist)-this.imageOffsetX, (512+dist)-this.imageOffsetY);

		/* Which map images to load from table  */
		ltx=this.blockOffsetX+Math.floor((rx+smallest[0])/256);
 		lty=this.blockOffsetY+Math.floor((ry+smallest[1])/256);
		
		rbx=this.blockOffsetX+Math.floor((rx+largest[0])/256);
 		rby=this.blockOffsetY+Math.floor((ry+largest[1])/256);

		for(y=lty;y<rby;y++) {
			for(x=ltx;x<rbx;x++) {
				this.loadBlock(x, y);
			}
		}

		this.cleanMap(ltx, lty, rbx, rby);
		this.dirtyMap=false;
	},


	cleanMap: function(ltx, lty, rbx, rby)
	{	
		for (index=0; index < this.loadedImages.length; ++index) {
			value=this.loadedImages[index];
			if (((value[0]<ltx) || (value[1]<lty)) || ((value[0]>rbx) || (value[1]>rby))) {
				Element.remove('block_'+value[0]+'_'+value[1]);
				this.loadedImages.splice(index, 1);
			}
		}

		/* Remove transparents */
		var mapimages=$('mapImages');
		var images=$A(mapimages.getElementsByTagName('img'));

		images.findAll( function(img) {
			var imgName = img.src;	
			if (imgName.substring(imgName.length-15, imgName.length) == "transparent.png") {
				Element.remove(img);
			}
		});
		this.updateDataInfo();
	},


	getAndSetCoords: function(callback)	
	{
		this.setCallback=callback;
		this.marking=true;
		$('mapDrag').style.cursor='crosshair';
	},


	loadBlock: function(block_x, block_y)
	{
		var pos_x, pos_y;

		/* If image is out of block count */
		var block_count=Math.ceil(this.mapWidth/256)-1;

		if (block_x<0 || block_y<0) {
			return;
		} else if (block_x > block_count || block_y > block_count) {
			return;
		}

		// Is block already loaded? 
		if (this.checkLoaded(block_x, block_y)) {	
			return;
		}

		pos_x=(block_x-this.blockOffsetX)*256+this.imageOffsetX;	 
		pos_y=(block_y-this.blockOffsetY)*256+this.imageOffsetY; 
	
		var truesrc=this.staticPath+''+this.zoomLevel+'-'+block_y+'-'+block_x+'.png';

		var html='<img id="block_'+block_x+'_'+ block_y+'" src="'+truesrc+'" style="width: 256px; height: 256px; position: absolute; top: '+(pos_y)+'px; left: '+(pos_x)+'px;" />';

		// Check if element is already in the field 
		var el=$('block_'+block_x+'_'+block_y);
		
		if (el!=null) {					// Element exists 
			el.style.left=pos_x+'px';
			el.style.top=pos_y+'px';	
			el.src=truesrc;	
		} else {
			new Insertion.Bottom('mapImages', html);
		}

		/* Load real block now :) */
		$('block_'+block_x+'_'+ block_y).src=truesrc;
		this.markLoaded(block_x, block_y);
	},


	checkLoaded: function(x, y)
	{
		var loaded=false;
		var index, value;
		var ret=false;	

		for (index=0; index < this.loadedImages.length; ++index) {
			value=this.loadedImages[index];
			if ((value[0]==x) && (value[1]==y)) {
				ret=true;
			}
		}
		return ret;
	},


	markLoaded: function(x, y)
	{
		this.loadedImages.push(new Array(x, y));
	},


	debug: function(str)
	{
 	//	$('debug').innerHTML+=str+'<br>';
	},


	mouseUp: function(event)
	{
		if (this.mapDrag) {
			this.mapDrag=false;
			$('mapDrag').style.cursor='-moz-grab';
		} else if (this.slider) {
			this.sliderMouseUp();
		}
		Event.stop(event);
	},

	
	zoomAdd: function()
	{
		this.setZoomLevel(this.getZoomLevel()-1);
	},


	zoomSub: function()
	{
		this.setZoomLevel(this.getZoomLevel()+1);
	},


	cleanUp: function()
	{	
		this.timerCheck=false;
		this.cleanRegisters();
		this.reloadMap();			
		this.timerCheck=true;					
	},


	cleanRegisters: function()
	{
		this.loadedImages=new Array();			// Remove images 
	//	$('mapImages').innerHTML='';			// 
		this.makeMapTransparent();
		$('mapDrag').style.top='0px';			// Reset drag layer 
		$('mapDrag').style.left='0px';			
	},

	
	makeMapTransparent: function()
	{
		var mapimages=$('mapImages');
		var images=$A(mapimages.getElementsByTagName('img'));

		images.findAll( function(img) {
			img.src='/gfx/transparent.png';
		});
	},



	pngFix: function()
	{
		if (!this.iePngFix)
			return;

		var arVersion = navigator.appVersion.split("MSIE")
		var version = parseFloat(arVersion[1])
	
		if ((version >= 5.5) && (document.body.filters)) {
		
			var sl=$('stuffLayer');
			var images=$A(sl.getElementsByTagName('img'));
	
			images.findAll( function(img){
			
		
				var imgName = img.src.toUpperCase()
	
				if (imgName.substring(imgName.length-3, imgName.length) == "PNG") {
					var imgID = (img.id) ? "id='" + img.id + "' " : ""
					var imgClass = (img.className) ? "class='" + img.className + "' " : ""
					var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
					var imgStyle = "display:inline-block;" + img.style.cssText 
					if (img.align == "left") imgStyle = "float:left;" + imgStyle
					if (img.align == "right") imgStyle = "float:right;" + imgStyle
					if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
					var strNewHTML = "<span " + imgID + imgClass + imgTitle
					+ " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
					+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
					+ "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>" 
					img.outerHTML = strNewHTML;
				}
			});
		}

	},

	_pngFixOn: function()
	{
		this.iePngFix=true;
		this.pngFix();
	}
}

map=new QredMap();

