var m3D = function () {
	/* ---- private vars ---- */
	var diapo = [],
		imb,
		scr,
		bar,
		selected,
		urlInfo,
		imagesPath = "foto/",
		camera = {x:0, y:0, z:-650, s:0, fov: 500},
		ndia = 0,
		nimg = 0,
		nw = 0,
		nh = 0;
	/* ==== camera tween methods ==== */
	camera.setTarget = function (c0, t1, p) {
		if (Math.abs(t1 - c0) > .1) {
			camera.s = 1;
			camera.p = 0;
			camera.d = t1 - c0;
			if (p) {
				camera.d *= 2;
				camera.p = 9;
			}
		}
	}
	camera.tween = function (v) {
		if (camera.s != 0) {
			camera.p += camera.s;
			camera[v] += camera.d * camera.p * .01;
			if (camera.p == 10) camera.s = -1;
			else if (camera.p == 0) camera.s = 0;
		}
		return camera.s;
	}
	/* ==== autoplayer ==== */
	var auto = {
		pos:0,
		timer:0,
		reset:true,
		play : function () {
			if (this.start) {
				/* ---- reset autoplay ---- */
				if (this.reset) {
					this.timeout = this.start;
					this.timer = 0;
					this.reset = false;
				}
				/* ---- next ---- */
				if (!camera.s && this.timer++ > this.timeout) {
					if (diapo[this.pos].but) {
						this.timer = 0;
						this.timeout = this.inter;
						diapo[this.pos].click(true);
					}
					this.pos++;
					if (!diapo[this.pos]) this.pos = 0;
				}
			}
		}
	}
	/* ==== diapo constructor ==== */
	var Diapo = function (img, x, y, z) {
		if (img) {
			this.n = ndia;
			this.url = img.url;
			this.title = img.title;
			this.color = img.color;
			this.isLoaded = false;
			if (document.createElement("canvas").getContext) {
				/* ---- using canvas in place of images (performance trick) ---- */
				this.srcImg = new Image();
				this.srcImg.src = imagesPath + img.src;
				this.img = document.createElement("canvas");
				this.canvas = true;
				scr.appendChild(this.img);
			} else {
				/* ---- normal image ---- */
				this.img = document.createElement('img');
				this.img.src = imagesPath + img.src;
				scr.appendChild(this.img);
			}
			/* ---- on click event ---- */
			this.img.onclick = function () { this.diapo.click(); }
			/* ---- command bar buttons ---- */
			this.but = document.createElement('div');
			this.but.className = "button";
			bar.appendChild(this.but);
			this.but.diapo = this;
			this.but.style.left = Math.round((this.but.offsetWidth  * 1.2) * (nimg % 7)) + 'px'; 
			this.but.style.top  = Math.round((this.but.offsetHeight * 1.2) * Math.floor(nimg / 7)) + 'px'; 
			this.but.onclick = this.img.onclick;
			imb = this.img;
			this.img.diapo = this;
			this.zi = 25000;
			nimg++;
		} else {
			/* ---- transparent div ---- */
			this.img = document.createElement('div');
			this.isLoaded = true;
			this.img.className = "fog";
			scr.appendChild(this.img);
			this.w = 300;
			this.h = 300;
			this.zi = 15000;
		}
		/* ---- object variables ---- */
		this.x = x;
		this.y = y;
		this.z = z;
		this.css = this.img.style;
		ndia++;
	}
	/* ==== prototype functions ==== */
	Diapo.prototype = {
		/* ---- main 3D animation ---- */
		anim : function () {
			if (this.isLoaded) {
				/* ---- 3D to 2D projection ---- */
				var x = this.x - camera.x;
				var y = this.y - camera.y;
				var z = this.z - camera.z;
				if (z < 20) z += 5000;
				var p = camera.fov / z;
				var w = this.w * p;
				var h = this.h * p;
				/* ---- HTML rendering ---- */
				this.css.left   = Math.round(nw + x * p - w * .5) + 'px';
				this.css.top    = Math.round(nh + y * p - h * .5) + 'px';  
				this.css.width  = Math.round(w) + 'px';
				this.css.height = Math.round(h) + 'px';
				this.css.zIndex = this.zi - Math.round(z);
			} else {
				/* ---- image is loaded? ---- */
				this.isLoaded = this.loading();
			}
		},
		/* ----  select a diapo ---- */
		click : function (autoplayed) {
			if (!autoplayed) {
				auto.reset = true;
				auto.pos = this.n;
			}
			if (camera.s) return;
			if (this.isLoaded) {
				if (this.urlActive) {
					/* ---- jump hyperlink ---- */
					top.location.href = this.url;
					/* window.open(this.url,"_self",'titlebar=no, scrollbars=yes, menubar=no, status=no, width=800, height=620');*/
				} else {
					/* ---- target positions ---- */
					camera.tz = this.z - camera.fov;
					camera.tx = this.x;
					camera.ty = this.y;
					/* ---- disable previously selected img ---- */
					if (selected) {
						selected.but.className = "button viewed";
						selected.img.className = "";
						selected.img.style.cursor = "pointer";
						selected.urlActive = false;
						urlInfo.style.visibility = "hidden";
					}
					/* ---- select current img ---- */
					this.but.className = "button selected";
					interpolation(false);
					selected = this;
				}
			}
		},
		/* ---- onload initialization ---- */
		loading : function () {
			if ((this.canvas && this.srcImg.complete) || this.img.complete) {
				if (this.canvas) {
					/* ---- canvas version ---- */
					this.w = this.srcImg.width;
					this.h = this.srcImg.height;
					this.img.width = this.w;
					this.img.height = this.h;
					var context = this.img.getContext("2d");
					context.drawImage(this.srcImg, 0, 0, this.w, this.h);
				} else {
					/* ---- plain image version ---- */
					this.w = this.img.width;
					this.h = this.img.height;
				}
				/* ---- button loaded ---- */
				this.but.className += " loaded";
				return true;
			}
			return false;
		}
	}
	////////////////////////////////////////////////////////////////////////////
	/* ==== screen dimensions ==== */
	var resize = function () {
		nw = scr.offsetWidth * .5;
		nh = scr.offsetHeight * .5;
	}
	/* ==== disable interpolation during animation ==== */
	var interpolation = function (bicubic) {
		var i = 0, o;
		while( o = diapo[i++] ) {
			if (o.but) {
				o.css.msInterpolationMode = bicubic ? 'bicubic' : 'nearest-neighbor'; // makes IE8 happy
				o.css.imageRendering = bicubic ? 'optimizeQuality' : 'optimizeSpeed'; // does not really work...
			}
		}
	}
	/* ==== init script ==== */
	var init = function (start, inter, data) {
		/* ---- containers ---- */
		scr = document.getElementById("screen");
		bar = document.getElementById("bar");
		urlInfo = document.getElementById("urlInfo");
		auto.start = start / 32;
		auto.inter = inter / 32;
		resize();
		/* ---- loading images ---- */
		var i = 0, 
		    o,
			n = data.length;
		while( o = data[i++] ) {
			/* ---- images ---- */
			var x = 1000 * ((i % 4) - 1.5);
			var y = Math.round(Math.random() * 4000) - 2000;
			var z = i * (5000 / n);
			diapo.push( new Diapo(o, x, y, z));
			/* ---- transparent frames ---- */
			for (var j = 0; j < 3; j++) {
				var x = Math.round(Math.random() * 4000) - 2000;
				var y = Math.round(Math.random() * 4000) - 2000;
				diapo.push( new Diapo(null, x, y, z + 100));
			}
		}
		/* ---- start engine ---- */
		run();
	}
	////////////////////////////////////////////////////////////////////////////
	/* ==== main loop ==== */
	var run = function () {
		/* ---- x axis move ---- */
		if (camera.tx) {
			if (!camera.s) camera.setTarget(camera.x, camera.tx);
			var m = camera.tween('x');
			if (!m) camera.tx = 0;
		/* ---- y axis move ---- */
		} else if (camera.ty) {
			if (!camera.s) camera.setTarget(camera.y, camera.ty); 
			var m = camera.tween('y');
			if (!m) camera.ty = 0;
		/* ---- z axis move ---- */
		} else if (camera.tz) {
			if (!camera.s) camera.setTarget(camera.z, camera.tz);
			var m = camera.tween('z');
			if (!m) {
				/* ---- animation end ---- */
				camera.tz = 0;
				interpolation(true);
				/* ---- activate hyperlink ---- */
				if (selected.url) {
					selected.img.style.cursor = "pointer";
					selected.urlActive = true;
					selected.img.className = "href";
					urlInfo.diapo = selected;
					urlInfo.onclick = selected.img.onclick;
					urlInfo.innerHTML = selected.title || selected.url;
					urlInfo.style.visibility = "visible";
					urlInfo.style.color = selected.color || "#fff";
					urlInfo.style.top = Math.round(selected.img.offsetTop + selected.img.offsetHeight - urlInfo.offsetHeight - 5) + "px";
					urlInfo.style.left = Math.round(selected.img.offsetLeft + selected.img.offsetWidth - urlInfo.offsetWidth - 5) + "px";
				} else {
					selected.img.style.cursor = "default";
				}
			}
		}
		/* ---- anim images ---- */
		var i = 0, o;
		while( o = diapo[i++] ) o.anim();
		/* ---- autoplay ---- */
		auto.play();
		/* ---- loop ---- */
		setTimeout(run, 32);
	}
	return {
		////////////////////////////////////////////////////////////////////////////
		/* ==== initialize script ==== */
		init : init
	}
}();
