/**
 * @file
 * This is DAMIAO version 0.2.6 .
 * DOMIAO is a javascript "library" to ease experiments with parallax scrolling
 * which can and should create 3D effects. The libraries name is created from
 * DOM, the Document Object Model, and miao(3d), of which it is a sub-
 * project. Its soon hosted on domiao.miao3d.de and published under the license that should have come with this download<br>
 * Domiao is not related to http://www.youtube.com/user/wlawee this sweety, apparently called Domiao.
 * "How all of it works" is inbetween documentation and tutorial. On the website you should find both.
 * The class names might be a bit misleading, but I do not like to have "Scene"s or "World"s inside computers.
 * A Blender script should be available soon, too.
 * This documentation was created using
 * (http://jsunit.berlios.de/internal.html), 
 * a perl script to render it nicely with doxygen. Since maybe one wants to 
 * keep traffic low in webpages, there is a version without comments available as well, that you should use in productive environment (haha, "productive" ... ).
 * Initial developement was started by Felix Wolfsteller at around
 * Sunday, Feb 24, 2008.
 * Feel free to contact him (its me, felix.wolfsteller@gmail.com).
 * I know that the pseudo- projection math is odd and false, but it gives an okay approximation.
 * 
 * Project homepage:
 * miao3d.com
 *
 * VERSION HISTORY
 * - X Prototyping made it v 0.1
 *  - X viewconstraints as global vars (hacky), read by mousehandler coined v 0.1.1
 * - X Simple Masking made v 0.1.2
 *  - X first/last zidx of layers gave +0.0.2 to v 0.1.4
 *  - X Reversing (hacky) made it in for v 0.1.6
 * - X basic animation were making it v 0.2
 *  - X further documentation was the "v 0.2.2 - feature"
 *  - X basic preloading images was then in v 0.2.3
 *  - X ID in layer, so that one can use the same image for multiple layers made it feel 2.3.1ish
 *  - X support for different sized layers was not only thought to be in v 0.2.5
 *  - X Pseudo- projection intermingled with other changes in version number(s) v 0.2.6
 * VERSION FUTURE
 * \todo
 * - cooler and smoother animations let me think of v 0.2.7
 * - better viewport control could make it v 0.2.8
 * - documentation is important, so it results in v 0.2.9
 * - putting it online should make it v 0.3
 * - the rudimentary blender export script justifies v 0.3.2
 * - preloading with "i am loading sign" comes somewhat later in 0.3.3
 * - mousehandler support for many viewports is right there in 0.3.5
 * - cropping divs is a cause for v 0.4
 * - including more correct movements (opening angle and depth calc)
 * - gives rise to 0.4.5
 * - allowing div/img greatly improves version to v 0.5
 * - magic, labour and time are engough to jumb to v 0.6
 * - 3d position and extend of layers is a feature for 0.7.5
 * - in between should be:
 * - having "slideshows of viewports"
 * - showing an icon or smth like that during preloading of images.
 * - use "delete" where it should be used
 * - clever and intelligent masking
 * - close to world end we will reach the 0.9.9
 */

// for the class / global / this->ref problems:
//  * http://www.thescripts.com/forum/thread88860.html
//  * or do http://killustar.blogspot.com/2005/04/javascript-setinterval-problem.html
//  * http://www.vonloesch.de/node/32

// To read, understand and use: associative, multidimensional arrays/lists or dictionaries: http://en.wikipedia.org/wiki/JavaScript_syntax
       // http://www.webreference.com/js/tips/000229.html

// for optimization:
	// http://isaacschlueter.com/2006/10/settimeout-for-fat-inits/
	// asynchronize the renders (style changes), experiments failed, so far.


/* *************************
           GLOBALS
************************* */
/**
 * Running on Internet Explorer? Has influence on event- capturing only (so far).
 * @type bool
 */
var isIE = document.all?true:false;

/**
 * global constraints for viewposition of (all) renderers.
 * (architectural weakness)
 */
var viewconstraintX = new Array(-300,300);

/**
 * global constraints for viewposition of (all) renderers.
 * (architectural weakness)
 */
var viewconstraintY = new Array(-300,300);

/**
 * global constraints for viewposition of (all) renderers.
 * (architectural weakness)
 */
var viewconstraintZ = new Array(-300,300);

var lastLayerID = 0;

/**
 * Browser- independent code from http://www.quirksmode.org/js/findpos.html to
 * find the position of a specific dom- element, relative to left upper corner of the page.
 * @tparam DOMObject The Object to find position from.
 * @type int[]
 * @return Array with left and top position of searched object.
 */
function findPos(obj) {
       var curleft = curtop = 0;
       if (obj.offsetParent) {
               do {
                       curleft += obj.offsetLeft;
                       curtop += obj.offsetTop;
               } while (obj = obj.offsetParent);
       }
       return [curleft,curtop];
}

/**
 * Fit a variable in bounds, if the variable is outside of it.
 * Its called cramping as well(?).
 * @tparam float variable The variable to "crop".
 * @tparam int[] bounds Lower and upper bound [lower, upper].
 * @return The variable, "cropped" into boundaries, if neccessary.
 */
function bound(variable, bounds){
	if(variable < bounds[0]){
		return bounds[0];
		}
	if(variable > bounds[1]){
		return bounds[1];
	}
	return variable;
}

/**
 * Simple abs() implementation.
 * @tparam float variableA the variable to take the abs of.
 * @type float
 * @return the absolute value of the argument.
 */
function abs(variableA){
	if(variableA < 0){
		return -variableA;
		}
	else{
		return variableA;
	}
}
/**
 * Finds the minimum of two variables.
 * @tparam float variableA The first variable.
 * @tparam float variableB The second variable.
 * @type float
 */
function min(variableA, variableB){
	if(variableA < variableB){
		return variableA;
		}
	else{
		return variableB;
	}
}
/**
 * Finds the maximum of two variables.
 * @tparam float variableA The first variable.
 * @tparam float variableB The second variable.
 * @type float
 */
function max(variableA, variableB){
	if(variableA > variableB){
		return variableA;
		}
	else{
		return variableB;
	}
}

/* ************************************
          RENDERER CLASS
 *********************************** */
/**
 * The Renderer class is in a way a Layer- Collection with the ability to
 * manipulate the rendering (css) position of each layer according to some logic,
 * which is usually deployed in a handler class. Naming is a bit strange.
 * @ctor
 * Constructor.
 * Can be called like this: \code 
 * r = new Renderer(width, height, "pic1.png", "img2.gif");
 * \endcode
 * or empty.
 * The constructor initializes the \c message member with the argument
 * \a msg.
 * \attention This is how i can write paragraphs
 * @tparam String msg The error message.
 */
function Renderer(){
       /**
        * The cameras x position (horizontal). Positive is to the right.
        * @type float
        */
       this.viewx = 0;
       /**
        * The cameras y position (vertical). Positive is to the ground.
        * @type float
        */
       this.viewy = 0;
       /**
        * The cameras z position ("depth"). Positve is forward.
        * @type float
        */
       this.viewz = 0;
       /**
        * Pixel position of center of viewport.
        * @type int
        */
       this.centerx = 0;
       /**
        * Pixel position of center of viewport.
        * @type int
        */
       this.centery = 0;
       /**
        * The opening angle of the virtual camera. To be used some day.
        * @type float
        */
       this.openingangle = 110.0;
       /**
        * The Renderers Layer array. Manipulateable any time.
        * @type Layer[]
        */
       this.layerlist = new Array();
       /**
        * The height of the viewport.
        * @type int
        */
       this.viewportheight = 640;
       /**
        * The width of the viewport.
        * @type int
        */
       this.viewportwidth = 480;
       /**
        * The id of the viewport div.
        * @type string
        */
       this.viewportid = "viewdiv";
       /**
        * Whether to output a mask when htmling.
        * @type bool
        */
       this.doMask = false;
       /**
        * Image used for masking.
        * @type string
        */
       this.maskimg = "mask.png";
       /**
        * Contains the lowest z- value (min) of a layer in layerlist.
        * Similar one has to handle the "true" depth of layers, later.
        * Has to be calculated once by calling calcStats()
        */
       this.minz = 10000;
       /**
        * Contains the highest z- value (max) of a layer in layerlist.
        * Similar one has to handle the "true" depth of layers, later.
        * Has to be calculated once by calling calcStats()
        */
       this.maxz = -10000;
       /**
        * Sets the outermost div to overflow- hidden. That means, everything outside
        * of the viewport area is clipped. Since this makes it neccessary to absolutely
        * position the div container, one might get layout- troubles.
        */
       this.doClip = false;
              
       // argument handling in constructor
       // add a layer for every arg after second
       if(arguments.length > 3){
               var width = arguments[0];
               var height = arguments[1];
               for(var i = 2; i < arguments.length; i++){
                       l = new Layer(width, height, arguments[i],i-2);
                       this.addLayer(l);
                       }
       }
}
// RENDERER CLASS DEF END
/* *************************************
            RENDERER FUNCTIONS
 ************************************* */
/**
 * Reversing changes the world in the following sense:
 * Now, when moving the viewport the foreground stays static and just the background moves.
 * Technically, the z-indices of the layers are changed to make the on with highest
 * zidx become zero if it was positive before. if maxz = 0 the min will be zero aftwewards
 * @type void
 */
function RENDERER_reverse(){
	this.calcStats();
	var diff = 0;
	if(this.maxz > 0){
		diff = -this.maxz;
	}
	else if(this.maxz < 0){
		diff = this.minz;
	}
	for(var i = 0; i < this.layerlist.length; i++){
		this.layerlist[i].zidx = this.layerlist[i].zidx+diff;
	}
}
/**
 * Calculates the correct values for minz and maxz.
 * @type void
 */
function RENDERER_calcStats(){
	for(var i = 0; i < this.layerlist.length; i++){
		this.minz = min(this.layerlist[i].zidx,this.minz);
		this.maxz = max(this.layerlist[i].zidx,this.maxz);
	}
}
/**
 * Adds a layer as the latest entry of layerlist.
 * @tparam Layer layer The Layer to be added.
 * @type void
 */
function RENDERER_addLayer(layer){
	this.layerlist[this.layerlist.length] = layer;
	this.calcStats();
}
/**
 * Called like \code r.addLayers("img.jpeg", "foto.png") \endcode
 * adds Layers to layerlist.
 * The zidx property of each Layer is set according to the position in the list,
 * increasing, starting with 0.
 * @tparam string Variable number of strings, indicating the image url for the respective layers ("img.gif", "easy.jpg").
 * @type void
 */
function RENDERER_addLayers(){
        for(var i = 0; i < arguments.length; i++){
                l = new Layer();
                l.imgurl = arguments[i];
                l.zidx = i;
                this.addLayer(l);
        }
        this.calcStats();
}
/**
 * Sets the camera position triple (x,y,z).
 * @tparam int vx Viewports new x coordinate.
 * @tparam int vy Viewports new y coordinate.
 * @tparam int vz Viewports new z coordinate.
 */
function RENDERER_setViewPos(vx, vy, vz){
        this.viewx=vx;
        this.viewy=vy;
        this.viewz=vz;
}
/**
 * Updates the dom, style, layer infos.
 * @type void
 */
function RENDERER_render(){
        for(var i = 0; i < this.layerlist.length; i++){
                // CODE for depth- dependent displacement (0.2.6)
                this.layerlist[i].domposx = (this.viewx - this.layerlist[i].worldx) * this.layerlist[i].xratioforscreen;
                this.layerlist[i].domposy = (this.viewy - this.layerlist[i].worldy) * this.layerlist[i].yratioforscreen;
                this.layerlist[i].updateStyle();

		/* CODE for z- dependent displacements (pre0.2.6)
                this.layerlist[i].posx = this.layerlist[i].zidx * 0.08 * this.viewx;
                this.layerlist[i].posy = this.layerlist[i].zidx * 0.08 * this.viewy;
                this.layerlist[i].updateStyle();
                */
        }
}
/**
 * Possible candidate to be moved to the Layer itself
 * Outputs html code to the web- page.
 * @type void
 */
function RENDERER_html(){
        // overflow:hidden issue! works only when the viewpoert div is overflow:hidden;position:absolute;top:0px;left:0px; 'ed
        document.write("<div id=\"", this.viewportid, "\" style=\"width:",this.viewportwidth, "px;");
        if(this.doClip){
        	document.write("position:absolute;overflow:hidden;top:0px;left:0px;");
        }
        document.write("height:", this.viewportheight,"px;\">");
        /*
        HTML writing code, pre0.2.6 -- now with DOM, below
        
        for(var i = 0; i < this.layerlist.length; i++){
                document.write("<img src=\"", this.layerlist[i].imgurl, "\" ");
                document.write(" id=\"" , this.layerlist[i].divid , "\"");
                document.write(" style=\"position:absolute;left:", this.layerlist[i].domposx);
                document.write("px;top:", this.layerlist[i].domposy, "px;z-index:",
			this.layerlist[i].zidx );
                if(this.layerlist[i].imgwidth != -1){
                        document.write(";width:" ,this.layerlist[i].imgwidth , "px;height:" ,
			this.layerlist[i].imgheight , "px;");
                }
                document.write("\"/>");
        }
        */
        document.write("</div>");
        if(this.doMask){
	        document.write("<div style=\"background-image:url(" , this.maskimg , ");z-index:20;width:", this.viewportwidth, "px;height:", this.viewportheight, "px;position:absolute;top:0px;left:0px;\"></div>");
        }
        /* DOM code */
	for(var i = 0; i < this.layerlist.length; i++){
		onelayerimg = document.createElement('img');
		onelayerimg.src = this.layerlist[i].imgurl;
		onelayerimg.id = this.layerlist[i].divid;
		onelayerimg.style.position = "absolute";
		onelayerimg.style.position.left = this.layerlist[i].domposx + "px";
		onelayerimg.style.position.top = this.layerlist[i].domposy+ "px";
		//;z-index:"+ ";width:" +this.layerlist[i].imgwidth+ "px;height:" +this.layerlist[i].imgheight + "px;";
		if(this.layerlist[i].imgwidth != -1){
			onelayerimg.setAttribute("width", this.layerlist[i].imgwidth);
			}
		if(this.layerlist[i].imgheight != -1){
			onelayerimg.setAttribute("height", this.layerlist[i].imgheight);
			}
		document.getElementById(this.viewportid).appendChild(onelayerimg);
	}
}
/**
 * Creates Images, which hopefully leads to already loaded images, once the page builds up.
 * Call this in the html-bodys onLoad function.
 * @return void
 */
function RENDERER_preload(){
	for(var i = 0; i < this.layerlist.length; i++){
		im = new Image();
		im.src = this.layerlist[i].imgurl;
	}
}
Renderer.prototype.preload = RENDERER_preload;
Renderer.prototype.addLayer = RENDERER_addLayer;
Renderer.prototype.addLayers = RENDERER_addLayers;
Renderer.prototype.render = RENDERER_render;
Renderer.prototype.setViewPos = RENDERER_setViewPos;
Renderer.prototype.html = RENDERER_html;
Renderer.prototype.calcStats = RENDERER_calcStats;
Renderer.prototype.reverse = RENDERER_reverse;

/* ************************************
             LAYER CLASS
 *********************************** */
/**
 * its something
 * @ctor
 * A Layer is a bundle of variables and a function to update the style
 * in the DOM.
 * It corresponds to a layer in a parallax-scrolling fake 3D environment.
 * If arguments are given, they are interpreted in order in the following way:
 * Initial value is 1, usually (even though it should be 0 some times).
 * - zidx layers/(z)- index: 0 is most far away
 * - width is width of image
 * - height is height of image
 * - name is id of div
 * - posx is left
 * - posy is top
 * - zoom is zoom
 * - imgurl is name of image
 * - depth is real depth
 * - divid is the divs id
 */
function Layer(){
	/**
	 * Image- width. If -1 it will use the original width.
	 * @type int
	*/
	this.imgwidth  = arguments[0] || -1;
	/**
	 * Image- height. If -1 it will use the original height.
	 * @type int
	*/
	this.imgheight = arguments[1] || -1;
	/**
	 * Images url.
	 * @type string
	*/
	this.imgurl = arguments[2] || 'img.jpg';
	/**
	 * World x coordinate. The higher, the more to the right.
	 * @type int
	*/
	this.worldx = 0;
	/**
	 * World y coordinate. The higher, the more far.
	 * @type int
	*/       
	this.worldy = 0;
	/**
	 * Width in world.
	 * @type int
	*/
	this.worldwidth = 0;
	/**
	 * Height in world.
	 * @type int
	*/
	this.worldheight = 0;
	/**
	 * This layers z-index (for css style).
	 * @type int
	*/
	this.zidx   = arguments[3] || 1;
	/**
	 * The x (hor) position (for css style).
	 * @type int
	*/
	this.domposx   = arguments[4] || 1;
	/**
	 * The y (ver) position (for css style).
	 * @type int
	*/
	this.domposy   = arguments[5] || 1;
	/**
	 * The depth in a real measure. How it maps to z- index and later how mouse movements
	 * influence this layers position in accordance to its depth is not yet clear or implemented.
	 * @type float
	*/
	this.depth  = arguments[7] || 1;
	/**
	 * The id- string (css) of the viewport. Is determined by lastLayerID (defined in the file).
	 * @type string
	*/
	this.divid = arguments[8] || this.imgurl;
	/**

	 * @type float
	*/	
	this.xratioforscreen = 1.0;
	/**
	 * The id- string (css) of the viewport. Is determined by lastLayerID (defined in the file).
	 * @type float
	*/
	this.yratioforscreen = 1.0;
}
// END CLASS DEF LAYERS
/* ********************************
         LAYER FUNCTIONS
********************************* */
/**
 * Updates this layers position (style) in the DOM.
 * So far, no zooming or whatsoever possible and all Layers share the same hook (0,0).
 * @type void
 */
function LAYER_updateStyle(){
       document.getElementById(this.divid).style.top=this.domposy+"px";
       document.getElementById(this.divid).style.left=this.domposx+"px";
}
/**
 * Defines a layer given its images screen position with initial camera.
 * Sets width and height to original images width and height.
 * @see initScrenPos(x,y,d,r)
 * @tparam string fname The file name of the image to load.
 * @tparam int x The initial x position (horizontal) of this layer on screen, relative to upper left corner (0,0).
 * @tparam int y The initial y position (vertical) of this layer on screen, relative to upper left corner (0,0).
 * @tparam float d The depth value, no useful metric here, yet.
 * @tparam Rendere r The Renderer to hook into.
 * @type void
 */
function LAYER_defineOnScreen(fname, x, y, d, r){
	// creepy code but did not find a way to do it better, so skipped at the moment, -1 instead
	//	img = new Image();
	//	img.src = fname;
	//while(!img.complete){;}
	//this.imgwidth = img.width;
	//this.imgheight = img.height;

	this.imgurl = fname;
	this.imgwidth = -1;
	this.imgheight = -1;

	this.divid = "l"+lastLayerID;
	lastLayerID = lastLayerID +1;
	this.initScreenPos(x,y,d,r);
	r.addLayer(this);
}
/**
 * Assigns an image to this layer. Sets width and heigth to the original size of the loaded image.
 * @tparam string fname The file name of the image to load.
 * @type void
 */
function LAYER_init(fname){
	this.imgurl = fname;
	img = new Image();
	img.src = fname;
	this.imgwidth = img.width;
	this.imgheight = img.height;
	this.divid = "l"+lastLayerID;
	lastLayerID = lastLayerID +1;
}
/**
 * Back-pseudo-projects a layer with given screen position into "space" (sets world coordinates, 
 * when camera sits at (0,0)).
 * @tparam int x The horizontal screen position - relative to upper left corner at (0,0).
 * @tparam int y The vertical screen position - relative to upper left corner at (0,0).
 * @tparam float d The depth to project to.
 * @tparam Renderer r The Renderer to use.
 * @return void
 */
function LAYER_initScreenPos(x,y,d,r){
	this.depth = d;
	// (1/2 viewidth)  / K
	this.xratioforscreen = 0.5*r.viewportwidth/(Math.tan(r.openingangle)*this.depth);
	// calculate position in world
	this.worldx = ( 0.0 - x) / this.xratioforscreen;
	// analog to x position above
	this.yratioforscreen = 0.5*r.viewportheight/(Math.tan(r.openingangle)*this.depth);
	this.worldy = ( 0.0 - y) / this.yratioforscreen;
	this.domposx = x;
	this.domposy = y;
}
Layer.prototype.defineOnScreen = LAYER_defineOnScreen;
Layer.prototype.init = LAYER_init;
Layer.prototype.updateStyle = LAYER_updateStyle;
Layer.prototype.initScreenPos = LAYER_initScreenPos;
/* ************************************
          MOUSEHANDLER CLASS
 *********************************** */
/**
 * Mousehandler
 * @ctor
 * The MouseHandler changes the "Camera position" of a Renderer.
 */
function RendererMouseHandler(r){
	/**
	 * The Renderer that is controlled by this mousehandler.
	 * @type Renderer
	 */
	this.renderer = r;
	if (!isIE) document.captureEvents(Event.MOUSEMOVE);

	// internal var to keep state of mousehandler.
	this.running = 0;
	/*this. doesnt work for callback func
	var/ this. viewconstraintX = new Array(-8000,8000);
	but should be here
	*/
	// do get calculated 
	var mouseoffx = 0;
	var mouseoffy = 1;
} // MOUSE HANDLER CLASS DEF END
/* *********************************
       MOUSEHANDLER FUNCTIOS
********************************* */
/**
 * The callback- function for mouse movement events.
 * When the mouse moves, the Renderers camera position is changed and render is called
 * on the Renderer, to update the positions of layers.
 * @param e event
 * @type void
 */
function MOUSEHANDLER_handleMouse(e){
        // running has to become a var
        if(this.running == 0){
                return;
                }
        if (!isIE) {
                mx = e.pageX;
                my = e.pageY;
        }
        if (isIE) {
                mx = event.clientX + document.body.scrollLeft;
                my = event.clientY + document.body.scrollTop;
        }

	r.setViewPos(bound(mx-mouseoffx,viewconstraintX) , bound(my-mouseoffy,viewconstraintY), bound(0, viewconstraintZ));
	r.render();
	/*
	For Debugging, uncomment and include
	<input id="y" type="text"/>
	<input id="x" type="text"/>
	in the html doc.
	*/
	/*
	document.getElementById("x").value=r.viewx+"";
	document.getElementById("y").value=r.viewy+"";
	*/
}
/**
 * Register the Mouse handler and calculate the center of viewport.
 * @type void
 */
function MOUSEHANDLER_startMouseHandling(){
        hookp = findPos(document.getElementById(r.viewportid));
        mouseoffx = hookp[0] + r.viewportwidth/2;
        mouseoffy = hookp[1] + r.viewportheight/2;
        this.running = 1;
        document.onmousemove = this.handleMouse;
}
/**
 * "Unregister" the mouse handling function.
 * @type void
 */
function MOUSEHANDLER_stopMouseHandling(){
        // doesnt work, running has to become a var i guess
        //alert("ging");
        document.onmousemove = null;
        this.running = 0;
}

RendererMouseHandler.prototype.handleMouse = MOUSEHANDLER_handleMouse;
RendererMouseHandler.prototype.startMouseHandling = MOUSEHANDLER_startMouseHandling;
RendererMouseHandler.prototype.stopMouseHandling = MOUSEHANDLER_stopMouseHandling;

// doesnt handle the animation... mmmh bad name
/* ************************************
       ANIMATIONHANDLER CLASS
 *********************************** */
/**
 * Class to change the "camera position" of a renderer in a static way.
 * The position is interpolated between keypoints, that have to be specified.
 * The interval attribute defines how much time should pass between each call of the step- function.
 * For technical reasons i have to pass the literal reference (..).
 * @ctor
 * @tparam Renderer r The Renderer to deal with
 * @tparam string lr The literal reference (see examples and wait for cooler implementation).
 */
function Animator(r, lr){
	/**
	 * Cooler than self - reference (just kidding).
	 * @type string
	 */
	this.literalref = lr;
	/**
	 * "Pointer" to the Renderer in use.
	 * @type Renderer
	 */
	this.renderer = r;
	/**
	 * Array of keypoints
	 * @type int[]
	 */
	this.keypoints = new Array();
	/**
	 * Current keypoint
	 */
	this.curKey = 0;
	/**
	 * Next keypoint
	 */
	this.nexKey = 1;
	/**
	 * Interval in milliseconds (be aware, its still just javascript) between
	 * two consequent position changes and render calls.
	 * @type int
	 */
	this.interval = 100;
	// Intervalhandle keeps the id of the timer/interval.
	this.intervalhandle = 0;
	// Running is internal variable to hold state.
	this.running = false;
} // ANIMATOR CLASS DEF END
/* ****************************
        ANIMATOR FUNCTIONS
***************************** */
/**
 * Adds a keypoint with the arguments as properties.
 * @tparam int time point
 * @tparam int x The x (hor) position.
 * @tparam int y The y (ver) position.
 * @tparam int z The z (depth) position.
 * @type void
 */
function ANIMATOR_addKeyPoint(time, x, y, z){
	this.keypoints[this.keypoints.length] = new Array(time,x,y,z);
}
/**
 * Does one animation step (interpolates between keypoints).
 * @type void
 */
function ANIMATOR_step(){
	//alert(this.running);
	if(this.running){
		// check if cur/nexkey has to be changed
		//alert("step");
		var tarx = this.keypoints[this.nexKey][1];
		var tary = this.keypoints[this.nexKey][2];
		var tarz = this.keypoints[this.nexKey][3];
		// has to make a cleverer check
		if(this.renderer.viewx == tarx && this.renderer.viewy == tary && this.renderer.viewz == tarz){
			// change cur and nex
			this.curKey = this.nexKey;
			this.nexKey = (this.nexKey+1)%this.keypoints.length;
		}
		var abstdif = abs(this.keypoints[this.curKey][0] - this.keypoints[this.nexKey][0]);
		var changerate = 1/(abstdif/ this.interval);
		//alert(changerate);
		this.renderer.viewx = this.renderer.viewx + 1/changerate * (this.keypoints[this.nexKey][1]-this.keypoints[this.curKey][1]);
		this.renderer.viewy = this.renderer.viewy + 1/changerate * (this.keypoints[this.nexKey][2]-this.keypoints[this.curKey][2]);
		this.renderer.viewz = this.renderer.viewz + 1/changerate * (this.keypoints[this.nexKey][3]-this.keypoints[this.curKey][3]);
		this.renderer.render();
	}
}
/**
 * Starts the animation if running is false, by setting it to true and starting an intervall call.
 * @type void
 */
function ANIMATOR_startAnim(){
	if(!this.running){
		this.running = true;
		// http://www.siteexperts.com/tips/functions/ts18/page5.asp ? helps?
		var v = new Function(this.step);
		this.intervalhandle = setInterval(this.literalref+'.step()', this.interval);
	}
}
/**
 * Stops the animation by setting running to false and clearing the interval- calls.
 * @type void
 */
function ANIMATOR_stopAnim(){
	this.running = false;
	clearInterval(this.intervalhandle);
}

Animator.prototype.step = ANIMATOR_step;
Animator.prototype.addKeyPoint = ANIMATOR_addKeyPoint;
Animator.prototype.stopAnim = ANIMATOR_stopAnim;
Animator.prototype.startAnim = ANIMATOR_startAnim;

