/*
 * Virtual Walk
 * version 0.1
 * Medianova
 * 2009
*/

// init default values and variables
function VirtualWalk(id)
{
	this.id = id;
	this.holder_suffix = "_holder";
	this.virtual_id = this.id + this.holder_suffix;
	
	this.Images = Array();
	
	this.history = Array();

	this.imageCursorPosition = new VirtualWalkPoint();
	this.imageStartingPoint = new VirtualWalkPoint();
	
	this.speed = 20;
	this.Timer = new TimerObject(this.speed);
	this.transition_speed = 10;
	this.defaultSpeedX = -1;
	this.defaultSpeedY = 1;
	
	this.panningHorizontal = false;
	this.panningVertical = false;
	
	this.pauseText = "Kliknite na sliku i krenite u šetnju";
	this.titleWaitTime = 1000;
	this.titleWaitRuns = 0;
	this.infoOpacity = 8;
	this.infoHeight = 15;
	this.opacitySpeed = 1;
	this.spotOpacity = 5;
	
	this.mainOffset = new VirtualWalkPoint();
	
	this.que = new Array();
		
	this.isMouseOver = false;
	this.isMouseOverSpot = false;
	this.state = "pause";
	
	this.holder_width = 0;
	this.holder_height = 0;
	
	this.showMap = true;
	this.mapWidth = 0;
	this.mapHeight = 0;
	
	this.currentImage = 0;
	
	var _self = this;
	var oldonload = window.onload;
	if((oldonload) && (typeof oldonload == 'function'))
	{
		window.onload = function()
		{
			oldonload();
			_self.create();
		}
	}
	else
	{
		window.onload = function()
		{
			_self.create();
		}
	}
}

// load custom settings
VirtualWalk.prototype.init = function(settings)
{
	if(settings.holder_suffix)
	{
		this.holder_suffix = settings.holder_suffix;
		this.virtual_id = this.id + this.holder_suffix;
	}
	if(settings.speed)
	{
		this.speed = settings.speed;
		this.Timer = new TimerObject(this.speed);
	}
	if(settings.defaultSpeedX)
		this.defaultSpeedX = settings.defaultSpeedX;
	if(settings.defaultSpeedY)
		this.defaultSpeedY = settings.defaultSpeedY;
	if(settings.panningHorizontal)
		this.panningHorizontal = settings.panningHorizontal;
	if(settings.panningVertical)
		this.panningVertical = settings.panningVertical;
	if(settings.state)
	{
		if((settings.state == "free") || (settings.state == "pause"))
			this.state = settings.state;
	}
	if(settings.Images)
		this.Images = settings.Images;
	if(settings.infoOpacity)
		this.infoOpacity = settings.infoOpacity;
	if(settings.opacitySpeed)
		this.opacitySpeed = settings.opacitySpeed;
	if(settings.pauseText)
		this.pauseText = settings.pauseText;
}

// create div element to hold virtual walk image
VirtualWalk.prototype.create = function()
{
	// first check for minimum requirements
	
	//we must have valid id
	if(!this.id)
	{
		alert("Error!\r\n\r\nYou must provide id for Virtual Walk!");
		return;
	}
	// we must have valid parent element
	if(!document.getElementById(this.id))
	{
		alert("Error!\r\n\r\nCan't find element with id = " + this.id);
		return;
	}
	// we must have Images as array
	if(this.Images.constructor.toString().indexOf("Array") == -1)
	{
		alert("Error!\r\n\r\nYou must provide at least one image for Virtual Walk!");
		return;
	}
	
	// get main element where we'll put our div for virtual walk
	var obj =  document.getElementById(this.id);
	
	// if this element exists
	if(obj)
	{
		this.mainOffset = this.getAbsPosition();
		
		// get parent element width and height
		this.holder_width = (obj.style.width) ? parseInt(obj.style.width) : obj.offsetWidth;
		this.holder_height = (obj.style.height) ? parseInt(obj.style.height) : obj.offsetHeight;
		
		// calculate middle point from first image and place it in the center
		this.imageStartingPoint.x = Math.floor(this.Images[0].width * 0.5 - this.holder_width * 0.5) * (-1);
		this.imageStartingPoint.y = Math.floor(this.Images[0].height * 0.5 - this.holder_height * 0.5) * (-1);

		// create new div where we'll put our image and do some basic styling
		var holder_div = document.createElement('div');
		holder_div.setAttribute('id', this.virtual_id);

		holder_div.style.display = 'block';
		holder_div.style.padding = "0px";
		holder_div.style.margin = "0px";
		holder_div.style.width = this.holder_width + "px";
		holder_div.style.height = this.holder_height + "px";

		holder_div.style.background = "url("+this.Images[0].image+")";
		holder_div.style.backgroundRepeat = '';
		holder_div.style.backgroundPosition = this.imageStartingPoint.x + "px " + this.imageStartingPoint.y + "px";
		
		// create overlay paragraph for info
		var info = document.createElement('p');
		info.setAttribute('id', this.virtual_id + "_info");
		info.style.fontWeight = 'bold';
		info.style.fontSize = '0.8em';
		info.style.position = 'relative';
		info.style.margin = "0px";
		info.style.padding = "5px";
		info.style.height = this.infoHeight + "px";
		info.style.color = "#fff";
		info.style.background = "#000";
		info.style.opacity = 0;
		info.style.filter = 'alpha(opacity=' + 0 + ')';
		info.innerHTML = "Click to play!";

		if(this.state != "free")
		{
			this.queAction("wait", 0);
			this.queAction("show pause", 0);
		}
		else
		{
			this.queAction("wait", 0);
			this.queAction("show title", 0);
			this.queAction("wait", 0);
			this.queAction("wait", 0);
			this.queAction("wait", 0);
			this.queAction("wait", 0);
			this.queAction("remove title", 0);
		}
		
		//attach info paragraph to holder div
		holder_div.appendChild(info);
		
		// create overlay spot paragraph
		var spot = document.createElement('p');
		spot.setAttribute('id', this.virtual_id + "_spot");
		spot.setAttribute("style", "float: left; display: block; z-index: 10;");
		spot.style.fontWeight = 'bold';
		spot.style.fontSize = '0.8em';
		spot.style.position = 'absolute';
		spot.style.margin = "0";
		spot.style.top = "0px";
		spot.style.left = "0px";
		spot.style.padding = "5px";
		spot.style.color = "#fff";
		spot.style.background = "#000";
		spot.style.opacity = 0;
		spot.style.filter = 'alpha(opacity=' + 0 + ')';
		spot.innerHTML = "Click to play!";
		
		//attach info paragraph to holder div
		holder_div.appendChild(spot);

		if(this.showMap)
		{
			// create overlay map div
			this.mapHeight = Math.ceil(this.holder_height * 0.05);
			this.mapWidth = Math.ceil(((this.holder_height / this.Images[0].height) * this.Images[0].width) * 0.1);
			var map_left = this.holder_width - this.mapWidth;
			var map_top = this.holder_height - this.mapHeight - this.infoHeight - 10;

			var map = document.createElement('div');
			map.setAttribute('id', this.virtual_id + "_map");
			map.setAttribute("style", "z-index: 20;");
			map.style.position = 'relative';
			map.style.margin = "0";
			map.style.top = map_top + "px";
			map.style.left = map_left + "px";
			map.style.width = this.mapWidth + "px";
			map.style.height = this.mapHeight + "px";
			map.style.padding = "0px";
			map.style.color = "#fff";
			map.style.background = "#000";
			map.style.opacity = 0.8;
			map.style.filter = 'alpha(opacity=' + 80 + ')';

			//attach info paragraph to holder div
			holder_div.appendChild(map);

			// create overlay inner map div
			var inner_map_height = Math.ceil((this.holder_height / this.Images[0].height) * this.mapHeight);
			var inner_map_width = Math.ceil(((this.holder_width / this.Images[0].width) * this.mapWidth));
			var inner_map_left = Math.ceil((Math.abs(this.imageStartingPoint.x) / this.Images[0].width) * this.mapWidth);
			var inner_map_top = Math.ceil((Math.abs(this.imageStartingPoint.y) / this.Images[0].height) * this.mapHeight);

			var inner_map = document.createElement('div');
			inner_map.setAttribute('id', this.virtual_id + "_inner_map");
			inner_map.setAttribute("style", "float: left; z-index: 30; display: inner;");
			inner_map.style.position = 'relative';
			inner_map.style.margin = "0px";
			inner_map.style.top = inner_map_top + "px";
			inner_map.style.left = inner_map_left + "px";
			inner_map.style.width = inner_map_width + "px";
			inner_map.style.height = inner_map_height + "px";
			inner_map.style.padding = "0px";
			inner_map.style.color = "#fff";
			inner_map.style.background = "#333";
			inner_map.style.opacity = 0.8;
			inner_map.style.filter = 'alpha(opacity=' + 80 + ')';

			//attach info paragraph to holder div
			map.appendChild(inner_map);
		}
		
		// history link
		var history_height = 12;
		var history_top = this.holder_height - history_height - 12 - this.infoHeight - 10;

		var history = document.createElement('div');
		history.setAttribute('id', this.virtual_id + "_history");
		history.setAttribute("style", "font-size: 0.7em; float:left; z-index: 40;");
		history.style.position = 'relative';
		history.style.marginTop = "-12px";
		history.style.top = history_top + "px";
		history.style.left = "0px";
		history.style.height = history_height + "px";
		history.style.padding = "5px";
		history.style.color = "#fff";
		history.style.background = "#000";
		history.style.opacity = 0;
		history.style.filter = 'alpha(opacity=' + 0 + ')';
		history.innerHTML = 'Go back';
//		history.style.display = 'none';
		
		var a_history = document.createElement('a');
		a_history.setAttribute('id', this.virtual_id + "_a_history");
		a_history.href = null;
		a_history.onclick = function () { return false; };
		a_history.appendChild(history);

		//attach info paragraph to holder div
		holder_div.appendChild(a_history);

		
		// assign functionalities to div
		
		// when mouse over div - start with virtual walk
		var _self = this;
		holder_div.onmouseover = function(evt) 
		{ 
			_self.isMouseOver = true;
			if(_self.state != "pause")
			{
				_self.state = "running";
			}
		}
		
		// when mouse leaves our div - use default settings
		holder_div.onmouseout = function(evt) 
		{ 
			_self.isMouseOver = false;
			if(_self.state != "pause")
			{
				_self.state = "free";
			}
		}

		// check if we are over spot
		holder_div.onmousemove = function(evt)
		{
			if(_self.state == "pause")
				_self.checkSpots();
		}
		
		// on click pause or continue with virtual walk
		holder_div.onclick = function(evt)
		{
			// check if user selected spot
			var spot = false;
			// if we have spot
			if(_self.isMouseOverSpot)
			{
				if(_self.Images[_self.currentImage].spots)
				{
					// itterate
					for(var i = 0; i < _self.Images[_self.currentImage].spots.length; i++)
					{
						spot = _self.Images[_self.currentImage].spots[i];
						// check if cursor position is inside spot
						if((_self.imageCursorPosition.x > spot.left) && (_self.imageCursorPosition.x < spot.left + spot.width) &&
							(_self.imageCursorPosition.y > spot.top) && (_self.imageCursorPosition.y < spot.top + spot.height))
						{
							break;
						}
						else
						{
							spot = false;
						}
					}
				}
			}
			// if we have spot and is clickable
			if((spot) && (spot.link))
			{
				_self.addHistory({'id' : _self.Images[_self.currentImage].id, 'startX' : _self.imageStartingPoint.x, 'startY' : _self.imageStartingPoint.y});
//				document.getElementById(_self.virtual_id + "_history").style.display = "block";
				_self.queClear(2, "history");
				_self.queAction("show history");
				
				// find next image to display via link id
				for(var i = 0; i < _self.Images.length; i++)
				{
					if(_self.Images[i].id == spot.link)
					{
						_self.currentImage = i;
						break;
					}
				}
				
				// get our holder div
				var img = document.getElementById(_self.virtual_id);
				// change background image
				img.style.background = 'url('+_self.Images[_self.currentImage].image+')';
				// set new starting point
				if(spot.startX && spot.startY)
				{
					_self.imageStartingPoint.x = spot.startX * (-1);
					_self.imageStartingPoint.y = spot.startY * (-1);
				}
				else
				{
					// calculate middle point from first image and place it in the center
					_self.imageStartingPoint.x = Math.floor(_self.Images[_self.currentImage].width * 0.5 - _self.holder_width * 0.5) * (-1);
					_self.imageStartingPoint.y = Math.floor(_self.Images[_self.currentImage].height * 0.5 - _self.holder_height * 0.5) * (-1);
				}
				img.style.backgroundPosition = _self.imageStartingPoint.x + "px " + _self.imageStartingPoint.y + "px";
				
				if(_self.showMap)
				{
					_self.mapHeight = Math.ceil(_self.holder_height * 0.05);
					_self.mapWidth = Math.ceil(((_self.holder_height / _self.Images[_self.currentImage].height) * _self.Images[_self.currentImage].width) * 0.1);
					var map_left = _self.holder_width - _self.mapWidth;
					var map_top = _self.holder_height - _self.mapHeight - _self.infoHeight - 10;

					map.style.top = map_top + "px";
					map.style.left = map_left + "px";
					map.style.width = _self.mapWidth + "px";
					map.style.height = _self.mapHeight + "px";

					// create overlay inner map div
					var inner_map_height = Math.ceil((_self.holder_height / _self.Images[_self.currentImage].height) * _self.mapHeight);
					var inner_map_width = Math.ceil(((_self.holder_width / _self.Images[_self.currentImage].width) * _self.mapWidth));
					var inner_map_left = Math.ceil((Math.abs(_self.imageStartingPoint.x) / _self.Images[_self.currentImage].width) * _self.mapWidth);
					var inner_map_top = Math.ceil((Math.abs(_self.imageStartingPoint.y) / _self.Images[_self.currentImage].height) * _self.mapHeight);

					inner_map.style.top = inner_map_top + "px";
					inner_map.style.left = inner_map_left + "px";
					inner_map.style.width = inner_map_width + "px";
					inner_map.style.height = inner_map_height + "px";
				}
								
				_self.queClear(0, "info");
				_self.queAction("wait", 0);
				_self.queAction("show title", 0);
				_self.queAction("wait", 0);
				_self.queAction("wait", 0);
				_self.queAction("wait", 0);
				_self.queAction("wait", 0);
				_self.queAction("remove title", 0);
			}
			else
			{
				if(_self.state == "pause")
				{
					_self.queClear(0, "info");
					_self.queAction("wait", 0);
					_self.queAction("show title", 0);
					_self.queAction("wait", 0);
					_self.queAction("wait", 0);
					_self.queAction("wait", 0);
					_self.queAction("wait", 0);
					_self.queAction("remove title", 0);
					_self.state = "running";
					_self.start();
				}
				else
				{
					_self.queClear(0, "info");
					_self.queAction("show pause", 0);
					_self.state = "pause";
					_self.stop();
				}
			}
		}
		
		// add our div to parent element
		obj.appendChild(holder_div);
		
		// preload images
		//this.preloadImages();
		
		// start the timer
		var func = {'func' : function() { _self.actions(); }, 'id' : "Title" }
		this.Timer.addFunction(func);
		this.Timer.run();
		
		// check for default action
		if(this.state == "free")
			this.start();
	}
}

// main loop function
VirtualWalk.prototype.start = function()
{
	var _self = this;
	var func = {'func' : function() {_self.update();}, 'id' : "Update"};
	this.Timer.addFunction(func);
}

// stop function
VirtualWalk.prototype.stop = function()
{
	// do nothing for now
	this.Timer.removeFunction("Update");
}

VirtualWalk.prototype.checkSpots = function()
{
		if(this.state == "pause")
		{
			if(this.imageStartingPoint.x < 0)
				this.imageStartingPoint.x = Math.abs(this.imageStartingPoint.x);
			if(this.imageStartingPoint.y < 0)
				this.imageStartingPoint.y = Math.abs(this.imageStartingPoint.y);

			// calculate mouse position relative to main element
			var relativePosition = new VirtualWalkPoint(VirtualWalk_mousePosition.x, VirtualWalk_mousePosition.y);
			relativePosition.substract(this.mainOffset);

			// calculate mouse position on image
			this.imageCursorPosition.copy(this.imageStartingPoint);
			this.imageCursorPosition.add(relativePosition);

			// round up values if they are bigger then image dimensions
			r = Math.floor(this.imageCursorPosition.x / this.Images[this.currentImage].width);
			this.imageCursorPosition.x = this.imageCursorPosition.x - r * this.Images[this.currentImage].width;
			r = Math.floor(this.imageCursorPosition.y / this.Images[this.currentImage].height);
			this.imageCursorPosition.y = this.imageCursorPosition.y - r * this.Images[this.currentImage].height;

			if(this.imageCursorPosition.x < 0)
				this.imageCursorPosition.x = Math.abs(this.imageCursorPosition.x);
			if(this.imageCursorPosition.y < 0)
				this.imageCursorPosition.y = Math.abs(this.imageCursorPosition.y);
		}
		
		var spot = false;
		// if we have spot
		if(this.Images[this.currentImage].spots)
		{
			// itterate
			for(var i = 0; i < this.Images[this.currentImage].spots.length; i++)
			{
				spot = this.Images[this.currentImage].spots[i];
				if(spot)
				{
					// check if cursor position is inside spot
					if(((this.imageCursorPosition.x > spot.left) && (this.imageCursorPosition.x < spot.left + spot.width)) &&
						((this.imageCursorPosition.y > spot.top) && (this.imageCursorPosition.y < spot.top + spot.height)))
					{	
						break;
					}
				}
				spot = false;
			}
		}
		// if we have spot
		if(spot)
		{
			var spot_p = document.getElementById(this.virtual_id + "_spot");
			
			var px = spot.left - this.imageStartingPoint.x + this.mainOffset.x;
			var py = spot.top - this.imageStartingPoint.y + this.mainOffset.y;
		
			spot_p.style.left = px + "px";
			spot_p.style.top = py + "px";			

			if(!this.isMouseOverSpot)
			{
				this.queAction("show spot " + i, 1);
			}
			this.isMouseOverSpot = true;
		}
		else if(spot == false)
		{
			if(this.isMouseOverSpot)
				this.queClear(1, "spot");
			this.isMouseOverSpot = false;
		}
}

VirtualWalk.prototype.addHistory = function(history)
{
	this.history[this.history.length] = history;
}

VirtualWalk.prototype.popHistory = function()
{
	if(!this.history)
		return false;
	
	var history = this.history[this.history.length - 1];
	
	var tmp = Array();
	for(var i = 1; i < this.history.length; i++)
		tmp[i - 1] = this.history[i];
	this.history = tmp;
	return history;	
}

// que some action
VirtualWalk.prototype.queAction = function(action, thread)
{
	if(!this.que[thread])
		this.que[thread] = new Array();
	this.que[thread][this.que[thread].length] = action;
}

VirtualWalk.prototype.queClear = function(thread, what)
{
	this.que[thread] = Array();
	this.que[thread][0] = "remove " + what;
}

VirtualWalk.prototype.popAction = function(thread)
{
	if(!this.que[thread])
		return false;
	
	var action = this.que[thread][0];
	
	var tmp = Array();
	for(var i = 1; i < this.que[thread].length; i++)
		tmp[i - 1] = this.que[thread][i];
	this.que[thread] = tmp;
	return action;	
}

// determin title
VirtualWalk.prototype.actions = function()
{
	for(var i = 0; i < this.que.length; i++)
	{
		if(this.que[i].length <= 0)
			continue;
			
		var action = this.que[i][0];
		var todo = action.split(" ");
		
		var info = document.getElementById(this.virtual_id + "_info");
		var spot = document.getElementById(this.virtual_id + "_spot");
		var history = document.getElementById(this.virtual_id + "_history");
		
		if(todo[0] == "show")
		{
			if(todo[1] == "title")
			{
				if(this.Images[this.currentImage].title)
				{
					if(info.innerHTML != this.Images[this.currentImage].title)
						info.innerHTML = this.Images[this.currentImage].title;
				}

				var opacity = info.style.opacity * 10;
				if(opacity < this.infoOpacity)
					opacity = opacity + this.opacitySpeed;

				if(opacity >= this.infoOpacity)
				{
					opacity = this.infoOpacity;
					this.popAction(i);
				}
							
				info.style.opacity = opacity / 10;
				info.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
			else if(todo[1] == "pause")
			{
				if(info.innerHTML != this.pauseText)
					info.innerHTML = this.pauseText;

				var opacity = info.style.opacity * 10;
				if(opacity < this.infoOpacity)
					opacity = opacity + this.opacitySpeed;

				if(opacity >= this.infoOpacity)
				{
					opacity = this.infoOpacity;
					this.popAction(i);
				}
							
				info.style.opacity = opacity / 10;
				info.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
			else if(todo[1] == "spot")
			{
				if(this.Images[this.currentImage].spots[todo[2]].title)
				{
					if(spot.innerHTML != this.Images[this.currentImage].spots[todo[2]].title)
						spot.innerHTML = this.Images[this.currentImage].spots[todo[2]].title;
				}
				
				var opacity = spot.style.opacity * 10;
				if(opacity < this.spotOpacity)
					opacity = opacity + this.opacitySpeed;

				if(opacity >= this.spotOpacity)
				{
					opacity = this.spotOpacity;
					this.popAction(i);
				}
							
				spot.style.opacity = opacity / 10;
				spot.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
			else if(todo[1] == "history")
			{
				var opacity = history.style.opacity * 10;
				if(opacity < this.infoOpacity)
					opacity = opacity + this.opacitySpeed;

				if(opacity >= this.infoOpacity)
				{
					opacity = this.infoOpacity;
					this.popAction(i);
				}
							
				history.style.opacity = opacity / 10;
				history.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
			else
			{
				continue;
			}
		}
		else if(todo[0] == "remove")
		{
			if((todo[1] == "title") || (todo[1] == "pause") || (todo[1] == "info"))
			{
				var opacity = info.style.opacity * 10;
				if(opacity > 0)
					opacity = opacity - this.opacitySpeed;

				if(opacity <= 0)
				{
					this.popAction(i);
					opacity = 0;
				}
						
				info.style.opacity = opacity / 10;
				info.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
			else if(todo[1] == "spot")
			{
				var opacity = spot.style.opacity * 10;
				if(opacity > 0)
					opacity = opacity - this.opacitySpeed;

				if(opacity <= 0)
				{
					this.popAction(i);
					opacity = 0;
				}
						
				spot.style.opacity = opacity / 10;
				spot.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
			else if(todo[1] == "history")
			{
				var opacity = history.style.opacity * 10;
				if(opacity > 0)
					opacity = opacity - this.opacitySpeed;

				if(opacity <= 0)
				{
					this.popAction(i);
					opacity = 0;
				}
						
				history.style.opacity = opacity / 10;
				history.style.filter = 'alpha(opacity=' + opacity * 10 + ')';
			}
		}
		else if(todo[0] == "wait")
		{			
			if(this.titleWaitRuns * this.speed > this.titleWaitTime)
			{
				this.titleWaitRuns = 0;
				this.popAction(i);
			}
			else
			{
				this.titleWaitRuns++;
			}
		}
		else
		{
		}
	}
}

// frame update
VirtualWalk.prototype.update = function()
{
	// check if we have our main element
	var obj =  document.getElementById(this.virtual_id);
	if (obj) 
	{
		// check for current state and get new positions
		
		// if virtual walk is running we must calculate new image position based on current cursor position
		if(this.state == "running")
		{
			// calculate mouse position relative to main element
			var relativePosition = new VirtualWalkPoint(VirtualWalk_mousePosition.x, VirtualWalk_mousePosition.y);
			relativePosition.substract(this.mainOffset);
			
			// calculate mouse position in percentage starting from a center of our main element
			var relativePosition_perc = new VirtualWalkPoint();
			relativePosition_perc.copy(relativePosition);
			
			relativePosition_perc.x = ((relativePosition_perc.x / this.holder_width) - 0.5);
			relativePosition_perc.y = ((relativePosition_perc.y / this.holder_height) - 0.5);
			
			// calculate transition
			relativePosition_perc.multiply(this.transition_speed * (-1));
		}
		// if we are free to move our image then use default speed
		else if(this.state == "free")
		{
			var relativePosition = new VirtualWalkPoint(this.defaultSpeedX, this.defaultSpeedY);
			var relativePosition_perc = new VirtualWalkPoint();
			relativePosition_perc.copy(relativePosition);
		}
		// otherwise return
		else
		{
			return;
		}
		
		// get current backgound position
		var background_position = obj.style.backgroundPosition;
		background_position = background_position.split(" ");
		var oldBackgroundPosition = new VirtualWalkPoint(parseInt(background_position[0]), parseInt(background_position[1]));
		
		// calculate new background position
		var newBackgroundPosition = new VirtualWalkPoint();
		newBackgroundPosition.copy(oldBackgroundPosition);
		newBackgroundPosition.add(relativePosition_perc);
		
		// correct values if we have horizontal limitation
		if(!this.panningHorizontal)
		{
			if(newBackgroundPosition.x > 0)
			{
				// correct value
				newBackgroundPosition.x = 0;
				// and change our default speed to bounce back
				this.defaultSpeedX = this.defaultSpeedX * (-1);
			}
			else if(newBackgroundPosition.x < (this.holder_width - this.Images[this.currentImage].width))
			{
				// correct value
				newBackgroundPosition.x = this.holder_width - this.Images[this.currentImage].width;
				// and change our default speed to bounce back
				this.defaultSpeedX = this.defaultSpeedX * (-1);
			}
			else
			{
				// update image starting point offset
				this.imageStartingPoint.x = Math.floor(oldBackgroundPosition.x + relativePosition_perc.x) * (-1);
				//startingX = Math.floor(pX_t + posX) * (-1);
			}
		}
		else
		{
			this.imageStartingPoint.x = Math.floor(oldBackgroundPosition.x + relativePosition_perc.x) * (-1);
		}

		// correct values if we have vertiacl limitation
		if(!this.panningVertical)
		{
			if(newBackgroundPosition.y < this.Images[this.currentImage].height * (-1) + this.holder_height)
			{
				newBackgroundPosition.y = this.Images[this.currentImage].height * (-1) + this.holder_height;
				this.defaultSpeedY = this.defaultSpeedY * (-1);
			}
			else if(newBackgroundPosition.y > 0)
			{
				newBackgroundPosition.y = 0;
				this.defaultSpeedY = this.defaultSpeedY * (-1);
			}
			else
			{
				this.imageStartingPoint.y = Math.floor(oldBackgroundPosition.y + relativePosition_perc.y) * (-1);
			}
		}
		else
		{
			this.imageStartingPoint.y = Math.floor(oldBackgroundPosition.y + relativePosition_perc.y) * (-1);
		}

		// round up values if they are bigger then image dimensions
		var r = Math.floor(this.imageStartingPoint.x / this.Images[this.currentImage].width);
		this.imageStartingPoint.x = this.imageStartingPoint.x - r * this.Images[this.currentImage].width;
		r = Math.floor(this.imageStartingPoint.y / this.Images[this.currentImage].height);
		this.imageStartingPoint.y = this.imageStartingPoint.y - r * this.Images[this.currentImage].height;
		
		// calculate mouse position on image
		this.imageCursorPosition.copy(this.imageStartingPoint);
		this.imageCursorPosition.add(relativePosition);

		// round up values if they are bigger then image dimensions
		r = Math.floor(this.imageCursorPosition.x / this.Images[this.currentImage].width);
		this.imageCursorPosition.x = this.imageCursorPosition.x - r * this.Images[this.currentImage].width;
		r = Math.floor(this.imageCursorPosition.y / this.Images[this.currentImage].height);
		this.imageCursorPosition.y = this.imageCursorPosition.y - r * this.Images[this.currentImage].height;

		this.checkSpots();
		
		if(this.showMap)
		{
			var inner_map_left = Math.ceil((Math.abs(this.imageStartingPoint.x) / this.Images[this.currentImage].width) * this.mapWidth);
			var inner_map_top = Math.ceil((Math.abs(this.imageStartingPoint.y) / this.Images[this.currentImage].height) * this.mapHeight);
			document.getElementById(this.virtual_id + "_inner_map").style.left = inner_map_left + "px";
			document.getElementById(this.virtual_id + "_inner_map").style.top = inner_map_top + "px";
		}

		// update image position
		obj.style.backgroundPosition = newBackgroundPosition.x + "px " + newBackgroundPosition.y + "px";

		// print out variables
		//document.getElementById('info').innerHTML = "Mouse global: " + relativePosition.x + ", " + relativePosition.y + " <br>Mouse relative: " + relativePosition_perc.x + ", " + relativePosition_perc.y + "<br>Background position: " + newBackgroundPosition.x + ", " + newBackgroundPosition.y + "<br>Background start: " + this.imageStartingPoint.x + ", " + this.imageStartingPoint.y + "<br>Cursor position: " + this.imageCursorPosition.x + ", " + this.imageCursorPosition.y;
	}
}

// get absolute position of element
VirtualWalk.prototype.getAbsPosition = function(obj)
{
	var position = new VirtualWalkPoint();
	
	obj = obj || document.getElementById(this.id);
	if(obj) 
	{
		position.x = obj.offsetLeft;
		position.y = obj.offsetTop;

		if( obj.offsetParent ) 
		{
			position.add(this.getAbsPosition(obj.offsetParent));
		}
	}

	return position;
}

VirtualWalk.prototype.preloadImages = function()
{
	if(document.images)
	{
		for(var i = 0; i < this.Images.length; i++)
		{
			if(this.Images[i])
			{
				var pic = new Image(this.Images[i].width, this.Images[i].height);
				pic.src = this.Images[i].image;
			}
		}
	}
}

// capture mouse position
var VirtualWalk_mousePosition = new VirtualWalkPoint();
// register mouse move event and track down current mouse position
if (!document.all) document.captureEvents(Event.MOUSEMOVE);
document.onmousemove = VirtualWalk_getMousePosition;

function VirtualWalk_getMousePosition(e)
{
	var IE = document.all ? true : false;
	var tempX = 0;
	var tempY = 0;

	if(IE)
	{
		tempX = event.clientX + document.body.scrollLeft;
		tempY = event.clientY + document.body.scrollTop;
	}
	else 
	{
		tempX = e.pageX;
		tempY = e.pageY;
	}  

	if (tempX < 0) {tempX = 0;}
	if (tempY < 0) {tempY = 0;}  

	VirtualWalk_mousePosition.x = tempX;
	VirtualWalk_mousePosition.y = tempY;

	return true;	
}


// Virtual Walk Point class
function VirtualWalkPoint(x, y)
{
	this.x = x || 0;
	this.y = y || 0;
}

VirtualWalkPoint.prototype.add = function(point)
{
	this.x = this.x + point.x;
	this.y = this.y + point.y;
}

VirtualWalkPoint.prototype.substract = function(point)
{
	this.x = this.x - point.x;
	this.y = this.y - point.y;
}

VirtualWalkPoint.prototype.multiply = function(constant)
{
	this.x = this.x * constant;
	this.y = this.y * constant;
}

VirtualWalkPoint.prototype.copy = function(point)
{
	this.x = point.x;
	this.y = point.y;
}

// Virtual Walk Timer Obj
function TimerObject(speed)
{
	this.timerID = 0;
	this.isRunning = false;
	this.state = "init";
	this.speed = speed || 20;
	this.functions = Array();
}

TimerObject.prototype.addFunction = function(func)
{
	var i = this.functions.length;
	this.functions[i] = func;
	
	if((!this.isRunning) && (this.state = "pause"))
		this.run();
}

TimerObject.prototype.removeFunction = function(id)
{
	var tmp = Array();

	var counter = 0;	
	for(var i = 0; i < this.functions.length; i++)
	{
		if(this.functions[i].id != id)
		{
			tmp[counter] = this.functions[i];
			counter++;
		}
	}
	this.functions = tmp;
}

TimerObject.prototype.start = function()
{
	this.isRunning = true;
	this.state = "running";
}

TimerObject.prototype.run = function()
{
	// stop timer
	if(this.timerID)
	{
		clearTimeout(this.timerID);
		this.timerID = 0;
	}
	
	if(this.functions.length <= 0)
	{
		this.isRunning = false;
		this.state = "pause";
		return;
	}
	
	// do functions
	for(var i = 0; i < this.functions.length; i++)
	{
		this.functions[i].func();
	}
	
	// wait
	var _self = this;
	this.timerID = self.setTimeout(function() { _self.run(); }, this.speed);
}

TimerObject.prototype.stop = function()
{
	clearTimeout(this.timerID);
	this.timerID = 0;
	this.isRunning = false;
	this.state = "stop";
}

function MultiDimensionalArray(iRows,iCols)
{
	var i;
	var j;
	var a = new Array(iRows);
	for (i=0; i < iRows; i++)
	{
		a[i] = new Array(iCols);
		for (j=0; j < iCols; j++)
		{
			a[i][j] = "";
		}
	}
	return(a);
} 
