﻿var box = { x:0, y:0 };

var letterChar = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '.', ',', ':', '-', '_', '!', '?'];
var letterWidth = [13, 11, 14, 14, 15, 13, 13, 14, 13, 14, 19, 16, 18, 19, 13, 13, 19, 19, 8, 10, 17, 13, 23, 18, 22, 15, 22, 17, 14, 16, 17, 19, 27, 17, 18, 17, 7, 8, 7, 10, 15, 7, 10];
var letterLeft = [];

(function ()
{
	var window = this, undefined;

	// *** Catching System Events ***
	$.addEvent(window, 'load', function (e)
	{
		return $.returnEvent(e, Game.init(e));
	});

	var mouseHideTimeout = null;
	var statusBarUpdateInterval = null;

	window["Game"] = {
		// *** Constants ***

		STATE_SPLASH_SCREEN: 0,
		STATE_LEVEL_SELECTION: 1,
		STATE_HELP: 2,
		STATE_ABOUT: 3,
		STATE_GAME: 4,

		// *** Variables ***

		splitAsSoonAsPossible: false,

		startTime: null,
		moves: 0,

		currentState: 0,
		currentPyramid: 0,

		enteredKey: '',

		// *** Functions ***

		init: function ()
		{
			// Required for backspace handling in IE (onkeydown) and Opera (onkeypress)
			document.onkeydown = function () { return false; };
			document.onkeypress = function () { return false; };
			
			$.addEvent(document, 'keydown', function (e)
			{
				return $.returnEvent(e, Input.keyDown(e));
			});

			$.addEvent(document, 'keyup', function (e)
			{
				return $.returnEvent(e, Input.keyUp(e));
			});
			// $.setUnselectable($('contentDiv'));
			$.setUnselectable($('splashDiv'));
			$.setUnselectable($('levelSelectorDiv'));
			$.setUnselectable($('gameDiv'));
			$.setUnselectable($('statusBarDiv'));

			$.addEvent(window, 'resize', function (e)
			{
				if (Game.currentState == this.STATE_GAME) { Draw.build(); }

				return $.returnEvent(e, true);
			});

			$.addEvent($('gameDiv'), 'mousemove', function (e)
			{
				if (mouseHideTimeout != null)
				{
					clearTimeout(mouseHideTimeout);
				}
				mouseHideTimeout = setTimeout(function ()
				{
					mouseHideTimeout = null;
					$('gameDiv').style.cursor = 'url("nocursor.cur"), default';
				}, 1000);

				$('gameDiv').style.cursor = 'auto';

				return $.returnEvent(e, true);
			});

			// IPhone - Prevent scrolling
			$.addEvent(document, 'touchmove', function(e)
			{
				e.preventDefault();
			});

			for (var i = 0, j = 0; i < letterWidth.length; i++)
			{
				letterLeft.push(j);
				j -= letterWidth[i];
			}

			this.setState(this.STATE_SPLASH_SCREEN);

			return true;
		},

		setState: function (newState)
		{
			if (newState == this.STATE_GAME && this.getPyramidLevelState(arguments[1]) == Level.PLAYER_STATE_LOCKED)
			{
				return;
			}

			switch (this.currentState)
			{
				case this.STATE_SPLASH_SCREEN:	// Start screen
					$('splashDiv').style.display = 'none';
					break;

				case this.STATE_LEVEL_SELECTION:	// Level selection
					$('levelOverviewDiv').style.display = 'none';
					break;

				case this.STATE_HELP:			// Help screen
					$('helpDiv').style.display = 'none';
					break;

				case this.STATE_ABOUT:			// About screen
					$('aboutDiv').style.display = 'none';
					break;

				case this.STATE_GAME:			// In game
					$('gameDiv').style.display = 'none';
					$('statusBarDiv').style.display = 'none';
					$('hintDiv').style.display = 'none';
					break;
			}

			this.currentState = newState;

			switch (this.currentState)
			{
				case this.STATE_SPLASH_SCREEN:	// Start screen
					$('splashDiv').style.display = 'block';
					
					this.enteredKey = this.getKeyCookie() || this.enteredKey;
					this.codeKeyPressed(-2);

					break;

				case this.STATE_LEVEL_SELECTION:	// Level selection
					this.loadPyramid(this.currentPyramid);

					var levelStateKey = Level.getPlayerLevelStateKey();
					var char = '';
					var charIndex = 0;
					var charPos = 34;
					for (var i = 0; i < 5; i++)
					{
						char = levelStateKey.charAt(i);
						if (char == '') { char = '_'; }
						charIndex = letterChar.indexOf(char);
						$('levelSelectorCodeLetter' + i).style.width = letterWidth[charIndex] + 'px';
						$('levelSelectorCodeLetter' + i).style.marginLeft = charPos + 'px';
						charPos += letterWidth[charIndex] + 2;
						$('levelSelectorCodeLetter' + i).style.backgroundPosition = letterLeft[charIndex] + 'px 0px';
					}
					$('levelSelectorCodeLetters').style.marginLeft = -charPos + 'px';

					$('levelOverviewDiv').style.display = 'block';
					break;

				case this.STATE_HELP:			// Help screen
					$('helpDiv').style.display = 'block';
					break;

				case this.STATE_ABOUT:			// About screen
					$('aboutDiv').style.display = 'block';
					break;

				case this.STATE_GAME:			// In game
					this.loadLevel((this.currentPyramid * 10) + arguments[1]);

					$('gameDiv').style.display = 'block';
					$('statusBarDiv').style.display = 'block';
					break;
			}
		},

		loadPyramid: function (pyramidNo)
		{
			if (pyramidNo < 0)
			{
				pyramidNo = 0;
			}
			else if (pyramidNo > 9)
			{
				pyramidNo = 9;
			}

			this.currentPyramid = pyramidNo;

			var y;
			if (pyramidNo == 0)
			{
				$('levelSelectorPrevPyramid').style.backgroundPosition = '0 -76px';
				$('levelSelectorPrevPyramid').style.cursor = 'default';
			}
			else
			{
				y = $.getBgYOffset($('levelSelectorPrevPyramid'));
				$('levelSelectorPrevPyramid').style.backgroundPosition = '0 ' + (y != -76 ? y + 'px' : '0');
				$('levelSelectorPrevPyramid').style.cursor = 'pointer';
			}
			if (pyramidNo == 9)
			{
				$('levelSelectorNextPyramid').style.backgroundPosition = '-38px -76px';
				$('levelSelectorNextPyramid').style.cursor = 'default';
			}
			else
			{
				y = $.getBgYOffset($('levelSelectorNextPyramid'));
				$('levelSelectorNextPyramid').style.backgroundPosition = '-38px ' + (y != -76 ? y + 'px' : '0');
				$('levelSelectorNextPyramid').style.cursor = 'pointer';
			}

			var levelNo;
			for (var i = 1; i <= 10; i++)
			{
				levelNo = (pyramidNo * 10) + i;
				if (levelNo > 40)
				{
					$('levelSelectorImage' + i).style.backgroundImage = 'url(images/levels/000.png)';
				}
				else
				{
                         $('levelSelectorImage' + i).style.backgroundImage = 'url(images/levels/' + ('00' + levelNo).right(3) + '.png)';
				}
				$('levelSelectorText' + i).innerHTML = 'Landscape #' + levelNo;

				switch (Level.getPlayerState(levelNo))
				{
					case Level.PLAYER_STATE_LOCKED:
						$('levelSelector' + i).style.backgroundPosition = '0 -276px';
						$('levelSelector' + i).style.cursor = 'default';
						$('levelSelectorState' + i).style.backgroundPosition = '0 0';
						$.setOpacity($('levelSelectorImage' + i), 0.2);
						break;

					case Level.PLAYER_STATE_UNLOCKED:
						$('levelSelector' + i).style.backgroundPosition = '0 0';
						$('levelSelector' + i).style.cursor = 'pointer';
						$('levelSelectorState' + i).style.backgroundPosition = '18px 0';
						$.setOpacity($('levelSelectorImage' + i), 1.0);
						break;

					case Level.PLAYER_STATE_SOLVED:
						$('levelSelector' + i).style.backgroundPosition = '0 0';
						$('levelSelector' + i).style.cursor = 'pointer';
						$('levelSelectorState' + i).style.backgroundPosition = '-18px 0';
						$.setOpacity($('levelSelectorImage' + i), 1.0);
						break;
				}
			}

			$('levelSelectorPyramidTitle').style.backgroundPosition = 'center ' + (-pyramidNo * 22) + 'px';
		},

		/*
			returns:
			- Level.PLAYER_STATE_LOCKED
			- Level.PLAYER_STATE_UNLOCKED
			- Level.PLAYER_STATE_SOLVED
		*/
		getPyramidLevelState: function (levelNo)
		{
			return Level.getPlayerState((this.currentPyramid * 10) + levelNo)
		},

		loadLevel: function (levelNo)
		{
			this.splitAsSoonAsPossible = false;

			this.startTime = new Date();
			this.moves = 0;

			if (Level.load(levelNo))
			{
				Draw.build();
			}
			else
			{
				return false;
			}

			$('statusBarMovesSpan').innerHTML = this.moves;
			statusBarUpdateInterval = setInterval(function ()
			{
				var seconds = Math.round(((new Date()) - Game.startTime) / 1000);
				$('statusBarTimeSpan').innerHTML = ('0' + Math.floor(seconds / 60)).right(2) + ':' + ('0' + (seconds % 60)).right(2);
			}, 1000);
			$('statusBarDiv').style.display = 'block';

			return true;
		},

		exitLevel: function (solved)
		{
			clearInterval(statusBarUpdateInterval);
			statusBarUpdateInterval = null;

			if (solved)
			{
				this.storeKeyCookie(Level.setPlayerStateSolved(Level.currentLevel));

				httpRequest('levefinished.php?level=' + Level.currentLevel + '&moves=' + this.moves + '&time=' + Math.round(((new Date()) - Game.startTime) / 1000), function () { return; });
				// alert("You did it!\n\nYour new level access code is:\n" + code;
				/*
					if (!this.loadLevel(Level.currentLevel + 1))
					{
						alert("You've solved all levels!");
					}
				*/

				this.setState(this.STATE_LEVEL_SELECTION);

				return;
			}
			else
			{
				this.setState(this.STATE_LEVEL_SELECTION);
			}

			$('statusBarDiv').style.display = 'none';
		},

		increaseMoveCount: function ()
		{
			this.moves++;
			$('statusBarMovesSpan').innerHTML = this.moves;
		},

		moveBoxXn: function ()
		{
			if (Draw.boxAnimInterval != null) { return; }

			for (var i = 0; i < Level.boxes.length; i++)
			{
				if (Level.boxes[i].type == Level.BOX_TYPE_GREEN && Level.boxes[i].state == Level.BOX_STATE_ACTIVE)
				{
					var box;
					for (var j = 0; j < Level.boxes.length; j++)
					{
						box = Level.boxes[j]
						if (box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_ACTIVE)
						{
							if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y) == 2)
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else if (Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y) || Level.isBlocked(Level.boxes[i].x - 2, Level.boxes[i].y))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED_TILT);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_XN_BLOCKED, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_XN_BLOCKED, i);
									}
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_XN_0, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_XN_0, i);
									}
								}
							}
							else if (box.x == Level.boxes[i].x - 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x - 2, Level.boxes[i].y))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_XN_1, j);
								}
							}
							else if (box.x == Level.boxes[i].x + 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_XN_1, i);
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y - 1)
							{
								if (Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y) || Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y - 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_XN, j);
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y + 1)
							{
								if (Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y) || Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y + 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_XN, j);
								}
							}
							break;
						}
					}
					if (j == Level.boxes.length)
					{
						if (Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y))
						{
							Sound.play(Sound.BOX_MOVING_BLOCKED);
						}
						else
						{
							this.increaseMoveCount();
							Sound.play(Sound.BOX_MOVING);
							Draw.startBoxAnim(i, Draw.ANIM_BOX_MOVE_XN);
						}
					}
				}
			}
		},
		moveBoxXp: function ()
		{
			if (Draw.boxAnimInterval != null) { return; }

			for (var i = 0; i < Level.boxes.length; i++)
			{
				if (Level.boxes[i].type == Level.BOX_TYPE_GREEN && Level.boxes[i].state == Level.BOX_STATE_ACTIVE)
				{
					var box;
					for (var j = 0; j < Level.boxes.length; j++)
					{
						box = Level.boxes[j]
						if (box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_ACTIVE)
						{
							if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y) == 2)
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else if (Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y) || Level.isBlocked(Level.boxes[i].x + 2, Level.boxes[i].y))
								{
									this.increaseMoveCount();
									Sound.play(Sound.BOX_MOVING_BLOCKED_TILT);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_XP_BLOCKED, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_XP_BLOCKED, i);
									}
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_XP_0, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_XP_0, i);
									}
								}
							}
							else if (box.x == Level.boxes[i].x - 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_XP_1, j);
								}
							}
							else if (box.x == Level.boxes[i].x + 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x + 2, Level.boxes[i].y))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_XP_1, i);
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y - 1)
							{
								if (Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y) || Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y - 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_XP, j);
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y + 1)
							{
								if (Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y) || Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y + 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_XP, j);
								}
							}
							break;
						}
					}
					if (j == Level.boxes.length)
					{
						if (Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y))
						{
							Sound.play(Sound.BOX_MOVING_BLOCKED);
						}
						else
						{
							this.increaseMoveCount();
							Sound.play(Sound.BOX_MOVING);
							Draw.startBoxAnim(i, Draw.ANIM_BOX_MOVE_XP);
						}
					}
				}
			}
		},
		moveBoxYn: function ()
		{
			if (Draw.boxAnimInterval != null) { return; }

			for (var i = 0; i < Level.boxes.length; i++)
			{
				if (Level.boxes[i].type == Level.BOX_TYPE_GREEN && Level.boxes[i].state == Level.BOX_STATE_ACTIVE)
				{
					var box;
					for (var j = 0; j < Level.boxes.length; j++)
					{
						box = Level.boxes[j]
						if (box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_ACTIVE)
						{
							if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 1) == 2)
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 1) || Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 2))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED_TILT);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_YN_BLOCKED, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_YN_BLOCKED, i);
									}
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_YN_0, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_YN_0, i);
									}
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y - 1)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 2))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_YN_1, j);
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y + 1)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_YN_1, i);
								}
							}
							else if (box.x == Level.boxes[i].x - 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 1) || Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y - 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_YN, j);
								}
							}
							else if (box.x == Level.boxes[i].x + 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 1) || Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y - 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_YN, j);
								}
							}
							break;
						}
					}
					if (j == Level.boxes.length)
					{
						if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y - 1))
						{
							Sound.play(Sound.BOX_MOVING_BLOCKED);
						}
						else
						{
							this.increaseMoveCount();
							Sound.play(Sound.BOX_MOVING);
							Draw.startBoxAnim(i, Draw.ANIM_BOX_MOVE_YN);
						}
					}
				}
			}
		},
		moveBoxYp: function ()
		{
			if (Draw.boxAnimInterval != null) { return; }

			for (var i = 0; i < Level.boxes.length; i++)
			{
				if (Level.boxes[i].type == Level.BOX_TYPE_GREEN && Level.boxes[i].state == Level.BOX_STATE_ACTIVE)
				{
					var box;
					for (var j = 0; j < Level.boxes.length; j++)
					{
						box = Level.boxes[j]
						if (box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_ACTIVE)
						{
							if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 1) == 2)
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 1) || Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 2))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED_TILT);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_YP_BLOCKED, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_YP_BLOCKED, i);
									}
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									if (box.z == 0)
									{
										Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_YP_0, j);
									}
									else // if (box.z == 1)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_YP_0, i);
									}
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y - 1)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_TILT_YP_1, j);
								}
							}
							else if (box.x == Level.boxes[i].x && box.y == Level.boxes[i].y + 1)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 2))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(j, Draw.ANIM_MERGED_BOX_TILT_YP_1, i);
								}
							}
							else if (box.x == Level.boxes[i].x - 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 1) || Level.isBlocked(Level.boxes[i].x - 1, Level.boxes[i].y + 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_YP, j);
								}
							}
							else if (box.x == Level.boxes[i].x + 1 && box.y == Level.boxes[i].y)
							{
								if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 1) || Level.isBlocked(Level.boxes[i].x + 1, Level.boxes[i].y + 1))
								{
									Sound.play(Sound.BOX_MOVING_BLOCKED);
								}
								else
								{
									this.increaseMoveCount();
									Sound.play(Sound.MERGED_BOX_MOVING);
									Draw.startBoxAnim(i, Draw.ANIM_MERGED_BOX_ROLL_YP, j);
								}
							}
							break;
						}
					}
					if (j == Level.boxes.length)
					{
						if (Level.isBlocked(Level.boxes[i].x, Level.boxes[i].y + 1))
						{
							Sound.play(Sound.BOX_MOVING_BLOCKED);
						}
						else
						{
							this.increaseMoveCount();
							Sound.play(Sound.BOX_MOVING);
							Draw.startBoxAnim(i, Draw.ANIM_BOX_MOVE_YP);
						}
					}
				}
			}
		},
		switchBox: function ()
		{
			if (Draw.boxAnimInterval != null) { return; }

			for (var i = 0; i < Level.boxes.length; i++)
			{
				if (Level.boxes[i].type == Level.BOX_TYPE_GREEN && Level.boxes[i].state == Level.BOX_STATE_ACTIVE && Level.boxes[i].z == 0)
				{
					for (var j = 0; j < Level.boxes.length; j++)
					{
						box = Level.boxes[j];
						if (box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_ACTIVE)
						{
							if (box.z == 0)
							{
								box.state = Level.BOX_STATE_INACTIVE;
								Draw.setBoxStyle(j);
								if (Level.isSolved())
								{
									this.exitLevel(true);
								}
								break;
							}
							else
							{
								Sound.play(Sound.BOX_SWITCHING_FAILED);
								return;
							}
						}
					}

					for (var j = i + 1; j < Level.boxes.length; j++)
					{
						if (Level.boxes[j].type == Level.BOX_TYPE_GREEN && Level.boxes[j].state == Level.BOX_STATE_INACTIVE)
						{
							Level.boxes[i].state = Level.BOX_STATE_INACTIVE;
							Level.boxes[j].state = Level.BOX_STATE_ACTIVE;
							Draw.setBoxStyle(i);
							Draw.setBoxStyle(j);
							Sound.play(Sound.BOX_SWITCHED);
							return;
						}
					}
					for (var j = 0; j < i; j++)
					{
						if (Level.boxes[j].type == Level.BOX_TYPE_GREEN && Level.boxes[j].state == Level.BOX_STATE_INACTIVE)
						{
							Level.boxes[i].state = Level.BOX_STATE_INACTIVE;
							Level.boxes[j].state = Level.BOX_STATE_ACTIVE;
							Draw.setBoxStyle(i);
							Draw.setBoxStyle(j);
							Sound.play(Sound.BOX_SWITCHING);
							return;
						}
					}
					Sound.play(Sound.BOX_SWITCHING_FAILED);
					return;
				}
			}
		},

		/*
			state-values:
			0/not set = normal behaviour
			1 = split without merge
			2 = switch between colored blocks without split
			3 = remerge the last merged block if possible, otherwise the next block
		*/
		mergeBox: function (state)
		{
			if (Draw.boxAnimInterval != null) { return; }

			var returnVal = false;
			var merged = false;
			var splitBox = null;
			var box;

			for (var i = 0; i < Level.boxes.length; i++)
			{
				if (Level.boxes[i].type == Level.BOX_TYPE_GREEN && Level.boxes[i].state == Level.BOX_STATE_ACTIVE && Level.boxes[i].z == 0)
				{
					var jStart = 0;
					for (var j = 0; j < Level.boxes.length; j++)
					{
						box = Level.boxes[j];
						if (box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_ACTIVE)
						{
							if (box.z == 0)
							{
								box.state = Level.BOX_STATE_INACTIVE;
								splitBox = j;
								jStart = j + 1;
							}
							else
							{
								jStart = Level.boxes.length;
							}
							break;
						}
					}
					if (state == 3 && typeof Level.boxes[i].lastMergedBox === 'number')
					{
						jStart = Level.boxes[i].lastMergedBox;
					}
					if (state != 1)
					{
						for (var j = jStart; j < Level.boxes.length; j++)
						{
							box = Level.boxes[j];
							if (
								box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_INACTIVE &&
								(
									(box.x == Level.boxes[i].x - 1 && box.y == Level.boxes[i].y) ||
									(box.x == Level.boxes[i].x + 1 && box.y == Level.boxes[i].y) ||
									(box.x == Level.boxes[i].x && box.y == Level.boxes[i].y - 1) ||
									(box.x == Level.boxes[i].x && box.y == Level.boxes[i].y + 1)
								)
							)
							{
								box.state = Level.BOX_STATE_ACTIVE;
								if (splitBox != null)
								{
									Draw.startBoxAnim(j, Draw.ANIM_MERGE_SPLIT, splitBox);
									splitBox = null;
								}
								else
								{
									Draw.startBoxAnim(j, Draw.ANIM_MERGE);
								}
								Level.boxes[i].lastMergedBox = j
								merged = true;
								break;
							}
						}

						if ((state == 2 || state == 3) && merged == false && jStart < Level.boxes.length)
						{
							for (var j = 0; j < jStart; j++)
							{
								box = Level.boxes[j];
								if (
									box.type != Level.BOX_TYPE_GREEN && box.state == Level.BOX_STATE_INACTIVE &&
									(
										(box.x == Level.boxes[i].x - 1 && box.y == Level.boxes[i].y) ||
										(box.x == Level.boxes[i].x + 1 && box.y == Level.boxes[i].y) ||
										(box.x == Level.boxes[i].x && box.y == Level.boxes[i].y - 1) ||
										(box.x == Level.boxes[i].x && box.y == Level.boxes[i].y + 1)
									)
								)
								{
									box.state = Level.BOX_STATE_ACTIVE;
									if (splitBox != null)
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGE_SPLIT, splitBox);
										splitBox = null;
									}
									else
									{
										Draw.startBoxAnim(j, Draw.ANIM_MERGE);
									}
									Level.boxes[i].lastMergedBox = j
									merged = true;
									break;
								}
							}
						}
					}
				}
			}

			if (splitBox != null)
			{
				Draw.startBoxAnim(splitBox, Draw.ANIM_SPLIT);
				if (Level.isSolved())
				{
					this.exitLevel(true);
				}
			}
			Sound.play(merged ? Sound.BOX_MERGING : Sound.BOX_MERGING_FAILED);

			switch (state)
			{
				case 0:
				case 2:
					return merged;
				case 1:
					return (splitBox != null);
			}
		},
		
		rotateLevel: function ()
		{
			if (Draw.boxAnimInterval == null)
			{
				Level.rotate();
			}
		},

		codeKeyPressed: function (keyIndex)
		{
			if (keyIndex == -1)
			{
				if (this.enteredKey.length > 0)
				{
					this.enteredKey = this.enteredKey.substr(0, this.enteredKey.length - 1);
				}
			}
			else if (keyIndex != -2 && this.enteredKey.length < 5)
			{
				this.enteredKey += letterChar[keyIndex];
			}

			var char = '';
			var charIndex = 0;
			for (var i = 0; i < 5; i++)
			{
				char = this.enteredKey.charAt(i);
				if (char == '') { char = '_'; }
				charIndex = letterChar.indexOf(char);
				$('splashCodeLetter' + i).style.width = letterWidth[charIndex] + 'px';
				$('splashCodeLetter' + i).style.marginLeft = (-60 + (30 * i) - Math.floor(letterWidth[charIndex] / 2)) + 'px';
				$('splashCodeLetter' + i).style.backgroundPosition = letterLeft[charIndex] + 'px 0px';
			}

			if (this.enteredKey.length == 5)
			{
				if (Level.setPlayerLevelStateKey(this.enteredKey))
				{
					$('splashCodeValidity').style.backgroundPosition = '-18px 0';
					$.setBgYOffset($('splashLoadGameButton'), 0);
					$('splashLoadGameButton').style.cursor = 'pointer';

					Game.currentPyramid = Level.getPlayerPyramid();
					$('splashPyramidTitle').style.backgroundPosition = 'center ' + (-Game.currentPyramid * 22) + 'px';
				}
				else
				{
					$('splashCodeValidity').style.backgroundPosition = '-36px 0';
					$.setBgYOffset($('splashLoadGameButton'), -56);
					$('splashLoadGameButton').style.cursor = 'default';

					$('splashPyramidTitle').style.backgroundPosition = 'center 22px';
				}
			}
			else
			{
				$('splashCodeValidity').style.backgroundPosition = '18px 0';
				$.setBgYOffset($('splashLoadGameButton'), -56);
				$('splashLoadGameButton').style.cursor = 'default';
				
				$('splashPyramidTitle').style.backgroundPosition = 'center 22px';
			}
		},
		
		storeKeyCookie: function (key)
		{
			document.cookie = 'key=' + key + ';path=/;expires=' + (new Date((new Date()).getTime() + 1000 * 60 * 60 * 24 * 365 * 10)).toGMTString();
		},
		
		getKeyCookie: function ()
		{
			if (document.cookie)
			{
				var keyArray = /(^|.*;)\W*key\=([^;]*)($|;.*)/.exec(document.cookie);
				if ((keyArray != null) && (keyArray.length == 4))
				{
					return keyArray[2];
				}
			}
			return null;
		}
	}
})();
