/* ================================================================================
 *                         ===== ologons talantis =====
 *
 * JavaScript written by Gerard Ferrandez
 * http://www.dhteumeuleu.com
 * Date: Fri May 14, 2010
 * Last Update: Wednesday 9 June, 2010 22:03 CET
 *
 * Use under a CC-BY-NC license
 * http://www.dhteumeuleu.com/about/license/
 *
 * other credits:
 * Inspired from http://www.daftalive.com/alive.php
 * Images from Flickr (EVE online screen captures): 
 * http://www.flickr.com/search/?q=EVE+online&l=deriv&ct=0&mt=all&adv=1&s=int
 * ================================================================================ */
 
var dp = function ()
{
	// private variables
	var object = {
			cell: [],
			menu: [],
			text: []
		},
		scr, imagesPath, params, fullImage, loader,
		P, Pn, Pt, lastMenuOver, pc, backgroundImage,
		preload, mibar, nx, ny, nw, nh, sw, sh;
	
	/* ===== append HTML Element function ==== */
	var appendHTML = function (p)
	{
		var i, object = document.createElement(p.tagName);   // create HTML element
		for (i in p.attributes) object[i] = p.attributes[i]; // copy attributes
		for (i in p.style) object.style[i] = p.style[i];     // copy style properties
		if (p.parentNode) p.parentNode.appendChild(object);  // insert object
		return object;
	};
	/* ===== copy JS object ==== */
	var clone = function (obj)
	{
		if (typeof(obj) != "object" || obj == null) return obj;
		var newObj = obj.constructor();
		for (var i in obj) newObj[i] = clone(obj[i]);
		return newObj;
	}
	/* ==== text constructor ==== */
	var Text = function ()
	{
		// text content
		this.div = appendHTML({
			parentNode: scr,
			tagName: "div",
			attributes:
			{
				className: "txt",
				onmouseover: function () { hideLastMenu(); }
			}
		});
		this.css = this.div.style;
	};
	
	Text.prototype =
	{
		/* ==== start typewriter ==== */
		startTypewriter: function (t)
		{
			this.k = 0;
			this.html = t.id ? (
				document.getElementById(t.id) ? 
					document.getElementById(t.id).innerHTML : t.id + " undefined"
			) : t.html + " ";
			this.html = this.html.replace(/\n/g, "");
			this.l    = this.html.length;
			this.css.visibility = "visible";
			this.css.left       = Math.round(t.x * sw) + "px";
			this.css.top        = Math.round(t.y * sh) + "px";
			this.css.width      = Math.round(t.w * sw) + "px";
			this.css.height     = Math.round(t.h * sh) + "px";
			this.div.innerHTML  = "";
			// typewriter loop
			var self = this;
			this.interval = setInterval(
				function () { self.typeLoop(); }
			, 32);
		},
	
		/* ==== skip HTML tag ==== */
		skipTag: function()
		{
			if (this.html.charAt(this.k) === "<")
				this.k += this.html.slice(this.k).indexOf(">") + 1;
		},
		
		/* ==== typewriter loop ==== */
		typeLoop: function ()
		{
			if (this.k <= this.l)
			{
				this.skipTag();
				var n = this.html.slice(this.k).indexOf(" ");
				this.k += (n >= 0) ? n : 1;
				this.skipTag();
				this.div.innerHTML = this.html.slice(0, this.k++);
			}
			else 
			{
				clearInterval(this.interval);
				this.interval = false;
			}
		}
	};
	
	/* ==== menu constructor ==== */
	var Menu = function (n, p)
	{
		// menu wrapper
		this.div = appendHTML({
			parentNode: scr,
			tagName: "div",
			attributes:
			{
				parent: this,
				className: "menu",
				onclick: function () { this.parent.click(); },
				onmouseover: function () { this.parent.over(); }
			},
			style: { visibility: "hidden" }
		});
		// Color backround
		var bgc = appendHTML({
			parentNode: this.div,
			tagName: "div",
			attributes: { className: "menubackgroundcolor" },
			style: { position: "absolute" }
		});
		this.bgc = bgc.style;
		// menu container
		this.menuDiv = appendHTML({
			parentNode: this.div,
			tagName: "div",
			attributes:
			{
				parent: this,
				className: "menucontent",
				innerHTML: p.html,
				onclick: function () { this.parent.click(); },
				onmouseover: function () { this.parent.over(); }
			}

		});
		
		this.css = this.div.style;
		this.pageTarget = p.target;
	
		// sub menu construction
		if (p.submenu)
		{
			this.submenuDiv = appendHTML({
				tagName: "div",
				parentNode: this.div,
				attributes: { className: "submenucontent" },
				style: { visibility: "hidden" }
			});
	
			// title
			if (p.submenu.title)
			{
				appendHTML({
					parentNode: this.submenuDiv,
					tagName: "div",
					attributes:
					{
						className: "submenutitle",
						innerHTML: p.submenu.title,
						onclick: function () {
							resetLoops();
							Pt = P.text;
							displayPage();
							return false;
						}
					}
				});
			}
	
			// submenu container
			this.submenuContent = appendHTML({
				parentNode: this.submenuDiv,
				tagName: "div",
				attributes: { className: "submenu" }
			});
	
			// submenu lines
			this.menuitem = [];
			var i = 0, o;
			while (o = p.submenu.lines[i++])
			{
				this.menuitem.push(
					new Submenuitem(this, o)
				);
			}
		}
	};
	
	Menu.prototype =
	{
		/* ==== menu over ==== */
		over: function ()
		{
			if (this.pageTarget != Pn && lastMenuOver != this)
			{
				hideLastMenu();
				lastMenuOver = this;
				this.menuDiv.style.visibility = "visible";
				/* ---- flash ---- */
				this.c = clone(params.flash);
				var self = this, k = 0;
				var overflash = function ()
				{
					if (k++ < 12)
					{
						self.fadeColor(0.2);
						setTimeout(overflash, 32);
					}
					else self.fadeColor(0);
				};
				overflash();
			}
		},
	
		/* ==== menu click ==== */
		click: function ()
		{
			var t = this.pageTarget;
			if (t !== Pn && params.page[t])
			{
				// new page
				resetLoops();
				Pn = t;
				P = params.page[t];
				Pt = P.text;
				displayPage();
			}
		},
	
		/* ==== target move ==== */
		move: function (i)
		{
			// targets
			this.xt = P.menuTarget[i].x;
			this.yt = P.menuTarget[i].y;
			this.ct = clone(P.menuBackgroundColor);
			// init menu dimension
			this.css.visibility = "visible";
			this.css.width      = this.bgc.width = Math.round(sw - 1) + "px";
			this.css.height     = this.bgc.height = Math.round(sh - 1) + "px";
			// content visibility
			this.menuDiv.style.visibility = (this.pageTarget === Pn) ? "visible" : "hidden";
			if (this.submenuDiv) this.displayMenuitem(false);
			// moving menu loop
			var self = this;
			this.interval = setInterval(
				function () { self.moving(); }
			, 32);
		},
		
		fadeColor: function (speed)
		{
			// transition
			if (speed)
			{
				this.c.r += (this.ct.r - this.c.r) * speed;
				this.c.g += (this.ct.g - this.c.g) * speed;
				this.c.b += (this.ct.b - this.c.b) * speed;
			}
			else this.c = clone(this.ct);
			// HTML background color
			this.bgc.backgroundColor = "RGB("
				+ Math.round(this.c.r) + ","
				+ Math.round(this.c.g) + ","
				+ Math.round(this.c.b) + ")";
		},
		/* ==== move ==== */
		moving: function ()
		{
			// distance to target
			var speed = 0;
			var dx = this.xt - this.x;
			var dy = this.yt - this.y;
			if (Math.abs(dx) > 0.01 || Math.abs(dy) > 0.01)
			{
				// inc position
				this.x += dx * .2;
				this.y += dy * .2;
				speed = 0.1;
			}
			else
			{
				// init values
				this.x = this.xt;
				this.y = this.yt;
				// stop animation
				clearInterval(this.interval);
				// submenu
				if (this.submenuDiv && this.pageTarget === Pn)
				{
					// display submenu
					this.menuDiv.style.visibility = "hidden";
					this.displayMenuitem(true);
				}
			}
			// update HTML
			this.css.left = Math.round(this.x * sw) + "px";
			this.css.top  = Math.round(this.y * sh) + "px";
			this.fadeColor(speed);
		},
		
		/* ---- show menu items ---- */
		displayMenuitem: function (visible)
		{
			var i = 0, o, menuitem = this.menuitem;
			while (o = menuitem[i++]) o.div.style.visibility = "hidden";
			this.submenuDiv.style.visibility = "hidden";
			if (visible)
			{
				i = 0;
				this.submenuEnabled = true;
				var self = this;
				var displayMenuitem = function ()
				{
					var o = menuitem[i++];
					if (o && self.submenuEnabled)
					{
						o.div.style.visibility = "visible";
						// complementary bar colors
						o.bar.style.background = "RGB(" +
							Math.round((256 - P.menuBackgroundColor.r) * 0.25) + "," + 
							Math.round((256 - P.menuBackgroundColor.g) * 0.25) + "," + 
							Math.round((256 - P.menuBackgroundColor.b) * 0.25) + ")";
						setTimeout(displayMenuitem, 64);
					}
				};
				setTimeout(displayMenuitem, 256);
				this.submenuDiv.style.visibility = "visible";
			} else this.submenuEnabled = false;
		}
	};
	
	/* ==== sub menu item constructor ==== */
	var Submenuitem = function (parent, p)
	{
		this.parent = parent;
		this.text = p.text;
		this.k = 100;
		this.fullImage = p.fullImage;
		this.div = appendHTML({
			tagName: "div",
			parentNode: parent.submenuContent,
			attributes:
			{
				className: "submenuline",
				parent: this,
				onclick:     function () { this.parent.click(); },
				onmouseover: function () { this.parent.over(); }
			}
		});
		this.bar = appendHTML({
			tagName: "div",
			parentNode: this.div,
			style:
			{
				position: "absolute",
				width: "100%",
				height: "100%",
				left: "100%"
			}
		});
		this.txt = appendHTML({
			tagName: "div",
			parentNode: this.div,
			attributes:
			{
				innerHTML: p.html
			},
			style:
			{
				position: "absolute",

				marginLeft: "10px"
			}
		});
	};
	
	/* ---- menu items functions ---- */
	Submenuitem.prototype =
	{
		/* ---- select ---- */
		click: function ()
		{
			resetLoops();
			resetText();
			Pt = this.text;	
			if (this.fullImage)
			{
				// display full image
				fullImage = this.fullImage;
				displayPage();
			}
			// update text
			else nextText();
		},
	
		/* ---- bar left ---- */
		over: function ()
		{
			mibar = this;
			var i = 0, o;
			while (o = this.parent.menuitem[i++]) if (o != this && !o.r) o.out();
			var self = this;
			this.r = false;
			var barLeft = function ()
			{
				if (self === mibar)
				{
					self.bar.style.left = Math.round(self.k *= .25) + "%";
					if (Math.round(self.k) > 0) setTimeout(barLeft, 32);
				}
			};
			barLeft();
		},
		
		/* ---- bar right ---- */
		out: function ()
		{
			if (this.k < 100)
			{
				if (this.k < 1) this.k = 1;
				var self = this;
				this.r = true;
				var barRight = function ()
				{
					self.bar.style.left = Math.round(self.k *= 2) + "%";
					if (Math.round(self.k) < 100) setTimeout(barRight, 32);
				};
				barRight();
			}
		}
	};
		
	/* ==== cell constructor ==== */
	var Cell = function (n, x, y)
	{
		this.n  = n;
		this.x0 = x;
		this.y0 = y;
		// next directions
		this.dir = [
			(x - 1 >= 0 ? n - ny : n), 
			(x + 1 < nx - 1 ? n + ny : n), 
			(y - 1 >= 0 ? n - 1 : n), 
			(y + 1 < ny - 1 ? n + 1 : n)
		];
		
		// fade in-out div
		this.opc = appendHTML({
			parentNode: scr,
			tagName: "div",
			attributes:
			{
				onmouseover: function () { hideLastMenu(); }
			},
			style:
			{
				position: "absolute",
				filter: "alpha(opacity=100)",
				opacity: 1,
				background: "#000",
				left:   Math.round(x * sw) + "px",
				top:    Math.round(y * sh) + "px",
				width:  Math.round(sw - 1) + "px",
				height: Math.round(sh - 1) + "px"
			}
		});
	
		// white flash div
		this.fla = appendHTML({
			parentNode: scr,
			tagName: "div",
			style:
			{
				position: "absolute",
				background: "#fff",
				visibility: "hidden",
				left:   Math.round(x * sw) + "px",
				top:    Math.round(y * sh) + "px",
				width:  Math.round(sw - 1) + "px",
				height: Math.round(sh - 1) + "px"
			}
		});
		
		// grid horizontal
		if (x == 0 && y > 0)
		{
			this.hor = appendHTML({
				parentNode: scr,
				tagName: "div",
				attributes: { className: "grid" },
				style:
				{
					top: Math.round(y * sh - 1) + "px",
					width: nw + "px",
					height: "1px"
				}
			});
		}
		// grid vertical
		if (y == 0 && x > 0)
		{

			this.ver = appendHTML({
				parentNode: scr,
				tagName: "div",
				attributes: { className: "grid" },
				style:
				{
					left: Math.round(x * sw - 1) + "px",
					width: "1px",
					height: nh + "px"
				}
			});
		}
	};

	Cell.prototype =
	{ 
		/* ==== crossbrowser opacity function ==== */
		opacity: function (alpha)
		{
			if (this.opc.filters && this.opc.filters.alpha)
			{
				// redefine function for IE<9
				Cell.prototype.opacity = function (alpha)
				{
					this.opc.filters.alpha.opacity = Math.round(alpha);
				};
				this.opacity(alpha);
			}
			else
			{
				// redefine function for CSS3
				Cell.prototype.opacity = function (alpha)
				{
					this.opc.style.opacity = alpha * 0.01;
				};
				this.opacity(alpha);
			}
		},
	
		/* ==== display image ==== */
		displayCell: function ()
		{
			// mark cell as displayed
			this.displayed = true;
			// flash
			this.fla.style.visibility = "visible";
			// fading loop
			var self = this;
			this.interval = setInterval(
				function () { self.displayCellLoop(); }
			, 32);
		},
	
		/* ==== display cell loop ==== */
		displayCellLoop: function ()
		{
			var o;
			if (this.alpha !== this.alphaTarget)
			{
				// opacity
				this.alpha += this.step;
				this.opacity(this.alpha);
				// find next cell
				if (this.alpha === this.nextCell)
				{
					var i = 0,
						s = false;
					while (i++ < 8)
					{
						o = object.cell[
							this.dir[Math.floor(Math.random() * 4)]
						];
						// cell is available
						if (!o.displayed)
						{
							o.displayCell();
							s = true;
							break;
						}
					}
					if (!s)
					{
						// find new starting point
						o = startingCell();
						if (o !== false) o.displayCell(); // next cell
						else this.startNext = true; // the end
					}
				}
				// stop flash
				if (this.alpha === this.endFlash) this.fla.style.visibility = "hidden";
				if (this.startNext && this.alpha === this.nextStep)
				{
					// start typeWriter
					if (this.txt && (this.id || this.html)) object.text[pc].startTypewriter(this);
					// next phase
					if (P.text[pc] && !fullImage) nextText();
				}
			}
			else
			{
				// stop animation loop
				clearInterval(this.interval);
				this.interval = false;
				this.fla.style.visibility = "hidden";
			}
		}
	};
	
	/* ==== return random available cell ==== */
	var startingCell = function ()
	{
		var o, i = 0, avail = [];
		while (o = object.cell[i++]) if (!o.displayed) avail.push(o);
		if (!avail.length) return false; // no available cell
		else
		{
			// return random available cell
			return avail[
				Math.floor(Math.random() * avail.length)
			];
		}
	};
	
	/* ==== initialize cells ==== */
	var initCell = function (p, fx, txt)
	{
		var i = 0, o;
		while (o = object.cell[i++])
		{
			// is Cell active
			if (o.x0 >= p.x && o.x0 <= (p.x + p.w - 1) && 
				o.y0 >= p.y && o.y0 <= (p.y + p.h - 1))
			{
				// copy variables
				o.displayed = false;
				o.startNext = false;
				o.id = false;
				o.txt = txt;
				for (var j in p)  o[j] = p[j];
				for (var k in fx) o[k] = fx[k];
			}
		}
	};
	
	/* ==== reset text ==== */
	var resetText = function ()
	{
		// reset text containers
		pc = 0;
		var i = 0, o;
		while (o = object.text[i++])
		{
			o.div.innerHTML = "";
			o.css.visibility = "hidden";
		}
		// reset opacity
		i = 0;
		while (o = object.cell[i++])
		{
			o.t = true;
			o.opacity(0);
		}
	};
	
	/* ==== display next bloc text ==== */
	var nextText = function ()
	{
		var o = Pt[pc++];
		if (o)
		{
			initCell(o, params.fadeout, true);
			o = startingCell();
			o.displayed = true;
			o.displayCell();
		}
	};
	
	/* ==== menu mouse out ==== */
	var hideLastMenu = function ()
	{
		if (lastMenuOver)
		{
			lastMenuOver.menuDiv.style.visibility = "hidden";
			lastMenuOver = false;
		}
	};
	
	/* ==== reset setIntervals ==== */
	var resetLoops = function ()
	{
		if (preload) {
			clearInterval(preload);
			preload = false;
		}
		var i, j, k, o;
		for (j in object)
		{
			k = object[j];
			i = 0;
			while (o = k[i++])
			{
				if (o.interval)
				{
					// stop loop
					clearInterval(o.interval);
					o.interval = false;
					// stop flash
					if (o.fla) o.fla.style.visibility = "hidden";
				}
			}
		}
	};

	/* ==== images display sequence ==== */
	var displayPage = function ()
	{
		var i, j, m, o;
		// reset
		lastMenuOver = false;
		resetText();
		if (!fullImage)
		{
			// move Menus
			i = 0;
			while (o = object.menu[i]) o.move(i++);
			// background images
			var img = P.backgroundImage;
		}
		else
		{
			// full Image
			var img = fullImage;
			// hide Menus
			i = 0;
			while (o = object.menu[i++]) o.css.left = "-1000px";
		}
		// preload image
		var timeout    = params.timeout;
		var preloadImg = new Image();
		preloadImg.src = imagesPath + img;
		/* ---- loading function ---- */
		var preloading = function ()
		{
			if ((preloadImg.complete && preloadImg.width) || timeout === 0)
			{
				// load complete - hide loader
				loader.innerHTML = "";
				loader.style.visibility = "hidden";
				// hide image
				var i = 0, o;
				while (o = object.cell[i++])
				{
					o.opacity(100);
					if (fullImage)
					{
						// close full image
						o.opc.style.cursor = "pointer";
						o.opc.onclick = function ()
						{
							resetLoops();
							fullImage = false;
							Pt = P.text;
							displayPage();
						}
					}
					else
					{
						o.opc.style.cursor = "default";
						o.opc.onclick = null;
					}
				
				}
				// display background image
				var css = backgroundImage.style;
				if (timeout > 0)
				{
					backgroundImage.src = imagesPath + img;
					css.left = Math.round((nw - preloadImg.width) * 0.5) + "px";
					css.top  = Math.round((nh - preloadImg.height) * 0.5) + "px";
					css.visibility = "visible";
				}
				else css.visibility = "hidden";
				setTimeout(function() {
					// display image			
					initCell(
						{
							x: 0,
							y: 0,
							w: nx,
							h: ny
						},
						params.fadein, false
					);
					// random starting point
					o = startingCell();
					o.displayed = true;
					o.displayCell();
				}, 64);
			}
			else
			{
				// waiting
				timeout--;
				if (timeout < params.timeout - 3)
				{
					// display ajax loader
					loader.style.visibility = "visible";
					loader.innerHTML = (params.timeout - timeout - 3);
				}
				preload = setTimeout(preloading, 64);
			}
		};
		preloading();
	};
	
	////////////////////////////////////////////////////////////////////////////
	
	/* ==== screen dimensions ==== */
	var resize = function ()
	{
		nw = scr.offsetWidth;
		nh = scr.offsetHeight;
		sw = Math.round(nw / nx);
		sh = Math.round(nh / ny);
	};
	
	/* ==== init script ==== */
	var init = function (p)
	{
		var k, i, j, o;
		params = p;
		scr = document.getElementById(p.containerID);
		nx = p.gridX;
		ny = p.gridY;
		imagesPath = p.imagesPath;
		Pn = 0;
		P  = p.page[Pn];
		Pt = P.text;
		resize();
		// create background image
		backgroundImage = appendHTML({
			parentNode: scr,
			tagName: "img",
			style:
			{
				position: "absolute",
				visibility: "hidden"
			}
		});
		// ajax loader
		loader = appendHTML({
			parentNode: scr,
			tagName: "div",
			attributes: { id: "loader" },
			style: { visibility: "hidden" }
		});
		// create cells
		k = 0;
		for (i = 0; i < nx; i++)
		{
			for (j = 0; j < ny; j++)
			{
				object.cell.push(
					new Cell(k++, i, j)
				);
			}
		}
		// create txt objects
		for (i = 0; i < 6; i++)
		{
			object.text.push(
				new Text()
			);
		}
		// create menu objects
		i = 0;
		while (o = p.menu[i])
		{
			object.menu.push(
				new Menu(i++, o)
			);
		}
		// load first page
		setTimeout(
			function () { displayPage(); }
		, 250);
	};
	return {
		// initialize script
		init : init 
	}
}();
