/**
 * Author: Tomas Burian, tomas.burian@atlas.cz
 * Released: 2010
*/

/* Global Variables */
/* general */
try {
	var errorCount = 0;
	var g_nextGameTick = null;
	var g_loops = 0;
	var TICKS_PER_SECOND = 25;
	var SKIP_TICKS = 1000 / TICKS_PER_SECOND;
	var MAX_FRAMESKIP = 5;
	var MIN_SIZE = 0.5; /* 50% size of the original (1920x1080) */
	
	/* agents */
	var MSIE = (navigator.appName == "Microsoft Internet Explorer");
	var MSIEWP7 = (navigator.userAgent.indexOf("Windows Phone") != -1);
	if (!MSIEWP7) {
		var viewPort = document.createElement('meta');
		viewPort.setAttribute('name', 'viewport');
		viewPort.setAttribute('content', 'initial-scale = 1.0, user-scalable=yes, width=device-width');
		document.head.appendChild(viewPort);
	}
	var MSIE9 = (navigator.userAgent.indexOf("MSIE 9") != -1);
	var IPHONE = (navigator.userAgent.toLowerCase().indexOf('iphone') != -1);
	var IPAD = (navigator.userAgent.toLowerCase().indexOf('ipad') != -1);
	
	/* intervals */
	var mainInterval = null;
	var randomizerInterval = null;
	
	/* circles (radar) */
	var MAIN_LOOP_INTERVAL = 10;
	var CIRCLES_RESTART_INTERVAL = 1500;
	var CIRCLES_RESTART_DELAY_RANGE = [600, 1000];
	var CIRCLES_COUNT_RANGE = [3, 6];
	/* IE PNG-read hack, edit getImageSize() */
	var CIRCLE_SIZE = 120;
	var INFOBOX_POSITION = [3, 1];
	var INFOBOX_SIZE = [4, 6];
	
	
	/* buttons */
	var TEXT_PADDING = 6;
	var ACTIVE_BUTTON_BGCOLOR = '#00ff00';
	var CLICKED_BUTTON_FONT_COLOR = '#00ff00';
	
	
	/* animation stuff */
	var animationEnded = 4;
	var restarted = []; /* animation id-groups */
	var doRestart = []; // array: {'objectId': ..., 'startTime': ...}
	/* stored ids for animation chain */
	var chars = [];
	var charGroup;
	var poster;
	var twitter;
	var facebook;
	var google;
	var googlePlux;
	var minigame;
	var popTexts = [];
	var buttons = [];
	var cssRuleCache = {}; /* cssRuleCache.ruleClass.classProperty */
	/* templates */
	var files = [
	             getPostfix('image/Mageo-web_intro.png'),
	             getPostfix('image/intro_artist.png'), 
	             getPostfix('image/intro_warrior.png'), 
	             getPostfix('image/intro_scientist.png'), 
	             getPostfix('image/intro_merchant.png'), 
	             getPostfix('image/circle.png'), 
	             getPostfix('image/fantasy-all.png'), 
	             getPostfix('image/dot.png'),
	             "image/shade.png",
	             "image/shade_button.png",
	             "image/arrow_up.png",
	             "image/arrow_down.png",
	             getPostfix("image/FreeToPlay.png"),
	             "image/twi_pas.png",
	             "image/twi_act.png",
	             "image/fac_pas.png",
	             "image/fac_act.png",
	             "image/gplus_pas.png",
	             "image/gplus_act.png",
	             "image/mageo_minigame_anim.gif"
	            ];
	/* template array indexes */
	var BACKGROUND = 0;
	var ARTIST = 1;
	var WARRIOR = 2;
	var SCIENTIST = 3;
	var MERCHANT = 4;
	var CIRCLE = 5;
	var ALL = 6;
	var DOT = 7;
	var SHADE = 8;
	var SHADE_BUTTON = 9;
	var POSTER = 12;
	var TWITTER_PASSIVE = 13;
	var TWITTER_ACTIVE = 14;
	var FACEBOOK_PASSIVE = 15;
	var FACEBOOK_ACTIVE = 16;
	var GOOGLE_PASSIVE = 17;
	var GOOGLE_ACTIVE = 18;
	var MINIGAME = 19;
	
	/**
	 * Renderer objects data holder.
	 */
	/* {'onEnd': func(), 'fade': bool, 'startTime': millis, 'elem': domElement, 'animation': animation, 'destOpacity': destOpacity, 'alive': bool} */
	var renderObjects = []; 
	var objectIndex = 0;
	
	/* original background size */
	var screenWidth;
	var screenHeight;
	
	/* resize stuff */
	var origWidth;
	var origHeight;
	var ratio;
	var scaleFactor = 0;
	var iPhoneScale = 0.5;
	var iPadScale = 1.075;
	var marginV;
	var marginH;
	
	var scrollPixels = 100;
	
	
	/* Page objects */
	/* Preloader.getCache() = [{'imgObj': el, 'origWidth': x, 'origHeight': y}, ...] */
	var preloader;
	var config;
	
	/* filters out some browsers with feable JS support */
	if (window.onload == undefined);
	
	/**
	 * Start point is here.
	 */
	window.onload = function() {
		if (location.href.indexOf("noSupportCheck") == -1 && isAgentBlocked()) {
			window.location = 'static.html';
		} else {
			config = new Config("config");
			preloader = new Preloader(files, document.body, runIt);
		}
	};

} catch(e) {
	//var st = "JavaScript error occured, forwarding to static content ...\n\n";
	//alert(st + e.toString());
	window.location = 'static.html';
}

/**
 * Main constructor.
 */
function runIt() {
	document.getElementById('agent').value = navigator.userAgent;
	var bg = setupBackground();
	resize();
	screenWidth = bg[0];
	screenHeight = bg[1];
	var textRectWidth = screenWidth * 0.09375;
	var textRectHeight = screenHeight * 0.06;

	log('<input id="bskip" type="button" value="Skip" onclick="skipAnimation();">');
	
	window.onresize = resize;
	
	var leftShift = 57;//px on original size
	var lshift = leftShift * scaleFactor;
	var customSpeed = 1;
	if (IPHONE) {
		lshift *= iPhoneScale;
		customSpeed = iPhoneScale;
	}
	
	createAndStartCircles();
	
	var isize = getImageSize(ALL);
	charGroup = createAnimation(files[ALL], new Anim(isize[0], isize[1], 0, screenWidth*0.3396, screenWidth*0.3396 + lshift, screenHeight*0.125, screenHeight*0.125, 0, 0), morph, now(), false, -1);
	createTextAnimation("copyright", new Anim(screenWidth * 0.13, screenHeight * 0.02, 0, screenWidth*0.68, screenWidth*0.70, screenHeight*0.86, screenHeight*0.86, 0, 1), null, now() + 0, false, -1);
	isize = getImageSize(POSTER);
	poster = createAnimation(files[POSTER], new Anim(isize[0], isize[1], 0, screenWidth*0.006, screenWidth*0.020, screenHeight*0.54, screenHeight*0.54, 0, 0), null, now() + 0, false, -1);

	isize = getImageSize(FACEBOOK_PASSIVE);
	var images = [files[FACEBOOK_PASSIVE], files[FACEBOOK_ACTIVE]];
	facebook = createAnimation(images, new Anim(isize[0]*.3, isize[1]*0.3, 0, getGridX(8), getGridX(8), getGridY(5), getGridY(5), 0, 0), null, now() + 0, false, -1, false, "http://www.facebook.com/mageo/");

	isize = getImageSize(TWITTER_PASSIVE);
	images = [files[TWITTER_PASSIVE], files[TWITTER_ACTIVE]];
	twitter = createAnimation(images, new Anim(isize[0]*0.3, isize[1]*0.3, 0, getGridX(8) + 85, getGridX(8) + 85, getGridY(5), getGridY(5), 0, 0), null, now() + 0, false, -1, false, "http://www.twitter.com/mageo/");

	isize = getImageSize(GOOGLE_PASSIVE);
	images = [files[GOOGLE_PASSIVE], files[GOOGLE_ACTIVE]];
	google = createAnimation(images, new Anim(isize[0]*0.3, isize[1]*0.3, 0, getGridX(8), getGridX(8), getGridY(5)  + 85, getGridY(5)  + 85, 0, 0), null, now() + 0, false, -1, false, "http://plus.google.com/115720562032309581164");

	isize = getImageSize(MINIGAME);
	var centerPos = {
			w: IPHONE ? isize[0] * 0.5 : isize[0],
			h: IPHONE ? isize[1] * 0.5 : isize[1],
			x: lshift + screenWidth * 0.45,
			y: screenHeight * 0.415
		};

	isize = getImageSize(MINIGAME);
	minigame = createAnimation(files[MINIGAME], new Anim(centerPos.w, centerPos.h, 0, centerPos.x, centerPos.x, centerPos.y, centerPos.y, 0, 0), null, now() + 0, false, -1, false, "/maidenvoyage", 'minigame');
	
	resize();
	
	if (location.href.indexOf("skipAnimation") == -1) {
		createMovingChars(lshift, customSpeed);
		popTexts.push(createTextAnimation("warrior_r", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.28, screenWidth*0.59 + lshift, screenHeight*0.32, screenHeight*0.15, 0, 0), null, now() + 0, false, -1));
		popTexts.push(createTextAnimation("artist_r", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.28, screenWidth*0.23 + lshift, screenHeight*0.32, screenHeight*0.42, 0, 0), null, now() + 0, false, -1));
		popTexts.push(createTextAnimation("scientist_r", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.28, screenWidth*0.63 + lshift, screenHeight*0.32, screenHeight*0.57, 0, 0), null, now() + 0, false, -1));
		popTexts.push(createTextAnimation("merchant_r", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.29, screenWidth*0.28 + lshift, screenHeight*0.32, screenHeight*0.77, 0, 0), null, now() + 0, false, -1));
	}

	popTexts.push(createTextAnimation("warrior_f", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.28, screenWidth*0.59 + lshift, screenHeight*0.32, screenHeight*0.15, 0, 0), null, now() + 0, false, -1));	
	popTexts.push(createTextAnimation("artist_f", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.28, screenWidth*0.23 + lshift, screenHeight*0.32, screenHeight*0.42, 0, 0), null, now() + 0, false, -1));
	popTexts.push(createTextAnimation("scientist_f", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.28, screenWidth*0.63 + lshift, screenHeight*0.32, screenHeight*0.57, 0, 0), null, now() + 0, false, -1));
	popTexts.push(createTextAnimation("merchant_f", new Anim(textRectWidth, textRectHeight, 0, screenWidth*0.29, screenWidth*0.28 + lshift, screenHeight*0.32, screenHeight*0.77, 0, 0), null, now() + 0, false, -1));

	document.getElementById('log').style.display = 'block';
	document.getElementById('log').style.width = marginH + 'px';
	
	loop(MAIN_LOOP_INTERVAL);
	startRandomizer();
	
	if (location.href.indexOf("skipAnimation") != -1) {
		skipAnimation();
	}
}

function createMovingChars(lshift, customSpeed) {
	var isize = getImageSize(WARRIOR);
	chars.push(createAnimation(files[WARRIOR], new Anim(isize[0], isize[1], 'auto', screenWidth*0.35, screenWidth*0.3265 + lshift, screenHeight*0.6, screenHeight*0.102, 13*customSpeed, 1), morph, now()+2500, false, -1));
	isize = getImageSize(ARTIST);
	chars.push(createAnimation(files[ARTIST], new Anim(isize[0], isize[1], 'auto', screenWidth*0.765, screenWidth*0.344 + lshift, screenHeight*0.62, screenHeight*0.252, 14*customSpeed, 1), morph, now()+2000, false, -1));
	isize = getImageSize(SCIENTIST);
	chars.push(createAnimation(files[SCIENTIST], new Anim(isize[0], isize[1], 'auto', screenWidth*0.78, screenWidth*0.47 + lshift, screenHeight*0.312, screenHeight*0.27, 7*customSpeed, 1), morph, now()+1000, false, -1));
	isize = getImageSize(MERCHANT);
	chars.push(createAnimation(files[MERCHANT], new Anim(isize[0], isize[1], 'auto', screenWidth*0.28, screenWidth*0.395 + lshift, screenHeight*0.32, screenHeight*0.5405, 4*customSpeed, 1), morph, now()+1400, false, -1));
}

/**
 * Main cycle starter.
 * @param millis
 * @return
 */
function loop(millis) {
	g_nextGameTick = now();
	mainInterval = setInterval("mainLoop()", millis);
}

/**
 * Restart the page.
 * @return
 */
function restart() {
	window.document.body.innerHTML = "";//IE hack
	window.location = "index.html";
	return;
}

function fwdStatic() {
	window.location = "static.html";
	return;
}

/**
 * Main renderer cycle.
 */
function mainLoop() {
    g_loops = 0;
    var uc = 0;
    var pc = 0;
    while (now() > g_nextGameTick && g_loops < MAX_FRAMESKIP) {
        uc = update(false);
        g_nextGameTick += SKIP_TICKS;
        g_loops++;
    }
    if (doRestart.length > 0) {
    	var time = now();
    	for (var i = 0; i < doRestart.length; i++) {
    		if (doRestart[i].startTime <= time) {
    			var oid = doRestart[i].oid; 
    			renderObjects[oid].animation.restart();
    			renderObjects[oid].alive = true;
    			doRestart.splice(i, 1);
    		}
    	}
    }
    var interpolation = (now() + SKIP_TICKS - g_nextGameTick) / SKIP_TICKS;
    if (interpolation >= 0 && interpolation <= 1) {
    	pc = paint(interpolation, false);
    }
}

/**
 * Renderer cycle helper calculating dimensions.
 * @param forceUpdate true to update non-active elements
 */
function update(forceUpdate) {
	var c = 0;
	var time = now();
	for (var i = 0; i < renderObjects.length; i++) {
		try {
			if (renderObjects[i] != null) {
				var startTime = renderObjects[i].startTime;
				if (startTime <= time || forceUpdate) {
					var anim = renderObjects[i].animation;
					var dOpacity = renderObjects[i].destOpacity;
					/* position and scale[w opacity] */
					if (!renderObjects[i].animation.isDone()) {
						var onAnimationEnd = renderObjects[i].onEnd;
						anim.nextPosition();
						anim.nextSize();
						if (!forceUpdate && anim.isDone()) {
							if (onAnimationEnd != null) {
								onAnimationEnd();
							}
						}
						c++;
					}
					/* custom opacity */
					if (dOpacity >= 0) {
						var opacity = anim.getOpacity();
						if (opacity < dOpacity) {
							if (renderObjects[i].type == "text") {
								opacity += 0.07;
							} else {
								opacity += 0.05;
							}
							if (opacity >= dOpacity) {
								opacity = dOpacity;
							}
						} else {
							if (renderObjects[i].type == "text") {
								opacity -= 0.07;
							} else {
								opacity -= 0.033;
							}
							if (opacity <= 0.033) {
								opacity = dOpacity;
							}
						}
						anim.setOpacity(opacity);
					}
					c++;
				}
			}
		} catch (e) {
			checkErrors(e);
		}
	}
	return c;
}

/**
 * Repaint all renderObjects[]
 * @param interpolation percentual portion from position A to position B.
 * @param forcePaint true to paint even non-active elements.
 */
function paint(interpolation, forcePaint) {
	var c = 0;
	var time = now();
	for (var i = 0; i < renderObjects.length; i++) {
		try {
			if (renderObjects[i] != null && (renderObjects[i].alive || forcePaint)) {
				var startTime = renderObjects[i].startTime;
				if (startTime <= time || forcePaint) {
					setupImg(renderObjects[i], interpolation);
					c++;
				}
			}
		} catch (e) {
			checkErrors(e);
		}
	}
	return c;
}

/**
 * Renderer-object style setter.
 * @param object image or DIV
 * @param interpolation percentual portion from position A to position B.
 */
function setupImg(object, interpolation) {
	var anim = object.animation;
	var div = object.elem;
	var imgs = div.getElementsByTagName('img');
	var fade = object.fade;
	var sf = scaleFactor;
	if (anim.isPositioned()) {
		div.style.left = (marginH + (Math.round(anim.interpolateLeft(interpolation) * scaleFactor))) + 'px';
		div.style.top = (marginV + (Math.round(anim.interpolateTop(interpolation) * scaleFactor))) + 'px';
	}
	if (imgs[0] == null) {
		div.style.height = Math.round(anim.interpolateHeight(interpolation) * sf) + 'px';
		div.style.width = Math.round(anim.interpolateWidth(interpolation) * sf) + 'px';
		if (fade) {
			var opacity = 1 - anim.interpolateScale(interpolation);
			setElemOpacity(div, opacity);
		}
		if (object.destOpacity >= 0) {
			var o = anim.interpolateOpacity(interpolation);
			setElemOpacity(div, o);
			if (anim.getOpacity() == object.destOpacity) {
				object.destOpacity = -1;
			}
		}
	} else for (var i = 0; i < imgs.length; i++) {
		var img = imgs[i];
		if (object.type == "static") {
			img = div;
			if (IPHONE) {
				sf *= iPhoneScale;
			}
		}
		if (img != null) {
			img.height = Math.round(anim.interpolateHeight(interpolation) * sf);
			img.width = Math.round(anim.interpolateWidth(interpolation) * sf);
		} else {
			/* case the object doesn't contain an IMG element */
			div.style.height = Math.round(anim.interpolateHeight(interpolation) * sf) + 'px';
			div.style.width = Math.round(anim.interpolateWidth(interpolation) * sf) + 'px';
			img = div;
		}
		if (fade) {
			var opacity = 1 - anim.interpolateScale(interpolation);
			setElemOpacity(img, opacity);
		}
		if (object.destOpacity >= 0) {
			var o = anim.interpolateOpacity(interpolation);
			setElemOpacity(img, o);
			if (anim.getOpacity() == object.destOpacity) {
				object.destOpacity = -1;
			}
		}
	}
	if (anim.isDone() && object.destOpacity < 0) {
		object.alive = false;
	}
}

/**
 * Creates buttons from the HTML templates (see index.html).
 */
function createButtons() {
	var time = now();
	for (var i = 1; i < 9; i++) {
		for (var j = 1; j < 9; j++) {
			var id = "b" + i + j;
			var src = document.getElementById(id);
			if (src != null) {
				buttons.push(
					createTextAnimation(
						id, 
						new Anim(
							getGridElemWidth(), 
							getGridElemHeight(), 
							0, 
							getGridX(i), 
							getGridX(i),  
							getGridY(j), 
							getGridY(j), 
							0, 
							0
						), 
						null, time, false, 1
					)
				);
				var obj = renderObjects[buttons[buttons.length - 1]];
				var lh = Math.round(obj.animation.getHeight() * scaleFactor / innerLines(src.innerHTML));
				obj.elem.style.lineHeight = lh + 'px';
			}
		}
	}
	resizeObjects();
}

function getGridX(column) {
	return origWidth * (0.125 * (column - 1) + 0.0089);
}

function getGridY(row) {
	return origHeight * (0.107 * (row - 1) + 0.15);
}

function getGridElemWidth() {
	return origWidth * 0.105;
}

function getGridElemHeight() {
	return origHeight * 0.075;
}

function startRandomizer() {
	randomizerInterval = setInterval("randomizeCircles()", CIRCLES_RESTART_INTERVAL);
}

function randomizeCircles() {
	var groupId = Math.floor(Math.random() * restarted.length);
	var c = 0;
	for (var i = 0; i < doRestart.length; i++) {
		for (var j = 0; j < restarted[groupId].length; j++) {
			var id = restarted[groupId][j];
			if (renderObjects[id].alive) {
				c++;
				break;
			}
			if (id == doRestart[i].oid) {
				c++;
				break;
			}
			
		}
	}
	if (c == 0) {
		restartCircles(groupId, getCircleDelay());
	}
}

function createAndStartCircles() {
	var time = now();
	var customSpeed = 1;
	if (IPHONE) {
		customSpeed = iPhoneScale/2;
	}
	restarted.push(circles(screenWidth*0.762, screenHeight*0.613, getCircleCount(), getCircleDelay()*customSpeed, time));
	restarted.push(circles(screenWidth*0.297, screenHeight*0.285, getCircleCount(), getCircleDelay()*customSpeed, time + 250));
	restarted.push(circles(screenWidth*0.355, screenHeight*0.555, getCircleCount(), getCircleDelay()*customSpeed, time + 750));
	restarted.push(circles(screenWidth*0.736, screenHeight*0.303, getCircleCount(), getCircleDelay()*customSpeed, time + 350));
	restarted.push(circles(screenWidth*0.303, screenHeight*0.66, getCircleCount(), getCircleDelay()*customSpeed, time + 400));
	restarted.push(circles(screenWidth*0.640, screenHeight*0.226, getCircleCount(), getCircleDelay()*customSpeed, time + 50));
}

function getCircleCount() {
	return Math.round(Math.random() * (CIRCLES_COUNT_RANGE[1] - CIRCLES_COUNT_RANGE[0]) + CIRCLES_COUNT_RANGE[0]);
}

function getCircleDelay() {
	return Math.round(Math.random() * (CIRCLES_RESTART_DELAY_RANGE[1] - CIRCLES_RESTART_DELAY_RANGE[0]) + CIRCLES_RESTART_DELAY_RANGE[0]);
}

function restartCircles(groupIndex, delay) {
	var ids = restarted[groupIndex];
	var time = now();
	for (var i = 0; i < ids.length; i++) {
		doRestart.push({'oid': ids[i], 'startTime': (time + (i * delay))});
	}
}

/**
 * Resize background and sets relevant global variables.
 */
function resize() {
	var cWidth = document.documentElement.clientWidth;//window.innerWidth;//document.body.clientWidth;
	var cHeight = document.documentElement.clientHeight;//window.innerHeight;//document.body.clientHeight;
	
	var cRatio = cWidth / cHeight;
	var obj = document.getElementById('bgri');
	if (obj != null) {
		if (ratio < cRatio) {
			scaleFactor = cHeight / origHeight;
			if (scaleFactor < MIN_SIZE) {
				scaleFactor = MIN_SIZE;
				window.document.body.style.overflow = 'scroll';
			} else {
				window.document.body.style.overflow = 'hidden';
			}
			obj.height = Math.round(origHeight * scaleFactor);
			obj.width = Math.round(obj.height * ratio);
		} else {
			scaleFactor = cWidth / origWidth;
			if (scaleFactor < MIN_SIZE) {
				scaleFactor = MIN_SIZE;
				window.document.body.style.overflow = 'scroll';
			} else {
				window.document.body.style.overflow = 'hidden';
			}
			obj.width = Math.round(origWidth * scaleFactor);
			obj.height = Math.round(obj.width / ratio);
		}
		marginH = Math.round((cWidth - obj.width) / 2);
		marginV = MSIEWP7 ? 0 : Math.round((cHeight - obj.height) / 2);
		if (marginV < 0)
			marginV = 0;
		if (marginH < 0)
			marginH = 0;
		obj.style.marginLeft = marginH + 'px';
		obj.style.marginTop = marginV + 'px';
		resizeObjects();
		resizeInfo();
		paint(1, true);
		if (IPHONE) {
			window.scrollTo(0,1);
		}
	}
}

/**
 * Resizes all text animations registered within renderObjects.
 */
function resizeObjects() {
	var sf = customScale();
	for (var i = 0; i < renderObjects.length; i++) {
		var obj = renderObjects[i];		
		if (obj.type == "text") {
			if (obj.elem.className.startsWith("button")) {
				obj.elem.style.fontSize = Math.round(sf * 120) + '%';
				obj.elem.style.lineHeight = Math.round(obj.animation.getHeight() * scaleFactor / obj.lines) + 'px';
			} else {
				obj.elem.style.fontSize = Math.round(sf * 100) + '%';
				obj.elem.style.padding = Math.round(TEXT_PADDING * sf) + 'px';
				obj.elem.style.lineHeight = '0.9em';
			}
		}
	}
}

/**
 * Resizes active infoBox.
 */
function resizeInfo() {
	var bconf = config.getActiveButtonConfig();
	if (bconf != null) {
		var elem = bconf.infoBox;
		if (elem != null) {
			var coord = INFOBOX_POSITION;
			var size = INFOBOX_SIZE;
			if (bconf.coord != null && bconf.size != null) {
				coord = bconf.coord;
				size = bconf.size;
			}
			var sf = customScale();
			var left = (marginH + (getGridX(coord[0]) * scaleFactor));
			var right = (marginH + (getGridX(coord[0] + size[0] - 1) + getGridElemWidth()) * scaleFactor);
			var top = (marginV + (getGridY(coord[1]) * scaleFactor));
			var bottom = (marginV + (getGridY(coord[1] + size[1] - 1) + getGridElemHeight()) * scaleFactor);
			elem.style.left = left + 'px';
			elem.style.top = top + 'px';
			elem.style.width = (right - left) + 'px';
			elem.style.height = (bottom - top) + 'px';
			/* infoBox top */
			var control = config.getInfoBoxControl(bconf.id);
			if (control != null) {
				var cSize = Math.round(27 * scaleFactor);
				if (cSize < 17) cSize = 17;
				control.style.width = (right - left) + 'px';
				control.style.height = cSize + 'px';
				var fSize = (100 * sf);
				if (fSize < 62) fSize = 62;// 17/30*110 [%]
				control.style.fontSize = Math.round(fSize) + '%';
				var controlContent = document.getElementById('x' + bconf.id);
				if (controlContent != null) {
					controlContent.style.height = (cSize - 2) + 'px';
					controlContent.style.width = (cSize - 2) + 'px';
				}
			}
			/* infoBox bottom */
			control = config.getInfoBoxBottom(bconf.id);
			if (control != null) {
				var cSize = Math.round(27 * scaleFactor);
				if (cSize < 17) cSize = 17;
				control.style.width = (right - left) + 'px';
				control.style.height = cSize + 'px';
				var fSize = (100 * sf);
				if (fSize < 62) fSize = 62;// 17/30*110 [%]
				control.style.fontSize = Math.round(fSize) + '%';
				var controlContent = document.getElementById('x' + bconf.id);
				if (controlContent != null) {
					controlContent.style.height = (cSize - 2) + 'px';
					controlContent.style.width = (cSize - 2) + 'px';
				}
			}
			/* infoBox content */
			var content = elem.getElementsByTagName('div')[0];
			if (content != null) {
				content.style.height = (bottom - top - 2*cSize) + 'px';
				content.style.top = cSize + 'px';
				content.style.fontSize = Math.round(100 * sf) + '%';
			}
		}
	}
}

function circles(left, top, count, delay, startTime) {
	var cSize = CIRCLE_SIZE;
	var speed = 1;
	if (IPHONE) {
		cSize *= iPhoneScale;
		speed *= iPhoneScale;
	}
	var circleSize = getImageSize(CIRCLE);
	var ids = [];
	for (var i = 0; i < count; i++) {
		ids.push(createAnimation(files[CIRCLE], new Anim(cSize, cSize, 'auto', left+(cSize/2), left, top+(cSize/2), top, speed, 0), null, (startTime+(i*delay)), true, -1, false));
	}
	var dotSize = getImageSize(DOT);
	var shiftX = (cSize - dotSize[0]) / 2;
	var shiftY = (cSize - dotSize[1]) / 2;
	createAnimation(files[DOT], new Anim(dotSize[0], dotSize[1], 0, left+shiftX, left+shiftX, top+shiftY, top+shiftY, 0, 1), null, now(), false, -1);
	return ids;
}

function morph() {
	animationEnded--;
	if (animationEnded == 0) {
		resizeObjects();
		fadeTextIn("_r");
		setTimeout("startMorph()", 1500);
		setTimeout("morphText()", 3500);
		clearLog();
	}
}

function morphText() {
	fadeTextOut("_r");
	fadeTextIn("_f");
	setTimeout("createButtons()", 1000);
	setTimeout("showPosterAndLogos()", 1000);
}

function startMorph() {
	renderObjects[charGroup].destOpacity = 1;
	renderObjects[charGroup].alive = true;
	for (var i = 0; i < chars.length; i++) {
		renderObjects[chars[i]].destOpacity = 0;
		renderObjects[chars[i]].alive = true;
	}
}

function showPosterAndLogos() {
	renderObjects[poster].destOpacity = 1;
	renderObjects[poster].alive = true;
	renderObjects[twitter].destOpacity = 1;
	renderObjects[twitter].alive = true;
	renderObjects[facebook].destOpacity = 1;
	renderObjects[facebook].alive = true;
	renderObjects[google].destOpacity = 1;
	renderObjects[google].alive = true;
	renderObjects[minigame].destOpacity = 1;
	renderObjects[minigame].alive = true;
}

function skipAnimation() {
	clearLog();
	if (animationEnded > 0) {
		animationEnded = -1;
		startMorph();
		fadeTextOut("_r");
		fadeTextIn("_f");
		createButtons();
		showPosterAndLogos();
		for (var i = 0; i < renderObjects.length; i++) {
			if (renderObjects[i].startTime) {
				renderObjects[i].startTime = 0;
			}
		}
	}
}

function fadeTextIn(postfix) {
	var time = now();
	for (var i = 0; i < popTexts.length; i++) {
		var obj = renderObjects[popTexts[i]];
		if (obj.elem.id.endsWith(postfix)) {
			obj.alive = true;
			setElemOpacity (obj.elem, 0);
			obj.animation.setOpacity(0);
			obj.destOpacity = 1;
			obj.startTime = time;
		}
	}
}

function fadeTextOut(postfix) {
	var time = now();
	for (var i = 0; i < popTexts.length; i++) {
		var obj = renderObjects[popTexts[i]];
		if (obj.elem.id.endsWith(postfix)) {
			obj.alive = true;
			setElemOpacity (obj.elem, 1);
			obj.animation.setOpacity(1);
			obj.destOpacity = 0;
			obj.startTime = time;
		}
	}
}

function createAnimation(template, animation, onAnimationEnd, startTime, fade, destOpacity, alive, href, className) {
	if (alive == undefined || alive == null) {
		alive = true;
	}
	var imgDiv;
	if (href == null) {
		imgDiv = createImage(template, animation.opacity);
	} else {
		imgDiv = createImageLink(template, animation.opacity, href);
	}
	if (className) {
		imgDiv.className = className;
	}
//xxx imgDiv.style.display = 'none';
	document.body.appendChild(imgDiv);
	renderObjects.push({'type': "image", 'onEnd': onAnimationEnd, 'fade': fade, 'startTime': startTime, 'elem': imgDiv, 'animation': animation, 'destOpacity': destOpacity, 'alive': alive});
	var index = objectIndex;
	objectIndex++;
	return index;
}

function createTextAnimation(divId, animation, onAnimationEnd, startTime, fade, destOpacity) {
	var textDiv = cloneDiv(divId, animation.opacity);
	if (!(divId.endsWith("_r") || divId.endsWith("_f") || divId.endsWith("copyright"))) {
		addEvent(textDiv, 'mouseover', invertElemColors);
		addEvent(textDiv, 'mouseout', invertElemColors);
		var bConfig = config.buttons[divId];
		var cutBytes = config.eventMark.length;
		if (bConfig) {
			for (var key in bConfig) {
				if (key.startsWith(config.eventMark)) {
					addEvent(textDiv, key.substring(cutBytes), eval(bConfig[key]));
				}
			}
		}
	}
	document.body.appendChild(textDiv);
	var lineCount = innerLines(textDiv.innerHTML);
	renderObjects.push({'type': "text", 'onEnd': onAnimationEnd, 'fade': fade, 'startTime': startTime, 'elem': textDiv, 'animation': animation, 'destOpacity': destOpacity, 'alive': true, 'lines': lineCount});
	var index = objectIndex;
	objectIndex++;
	return index;
}

function createImage(url, opacity) {
	var img = MSIE ? new Image() : document.createElement('img');
	img.src = url;
	img.style.position = 'absolute';
	img.width = 0;
	img.height = 0;
	setElemOpacity (img, opacity);
	var div = document.createElement('div');
	div.appendChild(img);
	div.style.position = 'absolute';
	return div;
}

function createImageLink(url, opacity, href) {
	if (typeof url == 'string') {
		var img = MSIE ? new Image() : document.createElement('img');
		img.src = url;
		img.style.position = 'absolute';
		img.style.border = 'none';
		img.width = 0;
		img.height = 0;
		setElemOpacity (img, opacity);
		
		var a = document.createElement('a');
		a.style.position = 'absolute';
		a.style.display = 'block';
		a.style.width = '100%';
		a.style.height = '100%';
		//a.onmouseover = showImage1;
		//a.onmouseout = showImage0;
		a.href = href;
		
		a.appendChild(img);
	} else {
		var img = MSIE ? new Image() : document.createElement('img');
		img.src = url[0];
		img.style.position = 'absolute';
		img.style.border = 'none';
		img.width = 0;
		img.height = 0;
		setElemOpacity (img, opacity);
		var img2 = MSIE ? new Image() : document.createElement('img');
		img2.src = url[1];
		img2.style.position = 'absolute';
		img2.style.border = 'none';
		img2.style.visibility = 'hidden';
		img2.width = 0;
		img2.height = 0;
		setElemOpacity (img2, opacity);
		var a = document.createElement('a');
		a.style.position = 'absolute';
		a.style.display = 'block';
		a.style.width = '100%';
		a.style.height = '100%';
		a.onmouseover = showImage1;
		a.onmouseout = showImage0;
		a.href = href;
		a.appendChild(img);
		a.appendChild(img2);
	}

	/*
	a.style.cursor = 'default';
	a.onclick = function(e) { e.preventDefault(); return false; };
	disabledLinks.push(a);
	setTimeout(function() {
		a.style.cursor = 'pointer';
		a.onclick = null;
	}, 10000);
	*/

	var div = document.createElement('div');
	div.appendChild(a);
	div.style.position = 'absolute';
	return div;
}

function cloneDiv(divId, opacity) {
	var srcDiv = document.getElementById(divId);
	var newDiv = document.createElement('div');
	newDiv.id = "cloned_" + divId;//used in showTexts()
	newDiv.innerHTML = srcDiv.innerHTML;
	newDiv.className = srcDiv.className;
	newDiv.style.display = 'block';
	if (IPHONE) {
		newDiv.style.borderWidth = '1px';
	}
	setElemOpacity (newDiv, opacity);
	return newDiv;
}

function setupBackground() {
	var obj = createImage(files[BACKGROUND], 1);
	obj.style.top = 0;
	document.body.appendChild(obj);
	var img = obj.getElementsByTagName('img')[0];
	img.id = 'bgri';
	if (img != null) {
		var isize = getImageSize(BACKGROUND);
		origWidth = isize[0];
		origHeight = isize[1];
		ratio = origWidth / origHeight;
		return isize;
	}
	return null;
}

function invertElemColors(e) {
	e = e || window.event;
	var elem = e.target || e.srcElement;
	elem = getButtonElem(elem);
	if (elem) {
		var oid = elem.id.substring(elem.id.indexOf("_") + 1);
		var obj = config.getButtonConfig(oid);
		var clazz = "." + elem.className;
		if (obj != null && !obj.clicked) {
			obj.over = !obj.over;
			var bColor;
			if (obj.over) {
				bColor = CLICKED_BUTTON_FONT_COLOR;
			} else {
				bColor = getStyleRule(clazz, "backgroundColor");
			}
			elem.style.backgroundColor = bColor;
			elem.style.borderColor = bColor;
		}
		return elem;
	}
	return null;
}

function showImage0(e) {
	e = e || window.event;
	var elem = e.target || e.srcElement;
	elem = elem.parentNode;
	var obj = elem.getElementsByTagName("img")[0];
	obj.style.visibility = 'visible';
	obj = elem.getElementsByTagName("img")[1];
	obj.style.visibility = 'hidden';
}

function showImage1(e) {
	e = e || window.event;
	var elem = e.target || e.srcElement;
	elem = elem.parentNode;
	var obj = elem.getElementsByTagName("img")[0];
	obj.style.visibility = 'hidden';
	obj = elem.getElementsByTagName("img")[1];
	obj.style.visibility = 'visible';
}

/**
 * Manages button look and triggers showInfo(e) or hideInfo(e)
 * @param e event captured on the button 
 */
function switchInfo(e) {
	e = e || window.event;
	var elem = e.target || e.srcElement;
	var elem = getButtonElem(elem);
	var oid = elem.id.substring(elem.id.indexOf("_") + 1);
	if (config.getInfoBox(oid) == null) {
		return false;
	}
	var thisClicked = config.getButtonConfig(oid).clicked;
	resetButtonStatesButThis(oid);
	thisClicked = !thisClicked;
	config.getButtonConfig(oid).clicked = thisClicked;
	if (thisClicked) {
		var obj = config.getButton(oid);
		if (obj != null) {
			/* activate button */
			obj.style.color = CLICKED_BUTTON_FONT_COLOR;
			obj.style.borderColor = CLICKED_BUTTON_FONT_COLOR;
			if (IPHONE) {
				obj.style.borderWidth = '1px';
			}
			obj.style.backgroundColor = "transparent";
			obj.style.backgroundImage = 'url('+ files[SHADE_BUTTON] +')';
		}
		showInfo(e);
		resizeInfo();
		inspectScrollBar(getButtonEventRespondingInfo(e).content);
		paint(1, true);
	} else {
		var obj = config.getButton(oid);
		if (obj != null) {
			/* deactivate button (remains hovered) */
			obj.style.color = getStyleRule(".button", "color");
			if (IPHONE) {
				obj.style.borderWidth = '1px';
			}
			obj.style.borderColor = ACTIVE_BUTTON_BGCOLOR;
			obj.style.backgroundColor = ACTIVE_BUTTON_BGCOLOR;
			obj.style.backgroundImage = '';
		}
		hideInfo(e);
	}
}

function showInfo(e) {
	var obj = getButtonEventRespondingInfo(e);
	if (obj != null) {
		obj.style.display = 'block';
	}
}

function hideInfo(e) {
	var obj = getButtonEventRespondingInfo(e);
	if (obj != null) {
		obj.style.display = 'none';
	}
}

function getButtonEventRespondingInfo(e) {
	e = e || window.event;
	var elem = e.target || e.srcElement;
	elem = getButtonElem(elem);
	var id = "i" + elem.id.substring(elem.id.indexOf("_") + 2);
	return document.getElementById(id);
}

function getButtonElem(elem) {
	while (!elem.className.startsWith("button")) {
		if (elem.parentNode != null && elem != elem.parentNode) {
			elem = elem.parentNode;
		} else {
			return null;
		}
	}
	return elem;
}

function resetButtonStatesButThis(oid) {
	for (var bKey in config.buttons) {
		if (bKey != "undefined" && bKey != oid) {
			config.buttons[bKey].clicked = false;
			config.buttons[bKey].over = false;
			var obj = config.getButton(bKey);
			if (obj != null) {
				var clazz = "." + obj.className;
				/* deactivate button */
				obj.style.color = getStyleRule(clazz, "color");
				if (IPHONE) {
					obj.style.borderWidth = '1px';
				}
				obj.style.backgroundImage = '';
				bColor = getStyleRule(clazz, "backgroundColor");
				obj.style.backgroundColor = bColor;
				obj.style.borderColor = bColor;
			}
			obj = config.getInfoBox(bKey);
			if (obj != null) {
				/* close window */
				obj.style.display = 'none';
			}
			
		}
	}
}

function getStyleRule(ruleClass, property) {
	if (cssRuleCache[ruleClass] != null) {
		var prop = cssRuleCache[ruleClass];
		if (prop[property] != null) {
			return prop[property];
		}
	}
	for (var s = 0; s < document.styleSheets.length; s++) {
		var sheet = document.styleSheets[s];
		if (sheet.href.endsWith("index.css")) {
			var rules = sheet.cssRules ? sheet.cssRules : sheet.rules;
			if (rules == null) return null;
			for (var i = 0; i < rules.length; i++) {
				var rule = rules[i];
				if (rule.selectorText == ruleClass) {
					var item = cssRuleCache[ruleClass] || {};
					item[property] = rule.style[property];
					cssRuleCache[ruleClass] = item;
					return item[property];
				}
			}
		}
	}
	return null;
}

function setElemOpacity(element, opacity) {
	if (element.style.opacity != null) {
		element.style.opacity = Math.round(opacity * 100) / 100;
	} else {
		element.style.filter = 'alpha(opacity=' + Math.round(opacity * 100) + ')';
	}
};

function getImageSize(ID) {
	return [preloader.getCache()[ID].origWidth, preloader.getCache()[ID].origHeight];
}

function checkErrors(e) {
	log(e.toString() + '<br>');
	errorCount++;
	if (errorCount > 10) {
		clearInterval(mainInterval);
		log('<br>Stopped due to errors.<br>');
	}
}

function addEvent(obj, event, funct) {  
	if (obj.attachEvent) { //IE  
		obj['e' + event + funct] = funct;  
		obj['x' + event + funct] = function() {  
			obj['e' + event + funct](window.event);  
		};  
		obj.attachEvent('on' + event, obj['x' + event + funct]);  
	} else {// other browser  
		obj.addEventListener(event, funct, false);  
	}
}

function hideParent(e) {
	e = e || window.event;
	var elem = e.target || e.srcElement;
	elem.parentNode.parentNode.style.display = 'none';
	resetButtonStatesButThis(null);
}

function inspectScroll(e) {
	try {
		e = e || window.event;
		var elem = e.target || e.srcElement;
		inspectScrollBar(elem);
	} catch(e) {
		//log(e.toString());
	}
}

function scrollDown(elem) {
	elem = elem.parentNode.parentNode.children[0];
	var diff = (elem.scrollHeight - elem.offsetHeight - 1) - elem.scrollTop;
	if (elem.scrollTop < (elem.scrollHeight - elem.offsetHeight - 1)) {
		if (diff > scrollPixels) diff = scrollPixels;
		elem.scrollTop += diff;
	}
}

function scrollUp(elem) {
	elem = elem.parentNode.parentNode.children[0];
	var diff = elem.scrollTop;
	if (elem.scrollTop > 0) {
		if (diff > scrollPixels) diff = scrollPixels;
		elem.scrollTop -= diff;
	}
}

/**
 * @param elem instance of infoBoxContent
 */
function inspectScrollBar(elem) {
	if (elem == undefined || elem == null) {
		return false;
	}
	if (elem.scrollTop == 0) {
		elem.parentNode.topControl.children[0].style.visibility = 'hidden';
	} else {
		elem.parentNode.topControl.children[0].style.visibility = 'visible';
	}
	if (elem.scrollTop >= (elem.scrollHeight - elem.offsetHeight - 1)) {
		elem.parentNode.bottomControl.children[0].style.visibility = 'hidden';
	} else {
		elem.parentNode.bottomControl.children[0].style.visibility = 'visible';
	}
}

function customScale() {
	if (IPHONE) return iPhoneScale * scaleFactor; 
	if (IPAD) return  iPadScale * scaleFactor;
	return scaleFactor;
}

function now() {
	return (new Date()).getTime();
}
