function freevolution(parentnode,ajaxhandler){
	// dom nodes for easy access.
	if(ajaxhandler=='undefined'){
		alert('setup an ajax handler first');
		return false;
	}
	this.ajaxhandler=ajaxhandler;
	this.backgroundpath = '../tilegen/';
	this.objectpath ='../images/objects/';
	this.usetransparancy=true;
	this.watertransparancy=true;
	this.quality='medium';
	this.tiles=new Array();
	this.planes=new Array();
	
	// viewport vars
	this.overlap=new Array(32,32,32,32); // margin like tiles/css (north-east-south-west)
	this.viewport=new Array(); // startX,endX,startY,endY

	//scroll options
	this.scrollDirection=null;
	this.scrollby=3;
	this.scrolltime=100;

	//mouse handler vars
	this.cursorover=new Array();
	this.clickedtile=new Array();

	// mouse handling, can we move the cursor, or is a move pending?
	this.check_cursor=true;
	
	// drag/click objects
	this.clickedtile;
	this.dragObj=new Object;
	
	// menu vars.
	this.menutimers=new Array();
	
	if(!parentnode){
		this.parentnode=document.body;
	} else {
		this.parentnode=parentnode;
	}
	this.clientsize=new Array(parseInt(this.parentnode.style.width),parseInt(this.parentnode.style.height));
	
	// enable scroll buttons
	this.scrollgui=true;
	var parent=this;	
}

function selectwindow(parentObj,
			title,
			question,
			options,
			targetobject,
			targetfunction){
	var filler=document.createElement('div');
	filler.style.zIndex=300000; // waaaay on top
	setopacity(filler,'60');
	filler.id='WindowModalForcer';
	
	var content='<strong>'+title+'</strong><br /><br />'+question+'<br />';
	var contentbox=document.createElement('div');
	var form=document.createElement('form');
	
	contentbox.className='alertbox';
	contentbox.id='WindowModalForcerAlert';
	contentbox.innerHTML=content;
	var list=document.createElement('ul');
	var labels=new Array();
	var inputs=new Array();
	var optionsboxes=new Array();
	for(var i=0;i<options.length;i++){
		optionsboxes[i]=document.createElement('li');
		labels[i]=document.createElement('label');
		labels[i].appendChild(document.createTextNode(options[i]));
		
		inputs[i]=document.createElement('input');
		inputs[i].id="alert_id_"+i;
		labels[i].htmlFor="alert_id_"+i;
		inputs[i].type="radio";
		inputs[i].name="modalalert";
		inputs[i].value=options[i];
		inputs[i].onchange=function(){
			if(this.checked==true){
				//selectedvalue=this.value;
				targetobject.quality=this.value;
			}
		}
		optionsboxes[i].appendChild(labels[i]);
		optionsboxes[i].appendChild(inputs[i]);
		list.appendChild(optionsboxes[i]);
	}
	form.appendChild(list);
	
	var confirmbutton=document.createElement('input');
	confirmbutton.id='modalalertconfirmbutton';
	confirmbutton.value='Select';
	confirmbutton.type='button';
	
	confirmbutton.onclick=createModalOnclickHandler(parentObj,targetobject, targetfunction);
		
	form.appendChild(confirmbutton);
	contentbox.appendChild(form);
	parentObj.appendChild(filler);
	parentObj.appendChild(contentbox);
	contentbox.style.left=((window.innerWidth-contentbox.offsetWidth)/2)+'px';
	contentbox.style.zIndex=filler.style.zIndex+1;
}

function createModalOnclickHandler(parentObj,targetobj, targetfunction){
	return function(){
		// remove the background and foreground modal windows from parentObj
		parentObj.removeChild(document.getElementById('WindowModalForcer'));
		parentObj.removeChild(document.getElementById('WindowModalForcerAlert'));
		targetfunction.call(targetobj,null);
	}
}

freevolution.prototype =
{
	//gets settings from the selected quality setting
	getsetting:function (quality,setting){
		//alert(setting+"for"+quality);
		if(!settings[quality] || !settings[quality][setting]){
			//alert("returning:"+settings['default'][setting]);
			return settings['default'][setting];
		} else {
			//alert("returning:"+settings[quality][setting]);
			return settings[quality][setting];	
		}
	},
	
	initmap: function(){
		
		if(this.quality!='low' && this.quality!='medium' && this.quality!='high'){
			this.quality='high';
		}
		//setCookie('quality',this.quality);
		
		// set up the gui objects
		this.cursor=document.createElement('img');
		this.cursor.className='cursor';
		this.cursor.src=this.backgroundpath+"cursor/0-0-0-0.png";	
		
		this.watercursor=document.createElement('img');
		this.watercursor.src=this.backgroundpath+"cursor/0-0-0-0.png"; 
		this.watercursor.className='watercursor';
		
		// attach handlers	
		this.cursor.onmousemove=this.cursor.onmouseover=attachEventHandler(this, "checkcursor");
		//attachEventHandler(this, "checkcursor");
		var parent=this;
		this.cursor.onmousedown=function(event) {
			parent.dragObj.elNode = this;
			// If this is a text node, use its parent element. // commented cause there are no text nodes in freevolution
			//if (parent.dragObj.elNode.nodeType == 3)
			//	parent.dragObj.elNode = parent.dragObj.elNode.parentNode;
			// Get cursor position with respect to the page 
			
			// Save starting positions of cursor and element.
			parent.dragObj.clickY = event.layerY;
			parent.dragObj.elStartTop   = parseInt(parent.dragObj.elNode.style.top,10);
			
			if (isNaN(parent.dragObj.elStartTop)) parent.dragObj.elStartTop  = 0;
			
			// Capture mousemove and mouseup events on the page. 
			parent.drag=true;
			this.onmousemove=attachEventHandler(parent, "dragGo");
			this.onmouseup=attachEventHandler(parent, "dragStop");
			event.preventDefault();
		}
		
		if(this.scrollgui==true){
			this.gui=document.createElement('div');
			this.gui_button_top=document.createElement('input');
			this.gui_button_top.type='button';
			this.gui_button_top.value='UP';
			this.gui_button_top.className='gui_button_top';
		
			this.gui_button_bottom=document.createElement('input');
			this.gui_button_bottom.type='button';
			this.gui_button_bottom.value='DOWN';
			this.gui_button_bottom.className='gui_button_bottom';
		
			this.gui_button_left=document.createElement('input');
			this.gui_button_left.type='button';
			this.gui_button_left.value='<';
			this.gui_button_left.className='gui_button_left';
			
			this.gui_button_right=document.createElement('input');
			this.gui_button_right.type='button';
			this.gui_button_right.value='>';
			this.gui_button_right.className='gui_button_right';
		
			this.gui.appendChild(this.gui_button_top);
			this.gui.appendChild(this.gui_button_bottom);
			this.gui.appendChild(this.gui_button_left);
			this.gui.appendChild(this.gui_button_right);
			// add scroll actions
			this.gui_button_bottom.onmouseover=attachEventHandler(this, "setScrollDirection");
			this.gui_button_top.onmouseover=attachEventHandler(this, "setScrollDirection");
			this.gui_button_left.onmouseover=attachEventHandler(this, "setScrollDirection");
			this.gui_button_right.onmouseover=attachEventHandler(this, "setScrollDirection");
		
			this.gui_button_bottom.onmouseout=attachEventHandler(this, "unsetScrollDirection");
			this.gui_button_top.onmouseout=attachEventHandler(this, "unsetScrollDirection");
			this.gui_button_left.onmouseout=attachEventHandler(this, "unsetScrollDirection");
			this.gui_button_right.onmouseout=attachEventHandler(this, "unsetScrollDirection");
		}
		
		this.Objviewport=document.createElement('div');
		this.Objviewport.className='viewport';
		this.map=document.createElement('div');
		this.map.className='map';
		this.viewportgui=document.createElement('div');
		this.Objviewport.appendChild(this.map);
	
		this.map.style.top='-64px';
		this.map.style.left='-32px';
		
		this.map.appendChild(this.viewportgui);
		this.map.appendChild(this.cursor);
		this.map.appendChild(this.watercursor);
	
		this.parentnode.appendChild(this.gui);
		this.parentnode.appendChild(this.Objviewport);
		
		// store some cars for quicker responses
		this.usetransparancy=this.getsetting(this.quality,'menu_transparancy');
		this.watertransparancy=this.getsetting(this.quality,'water_transparancy');
		this.Objviewport.style.width=(this.clientsize[0]-30)+'px';
		this.Objviewport.style.height=(this.clientsize[1]-30)+'px';
		
		if(this.scrollgui==true){
			this.gui_button_bottom.style.width=this.clientsize[0]+'px';
			this.gui_button_top.style.top=(parseInt(this.gui_button_top.offsetTop)+this.clientsize[1])-15+'px';
			this.gui_button_top.style.width=this.clientsize[0]+'px';
			this.gui_button_left.style.height=this.clientsize[1]+'px';
			this.gui_button_right.style.left=(parseInt(this.gui_button_top.offsetLeft)+this.clientsize[0])-15+'px';
			this.gui_button_right.style.height=this.clientsize[1]+'px';
		}
		this.setlocation(600,(600+this.clientsize[0]),600,(600+this.clientsize[1]));
	},
	
	setlocation: function (startX,endX,startY,endY){
		this.viewport[0]=startX-64;
		this.viewport[1]=endX+64;
		this.viewport[2]=startY-64;
		this.viewport[3]=endY+64;
		this.map.style.left=parseInt(this.map.style.left)-(startX-400)+'px';
		this.map.style.top=parseInt(this.map.style.top)-(startY-400)+'px';
		this.fetch(parseInt(startX)-64,parseInt(endX)+64,startY-64,parseInt(endY)+64);
	},
	
	addtile:function (idX,idY,height,x,y,zindex,picture,type,mouseevent){
		if(!this.tiles[idX] || !this.tiles[idX][idY]){
			var img=document.createElement("img");
			if(!this.tiles[idX]){	
				this.tiles[idX]=new Array();
			}
			var corners=picture.match(/\d\-\d\-\d\-\d/)[0].split('-');
			
			this.tiles[idX][idY]=new Array(	idX,
							idY,
							img,
							new Array(
								parseInt(corners[0]),
								parseInt(corners[1]),
								parseInt(corners[2]),parseInt(corners[3])
								),
							height
							);
			var parent=this;
			img.style.position="absolute";
			img.style.left=x+"px";
			img.style.top=y+"px";
			img.style.zIndex=zindex;
			img.src=this.backgroundpath+type+picture+".png";
			img.className="tile";
			this.map.appendChild(img);
			if(mouseevent=='true'){  // true is a string here!
				img.onmousemove=img.onmouseover=function(event) {
							var aMove = checkbounds(img,event);
							// The only time we call checktile is if the
							// cursor is positioned over a different tile
							// If *not* out of bounds, move the cursor to this tile	
							if(aMove == false){
								//if(this.check_cursor!=false){
									//this.check_cursor=false;
									parent.movecursortotile(idX,idY);
									//this.cursor.onmousemove=attachEventHandler(this, "checkcursor");
								//}
							} else {
								if(!parent.cursorover || (parent.cursorover['x']!=idX && parent.cursorover['y']!=idY) && parent.check_cursor!=false){ //&& this.move_cursor==true
									parent.cursorover['x']=idX;
									parent.cursorover['y']=idY;
									parent.check_cursor=false;
									parent.movecursor(aMove[0],aMove[1]);
								}
							}
							return true;
						}
			}
		}
	},

	addwater:function (idX,idY,idZ,x,y,zindex,picture,mouseevent){
		
		if(!this.planes[idX] || !this.planes[idX][idY] || !this.planes[idX][idY][idZ] ){
			var img=document.createElement("img");
			//img.id=id;
			
			if(!this.planes[idX]){
				this.planes[idX]=new Array();
			}
			if(!this.planes[idX][idY] ){
				this.planes[idX][idY]=new Array();
			}
			this.planes[idX][idY][idZ]=new Array(idX,idY,idZ,img);
			var parent=this;
			img.style.position="absolute";
			img.style.left=x+"px";
			img.style.top=y+"px";
			img.style.zIndex=zindex;
			if(this.watertransparancy){
				setopacity(img,40);
			}
			img.src=this.backgroundpath+'water/'+picture+'.png';
			img.className='tile';
			this.map.appendChild(img);
			if(mouseevent=='true'){  // true is a string here!
				img.onmousemove=img.onmouseover=function(event) {
							var aMove = checkbounds(img,event);
							// if(aMove!=false){ alert('triggered a water onmouseover, but its aparantyl out of bounds'); }
										
							//targ=document.getElementById(id[1]+'-'+id[2]); // reset the element to the lowest object
							
							// The only time we call checktile is if the
							// cursor is positioned over a different tile
							// If *not* out of bounds, move the cursor to this tile	
							if(aMove == false){
								//if(this.check_cursor!=false){
									//this.check_cursor=false;
									parent.movecursortotile(idX,idY);
									//this.movecursortotile( this.tiles[temp[1]][temp[2]] );
									//this.cursor.onmousemove=attachEventHandler(this, "checkcursor");
								//}
							} else {
								if(!parent.cursorover || (parent.cursorover['x']!=idX && parent.cursorover['y']!=idY) && parent.check_cursor!=false){ //&& this.move_cursor==true
									parent.cursorover['x']=idX;
									parent.cursorover['y']=idY;
									parent.check_cursor=false;
									parent.movecursor(aMove[0],aMove[1]);
								}
							}
							return true;
						}
			}
		}
	},
	
		
	fetch: function (startX,endX,startY,endY){	
		// cook up which range we need to get.		
		var url = "../xml/tiles.php?startX="+startX+"&endX="+endX+"&startY="+startY+"&endY="+endY+"&waterlevels="+this.getsetting(this.quality,'water_levels')+'&watertransparancy='+this.getsetting(this.quality,'water_transparancy');
		this.ajaxhandler.addRequest(url, 'GET', this.handleFetch, this);
		return true;
	}, 
	
		
	handleFetch: function (xml){
		// first add the tiles.	
		var watertiles=xml.getElementsByTagName("water");
		var watercount=watertiles.length;
		for(var i=0;i<watercount;i++){
			this.addwater(watertiles[i].getAttribute('x'),
					watertiles[i].getAttribute('y'),
					watertiles[i].getAttribute('waterlevel'),
					watertiles[i].getAttribute('top'),
					watertiles[i].getAttribute('left'),
					watertiles[i].getAttribute('zindex'),
					watertiles[i].getAttribute('image'),
					watertiles[i].getAttribute('cursor')
					);
		}
		
		var tiles=xml.getElementsByTagName("tile");
		var tilescount=tiles.length;
		for(var i=0;i<tilescount;i++){
			this.addtile(tiles[i].getAttribute('x'),
					tiles[i].getAttribute('y'),
					tiles[i].getAttribute('height'),
					tiles[i].getAttribute('top'),
					tiles[i].getAttribute('left'),
					tiles[i].getAttribute('zindex'),
					tiles[i].getAttribute('image'),
					tiles[i].getAttribute('type'),
					tiles[i].getAttribute('cursor')
					);
		}
	},
			
	handleDestroy: function (xml) {
		// first remove the tiles.
		var tiles=xml.getElementsByTagName("tile");
		var tilescount=tiles.length;
		var id=new Array();
		for(var i=0;i<tilescount;i++){
			id[0]=tiles[i].getAttribute('x');
			id[1]=tiles[i].getAttribute('y');
			if(this.tiles[id[0]] && this.tiles[id[0]][id[1]]){
				this.map.removeChild(this.tiles[id[0]][id[1]]);
				delete this.tiles[id[0]][id[1]];
			}
		}
		var water=xml.getElementsByTagName("water");
		var watercount=water.length;
		for(var i=0;i<watercount;i++){
			id[0]=tiles[i].getAttribute('x');
			id[1]=tiles[i].getAttribute('y');
			id[2]=tiles[i].getAttribute('waterlevel');
			if(this.planes[id[0]] && this.planes[id[0]][id[1]] && this.planes[id[0]][id[1]][id[2]] ){
				this.map.removeChild(this.planes[id[0]][id[1]][id[2]] );
				delete this.planes[id[0]][id[1]][id[2]];
			}
		}
	},
	
	destroy: function (startX,endX,startY,endY){
		var url = "../xml/tiles.php?startX="+startX+"&endX="+endX+"&startY="+startY+"&endY="+endY+"&waterlevels="+this.getsetting(quality,'water_levels')+'&watertransparancy='+this.getsetting(quality,'water_transparancy');
		this.ajaxhandler.addRequest(url, 'GET', this.handleDestroy, this);
		return true;
	}
	/*
	,
	
	tilelocation: function (id){
		id=id.split('-');
		var obj=this.tiles[ id[0] ] [ id[1] ];
		if(obj){
			return new Array(obj.style.left,obj.style.top);
		} else {
			return false;
		}
	}
		
	
	,
	createmessage: function (message,tileid,livespan){	
		var tile=this.tilelocation(tileid);
		if(tile!=false){
			var obj=document.createElement("div");
			obj.id='message'+tileid;
			obj.style.position="absolute";
			obj.style.left=tile[0];
			obj.style.top=tile[1];
			obj.style.zIndex=300;
			obj.className='message';
			obj.innerHTML=message;
			this.map.appendChild(obj);
			if(livespan>0){	
				setTimeout('map.removeChild(document.getElementById("'+obj.id+'"));',livespan);
			}
			return obj.id;
		}	
	}*/
}