Tutorial = Class.create();
Object.extend(Tutorial, {
			items : {
				battle1 : "b/map&tuto=battle1",
				battle2 : "b/map&tuto=battle2"
			},
			itemName : function(id) {
				return ti('tutorial.items.' + id);
			}
		});
Tutorial.prototype = {
	/**
	 * @type {Array}
	 */
	steps : null,
	/**
	 * @type {Function}
	 */
	textReader : null,
	/**
	 * @type {Function}
	 */
	stopCallback : null,
	/**
	 * @type {String}
	 */
	continueWith : null,

	clickListenerB : null,
	keypressListenerB : null,
	masks : null,
	current : null,

	initialize : function(options) {
		Object.extend(this, options);
	},

	start : function(stepIndex) {
		this.clickListenerB = this.clickListener.bindAsEventListener(this);
		this.keypressListenerB = this.keypressListener.bindAsEventListener(this);

		this.masks = {};
		['t', 'r', 'b', 'l'].each(function(part) {
					this.masks[part] = document.body.appendChild(new Element('div', {
								className : 'tutorialMask',
								style : 'position:absolute;z-index:9000;'
							}));
				}, this);
		this.masks.elm = document.body.appendChild(new Element('div', {
					style : 'position:absolute;z-index:9000;'
				}));
		this.masks.text = document.body.appendChild(new Element('div', {
					style : 'position:absolute;z-index:9001;',
					className : 'tutorialText'
				}));
		this.masks.textFake = document.body.appendChild(new Element('div', {
					style : 'position:absolute;top:0px;left:0px;z-index:-1;visibility:hidden;',
					className : 'tutorialText tutorialTextFake left top'
				}));

		this.current = {
			index : (stepIndex || 0) - 1
		};

		document.observe("keypress", this.keypressListenerB);
		document.observe("click", this.clickListenerB);

		this.goToStep();
	},

	stop : function(noCallback) {
		if (!this.current) {
			return;
		}

		document.stopObserving("click", this.clickListenerB);
		document.stopObserving("keypress", this.keypressListenerB);

		this.current = null;

		$H(this.masks).values().invoke("remove");

		this.keypressListenerB = null;
		this.clickListenerB = null;

		if (true !== noCallback && this.stopCallback) {
			this.stopCallback();
		}
	},

	goToStep : function(stepIndex) {
		if (Object.isUndefined(stepIndex)) {
			stepIndex = this.current.index + 1;
		}

		var step;
		if (stepIndex >= this.steps.length) {
			if (stepIndex > this.steps.length) {
				this.stop();
				return;
			} else {
				step = {
					elm : false,
					text : ('<div>' + ti('tutorial.beforeStopMsg', null, {
								link : '<a href="javascript:void(0);" class="tutorialBattleNewAi">' + ti('ai.name') + '</a>'
							}) + '</div>') + (!this.continueWith ? '' : ('<br/>' + ti('tutorial.continueWithMsg', null, {
								link : '<a href="javascript:void(0);" class="tutorialContinueWithLink">'
										+ Tutorial.itemName(this.continueWith) + '</a>'
							})))
				};
			}
		} else {
			step = this.steps[stepIndex];
		}

		var elms = step.elm;
		if (Object.isFunction(elms)) {
			elms = elms();
		}
		if (Object.isString(elms)) {
			elms = $(elms);
		}
		if (null == elms || Object.isUndefined(elms)) {
			this.goToStep.bind(this).delay(0.2, stepIndex);
			return;
		}
		if (elms) {
			if (Object.isArray(elms)) {
				elms = elms.collect(function(elm) {
							return $(elm);
						});
			} else {
				elms = [$(elms)];
			}
		}

		this.current = {
			index : stepIndex,
			condition : Object.isUndefined(step.condition) ? null : step.condition,
			elms : elms,
			checkAccess : step.checkAccess,
			params : step.params
		};
		this.current.protectElm = Object.isUndefined(step.protectElm) ? null == step.condition : step.protectElm;

		this.masks.textFake.innerHTML = '<div class="content">'
				+ ('<div class="text">' + (step.text || this.textReader(step, stepIndex)) + '</div>')
				+ ('<div class="toolbox">'
						+ (null != this.current.condition ? '' : ('<div class="next">' + ti('tutorial.next') + '</div>'))
						+ ('<div class="quit">' + ti('tutorial.quit') + '</div>') + '</div>') + '</div>';

		this.positionMasks();
		this.masks.text.innerHTML = '';
		this.masks.text.appendChild(this.masks.textFake.removeChild(this.masks.textFake.childNodes[0]));

		this.masks.text.select(".toolbox .quit")[0].observe('click', function(ev) {
					ev.stop();
					this.stop();
				}.bind(this));

		if (null != this.current.condition) {
			this.checkCondition();
		}
	},

	clickListener : function(ev) {
		if (null != this.current.condition) {
			return;
		}

		if (ev.findElement(".tutorialContinueWithLink")) {
			this.continueWithListener(ev);
			return;
		}
		if (ev.findElement(".tutorialBattleNewAi")) {
			this.continueWithListener(ev, "r/battleList&newAi=1");
			return;
		}

		ev.stop();
		this.goToStep();
	},

	continueWithListener : function(ev, link) {
		ev.stop();
		this.stop(true);
		PageManager.goTo(link || ("tuto://" + this.continueWith));
	},

	keypressListener : function(ev) {
		if (ev.keyCode == Event.KEY_ESC) {
			ev.stop();
			this.stop();
		} else if (null == this.current.condition
				&& ([Event.KEY_TAB, Event.KEY_RETURN, Event.KEY_RIGHT, Event.KEY_PAGEDOWN].indexOf(ev.keyCode) > -1 || 32 == ev.charCode)) {
			ev.stop();
			this.goToStep();
		}
	},

	checkCondition : function() {
		if (!this.current) {
			return;
		}
		var b = Object.isFunction(this.current.condition)
				? this.current.condition.call(this)
				: this.current.condition;
		if (b) {
			this.goToStep();
		} else {
			this.checkCondition.bind(this).delay(0.2);
		}
	},

	positionMasks : function() {
		var refPos, refDim;

		var screenDim = document.viewport.getDimensions();
		var docDim = {
			width : Math.max(document.body.scrollWidth, screenDim.width),
			height : Math.max(document.body.scrollHeight, screenDim.height)
		};
		if (this.current.elms) {
			refPos = {
				top : Number.MAX_VALUE,
				left : Number.MAX_VALUE,
				bottom : 0,
				right : 0
			};
			$A(this.current.elms).each(function(elm) {
						var refPosTmp = elm.cumulativeOffset();
						var refDimTmp = elm.getDimensions();
						refPos.top = Math.min(refPos.top, refPosTmp.top);
						refPos.left = Math.min(refPos.left, refPosTmp.left);
						refPos.bottom = Math.max(refPos.bottom, refPosTmp.top + refDimTmp.height);
						refPos.right = Math.max(refPos.right, refPosTmp.left + refDimTmp.width);
					});
			refDim = {
				width : refPos.right - refPos.left,
				height : refPos.bottom - refPos.top
			};
		} else {
			refPos = {
				top : 0,
				left : 0
			};
			refDim = {
				width : 0,
				height : 0
			};
		}
		var margin = 2;
		var posTop = refPos.top - margin;
		var posRight = refPos.left + refDim.width + margin;
		var posBottom = refPos.top + refDim.height + margin;
		var posLeft = refPos.left - margin;

		$(this.masks.t).setStyle({
					top : 0 + "px",
					left : 0 + "px",
					width : docDim.width + "px",
					height : Math.max(0, posTop) + "px"
				});
		this.masks.r.setStyle({
					top : posTop + "px",
					left : posRight + "px",
					width : (docDim.width - posRight) + "px",
					height : (posBottom - posTop) + "px"
				});
		this.masks.b.setStyle({
					top : posBottom + "px",
					left : 0 + "px",
					width : docDim.width + "px",
					height : (docDim.height - posBottom) + "px"
				});
		this.masks.l.setStyle({
					top : posTop + "px",
					left : 0 + "px",
					width : Math.max(0, posLeft) + "px",
					height : (posBottom - posTop) + "px"
				});
		this.masks.elm.setStyle({
					display : (this.current.protectElm ? "" : "none"),
					top : posTop + "px",
					left : posLeft + "px",
					width : (posRight - posLeft) + "px",
					height : (posBottom - posTop) + "px"
				});

		this.masks.textFake.setStyle({
					width : ""
				});
		var screenDim = document.viewport.getDimensions();
		var screenScroll = document.viewport.getScrollOffsets();
		var textFakeDim = this.masks.textFake.getDimensions();
		var top, left, side;
		if (textFakeDim.width > screenDim.width * 0.5) {
			this.masks.textFake.setStyle({
						width : (screenDim.width * 0.5) + "px"
					});
			textFakeDim = this.masks.textFake.getDimensions();
		}
		if (this.current.elms) {
			top = posTop;
			left = posRight;
			var availableSpaceLeft = refPos.left - screenScroll.left;
			var availableSpaceRight = screenDim.width - (refPos.left - screenScroll.left) - refDim.width;
			if (Math.max(availableSpaceLeft, availableSpaceRight) >= textFakeDim.width) {
				side = (availableSpaceLeft > availableSpaceRight ? 'left' : 'right');
			} else {
				var availableSpaceTop = refPos.top - screenScroll.top;
				var availableSpaceBottom = screenDim.height - (refPos.top - screenScroll.top) - refDim.height;
				side = (availableSpaceTop > availableSpaceBottom ? 'top' : 'bottom');
			}
			switch (side) {
				case 'left' :
					left -= (textFakeDim.width + refDim.width) + 6;
					break;
				case 'right' :
					left += 2;
					break;
				case 'top' :
					left -= refDim.width;
					top -= textFakeDim.height + 2;
					break;
				case 'bottom' :
					left -= refDim.width;
					top += refDim.height + 2
					break;
			}
		} else {
			side = null;
			left = screenScroll[0] + ((screenDim.width - textFakeDim.width) / 2);
			top = screenScroll[1] + ((screenDim.height - textFakeDim.height) / 2);
		}
		this.masks.text.setStyle({
					top : top + "px",
					left : left + "px",
					width : textFakeDim.width + "px"
				});
		this.masks.text.removeClassName('left');
		this.masks.text.removeClassName('right');
		this.masks.text.removeClassName('top');
		this.masks.text.removeClassName('bottom');
		if (side) {
			this.masks.text.addClassName(side);
		}
	}
};
