var Tutorial = Class.create();
Object.extend(Tutorial, {
			current : null,
			items : {
				battle1 : "b/map{tuto:'battle1'}",
				battle2 : "b/map{tuto:'battle2'}"
			},
			itemName : function(id) {
				return ti('tutorial.items.' + id);
			},
			showMenu : function(e) {
				var items = $H(this.items).keys().collect(function(tuto, i) {
							return {
								text : (i + 1) + '/ ' + this.itemName(tuto),
								link : "PageManager.navigateToTuto('" + tuto + "');"
							};
						}, this);
				ContextMenu.open(Event.pointerX(e), Event.pointerY(e), [{
									text : ti('tutorial.menuTitle'),
									items : items
								}], false);
			},
			stop : function() {
				if (this.current) {
					this.current.stop();
				}
			}
		});
Tutorial.prototype = {
	/**
	 * @type {Boolean}
	 */
	canStop : true,
	/**
	 * @type {Array}
	 */
	steps : null,
	/**
	 * @type {Function}
	 */
	textReader : null,
	/**
	 * @type {Function}
	 */
	stopCallback : null,
	/**
	 * @type {String}
	 */
	continueWith : null,

	clickListenerB : null,
	keypressListenerB : null,
	masks : null,
	current : null,
	checkConditionTimeout : null,
	stopped : false,

	initialize : function(options) {
		Tutorial.stop();
		Tutorial.current = this;

		Object.extend(this, options);
	},

	start : function(stepIndex) {
		if (this.stopped) {
			return;
		}

		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;',
					style : 'position:absolute;top:0px;left:0px;z-index:1000;',
					className : 'tutorialText tutorialTextFake left top'
				}));

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

		Windows.windows.invoke('close');

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

		this.goToStep();
	},

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

		this.stopped = true;
		if (this.current) {
			document.stopObserving("click", this.clickListenerB);
			document.stopObserving("keypress", this.keypressListenerB);
			window.clearTimeout(this.checkConditionTimeout);

			this.current = null;

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

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

		Tutorial.current = null;

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

	goToStep : function(stepIndex) {
		if (this.stopped) {
			return;
		}

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

		var isLastStep = false;
		var step;
		if (stepIndex >= this.steps.length) {
			if (stepIndex > this.steps.length) {
				this.stop();
				return;
			} else {
				isLastStep = true;
				step = {
					elm : false,
					text : ('<div>' + ti('tutorial.beforeStopMsg', null, {
								newBattleAi : '<a href="javascript:void(0);" class="tutorialBattleNewAi">',
								newBattleNewbieSponsor : '<a href="javascript:void(0);" class="tutorialBattleNewNewbieSponsor">',
								end : '</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];
		}

		step.params = step.params || {};
		if (step.tpl) {
			(Object.isArray(step.tpl) ? step.tpl : [step.tpl]).each(function(tpl) {
				var o = {};
				switch (tpl) {
					case 'detailPre' :
						o.checkAccess = function(step, action, params, callback) {
							var entity = mp.entity.getObj(step.params.entityId, step.params.entityType);
							var iState = entity.state;
							switch (true) {
								case mp.entity.haveState(iState, 'onBF', step.params.entityType) :
									return ("mapAction" == action && 'battleField' == params.sZone
											&& entity.posX == params.aParam[0] && entity.posY == params.aParam[1]);
									break;
								case mp.entity.haveState(iState, 'inPit', step.params.entityType) :
									return ("mapAction" == action && 'pit' == params.sZone
											&& step.params.entityType == params.aParam[0] && step.params.entityId == params.aParam[1]);
									break;
							}
						};
						o.condition = function(step) {
							return mp.map.bBoxInfoDetail && step.params.entityType == mp.map.iBoxInfoDetailType
									&& step.params.entityId == mp.map.iBoxInfoDetailId;
						};
						break;

					case 'actionPre' :
						o.checkAccess = function(step, action, params, callback) {
							var entity = mp.entity.getObj(step.params.entityId, step.params.entityType);
							if ("mapAction" == action && 'battleField' == params.sZone && entity.posX == params.aParam[0]
									&& entity.posY == params.aParam[1]) {
								return true;
							}
							return ("battleAction" == action && step.params.entityType == params[0]
									&& step.params.entityId == params[1] && step.params.effectId == params[2]);
						};
						o.condition = function(step) {
							return mp.battle.action.bInProgress && step.params.entityType == mp.battle.action.iEntityType
									&& step.params.entityId == mp.battle.action.iEntityId
									&& step.params.effectId == mp.battle.action.iActionId;
						};
						break;

					case 'action' :
						step.params._action = true;
					case 'actionPost' :
						o.condition = false;
						o.checkAccess = function(step, action, params, callback) {
							if ("mapAction" == action && 'battleField' == params.sZone) {
								if ($A(step.params.mapActionAllowedPos).any(function(pos) {
											return pos.x == params.aParam[0] && pos.y == params.aParam[1];
										})) {
									return true;
								}
							}
							if (step.params._action && "battleAction" == action && step.params.entityType == params[0]
									&& step.params.entityId == params[1] && step.params.effectId == params[2]) {
								return true;
							}
							if ("action" == action && step.params.entityType == mp.battle.action.iEntityType
									&& step.params.entityId == mp.battle.action.iEntityId
									&& step.params.effectId == mp.battle.action.iActionId) {
								if (step.params.checkActionValues(mp.battle.action.aRefActionInput.pluck('value'))) {
									this.goToStep.bind(this).defer();
								}
							}
							return false;
						};
						break;

					case 'goNext' :
						o.protectElm = true;
						o.elm = 'page_content';
						o.init = function(step) {
							if (step.params.data) {
								mp.replay.dataLoaded(this.externalDatas[step.params.data], true);
							} else {
								mp.replay.slideshow();
							}
						};
						o.checkAccess = function() {
							return true;
						};
						o.condition = function(step) {
							return !mp.replay.showInProgress && mp.strategicData.isLastEventDisplayed();
						};
						break;

					case 'transparent' :
						o.condition = true;
						o.protectElm = true;
						o.elm = 'page_content';
						break;
				}
				for (p in o) {
					if (Object.isUndefined(step[p])) {
						step[p] = o[p];
					}
				}
			}, this);
			delete step.tpl;
		}

		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;

		var text = (step.text || this.textReader(step, stepIndex))
		if (text) {
			this.masks.textFake.style.visibility = 'visible';
			this.masks.textFake.innerHTML = ('<div class="ctn">'
					+ ('<div class="content">'
							+ ('<div class="text">' + text + '</div>')
							+ ('<div class="toolbox">'
									+ (isLastStep || null != this.current.condition ? '' : ('<div class="next">'
											+ ti('tutorial.next') + '</div>'))
									+ (isLastStep || this.canStop
											? ('<div class="quit">' + ti('tutorial.quit') + '</div>')
											: '') + '</div>') + '</div>') + '</div>');
		}

		this.positionMasks();
		this.masks.text.innerHTML = '';
		if (text) {
			this.masks.text.style.visibility = 'visible';
			this.masks.text.appendChild(this.masks.textFake.removeChild(this.masks.textFake.childNodes[0]));
			var quitBtn = this.masks.text.select(".toolbox .quit")[0]
			if (quitBtn) {
				quitBtn.observe('click', function(ev) {
							ev.stop();
							this.stop();
						}.bind(this));
			}
		} else {
			this.masks.textFake.style.visibility = 'hidden';
		}

		if (Object.isFunction(step.init)) {
			step.init.call(this, this.current);
		}

		if (null != this.current.condition && false !== 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:true}");
			return;
		}
		if (ev.findElement(".tutorialBattleNewNewbieSponsor")) {
			this.continueWithListener(ev, "r/battleList{newNewbieSponsor:true}");
			return;
		}

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

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

	keypressListener : function(ev) {
		if (this.canStop && 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)
				: this.current.condition;
		if (b) {
			this.goToStep();
		} else {
			this.checkConditionTimeout = 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;
		var textFakeDimMaxWidth = 600;
		if (textFakeDim.width > textFakeDimMaxWidth) {
			this.masks.textFake.setStyle({
						width : textFakeDimMaxWidth + "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 + 10)) {
				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');
			}
			var rewidth = false;
			switch (side) {
				case 'left' :
					left -= (textFakeDim.width + refDim.width) + 6;
					break;
				case 'right' :
					left += 2;
					break;
				case 'top' :
					left -= refDim.width;
					top -= Math.max(110, textFakeDim.height) + 2;
					rewidth = true;
					break;
				case 'bottom' :
					left -= refDim.width;
					top += refDim.height + 2
					rewidth = true;
					break;
			}
			if (rewidth) {
				var textFakeDimMaxWidth = (screenDim.width - left);
				if (textFakeDim.width > textFakeDimMaxWidth) {
					textFakeDim.width = textFakeDimMaxWidth;
				}
			}
		} 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);
		}
	},

	checkAccess : function(action, params, callback) {
		var ok = false;
		if (this.current.checkAccess) {
			var args = [this.current];
			args.push.apply(args, arguments);
			ok = this.current.checkAccess.apply(this, args);
		}
		if (!ok) {
			if (callback) {
				callback();
			}
		}
		return ok;
	}

};

