﻿(function ()
{
	var window = this, undefined;

	// *** Private Constants ***

	var codes = [
		'16ESYBXZP735JLOVDIMUR8HF9AWGC2Q4',
		'1C8WORGJ7HISPQEMU592D6NTBLZ4XYFV',
		'3UR97AJFGVPT2DE5WCYXQZHSL4I8MO6N',
		'3YUGZHRC8EINB46KDQWFOVP51AS29XTJ',
		'4IKJM5PW1ZCLDO68BRAXTVHU7G2Y39FS',
		'5AMYJK1678WSRDXT924LOGU3QVPBCIEN',
		'6XNMZC5U9RAIEVFSQO2D873PWKLTB4GH',
		'7RWB38MTZ2IP6SJDOQC1GLKA9U5NF4XV',
		'8RUE5IL91ZHXYANFK2POB6TDMQSGJC37',
		'8ZHNGQUWV93P5R7EXMTADIB14K2LOSCY',
		'972E6X1VAWRJQ8UF5MNYOSPZKTCI3BHG',
		'9U58PNOS72GZJLEQFKT1IYHVX4RCMA6D',
		'BSKTGZ6XJ521O7IPVQMYNDU9HRA8E43L',
		'CX92I8ULQKJ3OH754RED1GPVTB6MYNZW',
		'EUS5QD9GXFHBR1C42VYKJ6WNTAZM78P3',
		'G1T5Q94P2WIKRHSDB7UZM3VJELONYCAF',
		'HA51QWK37ON42XCIVGSRBUDEF8ZMJ9LT',
		'HNSY2JK6IQ93UEVWO75TCXL4BZFGD18A',
		'JGWTDEANVY6I35PXM1K472CUQ8F9LZRS',
		'K683JC9THN1VWGU4YRMIQBPD57O2LFSX',
		'N9G1ZMQ725SLTAB6K84XVYHRCJIFP3ED',
		'NB9O7E618AJFXGWMHZQKT3U2CLSPV5IY',
		'NRAHM6I37CXEDJF41TULZQG85YV29WPK',
		'ONBT9MZGV87P1XIJCYK2WUASRE53LHDF',
		'SINGRHKAT3DUO786LZFY4J52QP9BCV1W',
		'TINWMR8YD9SGCLJ3P1FXA7OK2UV5HQBZ',
		'UL5DS2RK9T1PA3G4XCIEVQWJN87YBFOM',
		'VFPYH9RN4AU7ECT5DIGWX62J183ZMLQO',
		'W3PL8KYUQI1GSZR5NDFBOE4C9JX7TAH2',
		'XVB5WOK2M4HNT9Y6JRFSZ3IGU8L7DCA1',
		'YH98QZFND37MIT1UV6ASO4LRK2JW5XCG',
		'ZLGA6HC1VYD5KOSPJ8WIQE9B4RMXUFT7',
	];
	var salt = [17, 20, 25, 18, 11, 26, 21, 9, 19, 27, 13, 10];

	// *** Private Variables ***

	var levelStateKey = 'GIXFD';

	window["Level"] = {
		// *** Constants ***

		FLOOR_EMPTY: undefined,
		FLOOR_NORMAL: 1,
		FLOOR_RED: 2,
		FLOOR_PURPLE: 3,
		FLOOR_CYAN: 4,
		FLOOR_YELLOW: 5,
		FLOOR_BRIDGE_OPEN: 6,
		FLOOR_BRIDGE_CLOSED: 7,
		FLOOR_BROKEN: 8,

		BOX_TYPE_GREEN: 0,
		BOX_TYPE_RED: 1,
		BOX_TYPE_PURPLE: 2,
		BOX_TYPE_CYAN: 3,
		BOX_TYPE_YELLOW: 4,

		BOX_STATE_ACTIVE: 0,
		BOX_STATE_INACTIVE: 1,
		BOX_STATE_UNMOVABLE: 2,

		PLAYER_STATE_LOCKED: 0,
		PLAYER_STATE_UNLOCKED: 1,
		PLAYER_STATE_SOLVED: 2,

		// *** Variables ***

		floor:null,
		boxes:null,
		currentLevel:null,

		// *** Functions ***

		load: function (levelNo)
		{
			this.currentLevel = levelNo;

			switch (levelNo)
			{
				case 1:
/*
					return levelFromMap([
						'     r',
						'    ++',
						'+RGRGRGr',
						'    ++',
						'    r'
					]);
*/
					return levelFromMap([
						'+++++++',
						'+R+G+r+',
						'+++++++'
					]);

				case 2:
					return levelFromMap([
						'+++++++',
						'+R+++++',
						'+++G+++',
						'+++++r+',
						'+++++++'
					]);

				case 3:
					return levelFromMap([
						'+++++++',
						'+R+++++',
						'  +G+',
						'+++++r+',
						'+++++++'
					]);

				case 4:
					return levelFromMap([
						'+++',
						'+ r',
						'+ G',
						'++R'
					]);

				case 5:
					return levelFromMap([
						'++',
						'R+',
						' G++',
						'  r+'
					]);

				case 6:
					return levelFromMap([
						'+++++++',
						'+R + ++',
						' + G +',
						'++ + r+',
						'+++++++'
					]);

				case 7:
					return levelFromMap([
						'   ++',
						'   ++',
						'G+++++r',
						'+',
						'R',
					]);

				case 8:
					return levelFromMap([
						'pR+',
						'pR++++',
						'  +++G+++',
						'     ++++Pr',
						'        +Pr'
					]);

				case 9:
					return levelFromMap([
						'R + ++R',
						'+ +++  ',
						'++r r++',
						' +   +',
						'++r r++',
						'+ +G+',
						'R + ++R'
					]);

				case 10:
					return levelFromMap([
						'ry cp',
						'+++++',
						'CPGRY'
					]);

				case 11:
					return levelFromMap([
						'+++++++',
						'+rrrrr+',
						'+     +',
						'+     +',
						'+RRRRR+',
						'+++G+++'
					]);

				case 12:
					return levelFromMap([
						' +++',
						'+G+++',
						'++R++',
						'++R +',
						'  R +',
						'r+r+r'
					]);

				case 13:
					return levelFromMap([
						'          ++++',
						'          +  +',
						'        +R+R++',
						'        ++R++',
						'rprp++  P++P++',
						'prpr++++R+RPG',
						'rprp++  +R++P',
						'        +   +++',
						'        +++++P+',
						'        + P  ++',
						'        +++'
					]);

				case 14:
					return levelFromMap([
						'+r+r+',
						'pRPRp',
						'+PGP+',
						'pRPRp',
						'+r+r+'
					]);

				case 15:
					return levelFromMap([
						' ++',
						'+D+',
						'+DR+',
						'+r++',
						'+ ++',
						'+G+'
					]);

				case 16:
					return levelFromMap([
						'  +',
						'  r',
						'  R+Rr+',
						'  +G+',
						'+rR+R',
						'    r',
						'    +'
					]);


				case 17:
					return levelFromMap([
						'RrPCrR',
						'p++++c',
						'R+r0+R',
						'R+rr+R',
						'c++++p',
						'RrPCrR'
					]);

				case 18:
					return levelFromMap([
						'2+++++6',
						'+     +',
						'+     +',
						'+++G+++',
						'+     +',
						'+++ +++',
						' 6+++2'
					]);

				case 19:
					return levelFromMap([
						' +++',
						' +++ ++',
						'  +G++r',
						'  +  +r',
						'R++  +r',
						'+R+',
						'R++'
					]);

				case 20:
					return levelFromMap([
						'R+R  +++P+P',
						'+++  + ++++',
						'R+R  + rP+P',
						' +   + r +',
						' G++++ r +',
						' +     r +',
						' ++pppp+++',
						' +     +++',
						' ++++++++'
					]);

				case 21:
					return levelFromMap([
						' ++++++',
						' RD+D+R',
						'+Rr+r r',
						'GRr r+r',
						' RDRD++',
						' ++++++'
					]);

				case 22:
					return levelFromMap([
						'+++++++r+++',
						'+  R  +   +',
						'+  +  +   R',
						'Rrr+++G  r+',
						'    + +  +',
						'    R+++++'
					]);

				case 23:
					return levelFromMap([
						' ++++',
						'+++ +',
						'+ ++P',
						'rr+ ++R',
						' +++R +',
						' + + +Rr',
						' +p+ +',
						'   ++G'
					]);

				case 24:
					return levelFromMap([
						'GRr++',
						'YCy++',
						'cPRr+',
						'+pYCy+',
						' +cPRr+',
						'  +pYCy+',
						'   +c+Pr',
						'    +pR+'
					]);

				case 25:
					return levelFromMap([
						' ++',
						' +++RGR+',
						' +DD  r+',
						' RrR++r+',
						'++r +rD',
						'++++R++',
						'     ++'
					]);

				case 26:
					return levelFromMap([
						'  +++++',
						'  +   +',
						'r++++++',
						'  RR  +',
						'  G+  +',
						'  +++R+',
						'  r   +',
						'      r'
					]);

				case 27:
					return levelFromMap([
						'  ++',
						'  +G++r+',
						'  +   r+',
						'+RR   r+',
						'+R+',
						'+++'
					]);

				case 28:
					return levelFromMap([
						'+R+C+P+Y',
						'rrccppyy',
						'Y+P+C+RG'
					]);

				case 29:
					return levelFromMap([
						'rr++    G',
						'rr++   +++',
						'rr+++++RR+',
						'rr++ + +R+',
						'rr   + +R+',
						'   +R+ R++',
						'   ++R +R+',
						'   +R++R++',
						'   ++  +++'
					]);

				case 30:
					return levelFromMap([
						'rr   +++',
						'rr+  +R++R++',
						'rr++ R    ++',
						'rr++++G+  ++',
						'rr   + ++R+',
						'        R+R',
						'  +R++R+R R'
					]);

				case 31:
					return levelFromMap([
						'  RRR',
						' ++ ++',
						'+++++++',
						'+  +  +',
						'+  0  +',
						'+  +  +',
						'+++r+++',
						' + + +',
						' ++r++'
					]);

				case 32:
					return levelFromMap([
						'++++R P++++',
						'+R p+Y+r P+',
						'+   + +   +',
						'+pRr+ +pPr+',
						'+r y+G+y p+',
						'+   + +   +',
						'+P r+Y+p R+',
						'++++P R++++'

					]);

				case 33:
					return levelFromMap([
						'   +++',
						' +R+ +D+',
						' +RDrD++',
						'++D+++r+',
						'G++   ++'
					]);

				case 34:
					return levelFromMap([
						' RG',
						' Py',
						'+Cc',
						' Yp',
						' +r'
					]);

				case 35:
					return levelFromMap([
						'C++',
						'+ +',
						'++r++c+R',
						'  +  + +',
						'  +  ++R',
						'++rCG+',
						'+ +  +',
						'++cR+r',
						'   + ++',
						'   ++++'
					]);

				case 36:
					return levelFromMap([
						'++ + R+',
						'R++R++R+',
						' R +  +++',
						' + ++++++',
						' +R+R+ R',
						'G+R R ++',
						'+++ +++',
						' +RRRR+ +rrr',
						' ++ +++++r r',
						'  ++ +  +rrr',
						'   +++  ++rr',
						'        rrrr'
					]);

				case 37:
					return levelFromMap([
						'       y',
						'       R',
						'       +',
						'      +r+',
						'YYY+R+rGr+R+y',
						'      +r+',
						'       +',
						'       R',
						'       y'
					]);

				case 40:
					return levelFromMap([
						'     +++',
						'22   +G+',
						'22++++++',
						'22++ +',
						'22+  ++',
						'22   +++',
						'    66666',
						'    66666'
					]);

				case 38:
				case 39:

				case 41:
				case 42:
				case 43:
				case 44:
				case 45:
				case 46:
				case 47:
				case 48:
				case 49:
				case 50:
				case 51:
				case 52:
				case 53:
				case 54:
				case 55:
				case 56:
				case 57:
				case 58:
				case 59:
				case 60:
				case 61:
				case 62:
				case 63:
				case 64:
				case 65:
				case 66:
				case 67:
				case 68:
				case 69:
				case 70:
/*
				case 99:
					return levelFromMap([
						'~+~+~+',
						'+~+~+~',
						'~G~+~+',
						'+~+~+~',
						'~+~+~+'
					]);
*/
			}

			return levelFromMap(['G R r']);
		},

		/*
			return values:
			0 = not blocked
			1 = no floor (FLOOR_EMPTY, FLOOR_BRIDGE_OPEN etc.)
			2 = blocked by box
		*/
		isBlocked: function (x, y)
		{
			if (x < 0 || x >= this.floor.length || y < 0 || y >= this.floor[0].length)
			{
				return 1;
			}

			if (this.floor[x][y] === undefined)
			{
				return 1;
			}
			else
			{
				switch (this.floor[x][y].type)
				{
					case this.FLOOR_EMPTY:
					case this.FLOOR_BRIDGE_OPEN:
						return 1;
				}
			}

			for (var i = 0; i < this.boxes.length; i++)
			{
				if (this.boxes[i].x == x && this.boxes[i].y == y)
				{
					return 2;
				}
			}

			return 0;
		},

		/*
			return values:
			true = Level is solved
			false = Level is solved
		*/
		isSolved: function ()
		{
			var box;
			for (var i = 0; i < Level.boxes.length; i++)
			{
				box = Level.boxes[i]
				switch (box.type)
				{
					case Level.BOX_TYPE_RED:
						if (box.state != Level.BOX_STATE_INACTIVE || Level.floor[box.x][box.y].type != Level.FLOOR_RED)
						{
							return false;
						}
						break;

					case Level.BOX_TYPE_PURPLE:
						if (box.state != Level.BOX_STATE_INACTIVE || Level.floor[box.x][box.y].type != Level.FLOOR_PURPLE)
						{
							return false;
						}
						break;

					case Level.BOX_TYPE_CYAN:
						if (box.state != Level.BOX_STATE_INACTIVE || Level.floor[box.x][box.y].type != Level.FLOOR_CYAN)
						{
							return false;
						}
						break;

					case Level.BOX_TYPE_YELLOW:
						if (box.state != Level.BOX_STATE_INACTIVE || Level.floor[box.x][box.y].type != Level.FLOOR_YELLOW)
						{
							return false;
						}
						break;
				}
			}

			return true;
		},

		rotate: function ()
		{
			var rFloor = new Array2D(this.floor[0].length, this.floor.length);

			var x, y, y2;
			for (x = 0; x < this.floor.length; x++)
			{
				for (y2 = 0; y2 < this.floor[x].length; y2++)
				{
					y = (this.floor[x].length - 1) - y2;
					if (this.floor[x][y2] != undefined)
					{
						rFloor[y][x] = this.floor[x][y2];
					}
				}
			}
			this.floor = rFloor;

			y2 = this.floor.length - 1;
			for (var i = 0; i < this.boxes.length; i++)
			{
				x = this.boxes[i].x;
				y = this.boxes[i].y;
				this.boxes[i].x = y2 - y;
				this.boxes[i].y = x;
			}
			Draw.build();
		},

		/*
			Player Handling
		*/
		getPlayerPyramid: function ()
		{
			var pyramid = decodeLevelKey(levelStateKey);
			if (pyramid == null)
			{
				return 0;
			}
			else
			{
				return pyramid.pyramid - 1;
			}
		},

		getPlayerState: function (levelNo)
		{
			var pyramid = decodeLevelKey(levelStateKey);
			if (pyramid == null)
			{
				return Level.PLAYER_STATE_LOCKED;
			}
			else if ((levelNo - 1) < (pyramid.pyramid - 1) * 10)
			{
				return Level.PLAYER_STATE_SOLVED;
			}
			else if (levelNo > pyramid.pyramid * 10)
			{
				return Level.PLAYER_STATE_LOCKED;
			}
			else
			{
				if (pyramid.states.charAt((levelNo - 1) % 10) == '1')
				{
					return Level.PLAYER_STATE_SOLVED;
				}
				else
				{
					switch ((levelNo - 1) % 10)
					{
						case 0:
						case 1:
						case 2:
						case 3:
							return Level.PLAYER_STATE_UNLOCKED;
						case 4:
							return (pyramid.states.charAt(0) == '1' && pyramid.states.charAt(1) == '1') ? Level.PLAYER_STATE_UNLOCKED : Level.PLAYER_STATE_LOCKED;
						case 5:
							return (pyramid.states.charAt(1) == '1' && pyramid.states.charAt(2) == '1') ? Level.PLAYER_STATE_UNLOCKED : Level.PLAYER_STATE_LOCKED;
						case 6:
							return (pyramid.states.charAt(2) == '1' && pyramid.states.charAt(3) == '1') ? Level.PLAYER_STATE_UNLOCKED : Level.PLAYER_STATE_LOCKED;
						case 7:
							return (pyramid.states.charAt(4) == '1' && pyramid.states.charAt(5) == '1') ? Level.PLAYER_STATE_UNLOCKED : Level.PLAYER_STATE_LOCKED;
						case 8:
							return (pyramid.states.charAt(5) == '1' && pyramid.states.charAt(6) == '1') ? Level.PLAYER_STATE_UNLOCKED : Level.PLAYER_STATE_LOCKED;
						case 9:
							return (pyramid.states.charAt(7) == '1' && pyramid.states.charAt(8) == '1') ? Level.PLAYER_STATE_UNLOCKED : Level.PLAYER_STATE_LOCKED;
					}
				}
			}
			return Level.PLAYER_STATE_LOCKED;
		},

		setPlayerStateSolved: function (levelNo)
		{
			var pyramid = decodeLevelKey(levelStateKey);
			if (pyramid == null)
			{
				return levelStateKey;
			}
			else if ((levelNo - 1) < (pyramid.pyramid - 1) * 10)
			{
				return levelStateKey;
			}
			else if (levelNo > pyramid.pyramid * 10)
			{
				return levelStateKey;
			}
			else
			{
				if (pyramid.states.charAt((levelNo - 1) % 10) == '1')
				{
					return levelStateKey;
				}
				else
				{
					if (((levelNo - 1) % 10) == 9)
					{
						pyramid.states = '0000000000';
						pyramid.pyramid++;
					}
					else
					{
						pyramid.states = (((levelNo - 1) % 10) > 0 ? pyramid.states.substr(0, ((levelNo - 1) % 10) - 0) : '') + '1' + pyramid.states.substr(((levelNo - 1) % 10) + 1)
					}

					levelStateKey = encodeLevelKey(pyramid.states, pyramid.pyramid);
					return levelStateKey;
				}
			}
		},

		getPlayerLevelStateKey: function ()
		{
			return levelStateKey;
		},

		setPlayerLevelStateKey: function (newKey)
		{
			if (decodeLevelKey(newKey) == null)
			{
				return false;
			}
			else
			{
				levelStateKey = newKey;
				return true;
			}
		}
	}

	/*
		return true if the level was successfully created

		' ' - FLOOR_EMPTY
		'+' - FLOOR_NORMAL
		'~' - FLOOR_BROKEN
		'r' - FLOOR_RED
		'p' - FLOOR_PURPLE
		'c' - FLOOR_CYAN
		'y' - FLOOR_YELLOW
		'G' - FLOOR_NORMAL + BOX_TYPE_GREEN
		'R' - FLOOR_NORMAL + BOX_TYPE_RED
		'P' - FLOOR_NORMAL + BOX_TYPE_PURPLE
		'C' - FLOOR_NORMAL + BOX_TYPE_CYAN
		'Y' - FLOOR_NORMAL + BOX_TYPE_YELLOW

		'0' - FLOOR_RED + BOX_TYPE_GREEN
		-- '1' - FLOOR_RED + BOX_TYPE_RED
		'2' - FLOOR_RED + BOX_TYPE_PURPLE
		-- '3' - FLOOR_RED + BOX_TYPE_CYAN
		-- '4' - FLOOR_RED + BOX_TYPE_YELLOW
		-- '5' - FLOOR_PURPLE + BOX_TYPE_GREEN
		'6' - FLOOR_PURPLE + BOX_TYPE_RED
		-- '7' - FLOOR_PURPLE + BOX_TYPE_PURPLE
		-- '8' - FLOOR_PURPLE + BOX_TYPE_CYAN
		-- '9' - FLOOR_PURPLE + BOX_TYPE_YELLOW
		-- 'A' - FLOOR_CYAN + BOX_TYPE_GREEN
		-- 'B' - FLOOR_CYAN + BOX_TYPE_RED
		-- '' - FLOOR_CYAN + BOX_TYPE_PURPLE
		'D' - FLOOR_CYAN + BOX_TYPE_CYAN
		-- 'E' - FLOOR_CYAN + BOX_TYPE_YELLOW
		-- 'F' - FLOOR_YELLOW + BOX_TYPE_GREEN
		-- '' - FLOOR_YELLOW + BOX_TYPE_RED
		-- 'H' - FLOOR_YELLOW + BOX_TYPE_PURPLE
		-- 'I' - FLOOR_YELLOW + BOX_TYPE_CYAN
		-- 'J' - FLOOR_YELLOW + BOX_TYPE_YELLOW
	*/
	function levelFromMap(map)
	{
		var y;
		var xMax = 0;
		var firstGreen = true;

		for (var y = 0; y < map.length; y++)
		{
			if (map[y].length > xMax)
			{
				xMax = map[y].length;
			}
		}
		
		Level.floor = new Array2D(xMax, map.length);
		Level.boxes = new Array();

		for (var y2 = map.length - 1; y2 >= 0; y2--)
		{
			y = (map.length - 1) - y2;
			for (var x = 0; x < map[y2].length; x++)
			{
				switch (map[y2].charAt(x))
				{
					case ' ':
						break;

					case '+':
						Level.floor[x][y] = { "type":Level.FLOOR_NORMAL };
						break;

					case '~':
						Level.floor[x][y] = { "type":Level.FLOOR_BROKEN };
						break;

					case 'r':
						Level.floor[x][y] = { "type":Level.FLOOR_RED };
						break;

					case 'p':
						Level.floor[x][y] = { "type":Level.FLOOR_PURPLE };
						break;

					case 'c':
						Level.floor[x][y] = { "type":Level.FLOOR_CYAN };
						break;

					case 'y':
						Level.floor[x][y] = { "type":Level.FLOOR_YELLOW };
						break;

					case 'G':
						Level.floor[x][y] = { "type":Level.FLOOR_NORMAL };

						Level.boxes.push({
							"type":Level.BOX_TYPE_GREEN,
							"state":firstGreen ? Level.BOX_STATE_ACTIVE : Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						firstGreen = false;
						break;

					case 'R':
						Level.floor[x][y] = { "type":Level.FLOOR_NORMAL };

						Level.boxes.push({
							"type":Level.BOX_TYPE_RED,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;

					case 'P':
						Level.floor[x][y] = { "type":Level.FLOOR_NORMAL };

						Level.boxes.push({
							"type":Level.BOX_TYPE_PURPLE,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;

					case 'C':
						Level.floor[x][y] = { "type":Level.FLOOR_NORMAL };

						Level.boxes.push({
							"type":Level.BOX_TYPE_CYAN,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;

					case 'Y':
						Level.floor[x][y] = { "type":Level.FLOOR_NORMAL };

						Level.boxes.push({
							"type":Level.BOX_TYPE_YELLOW,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;

					case '0':
						Level.floor[x][y] = { "type":Level.FLOOR_RED };

						Level.boxes.push({
							"type":Level.BOX_TYPE_GREEN,
							"state":firstGreen ? Level.BOX_STATE_ACTIVE : Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						firstGreen = false;
						break;

					case '2':
						Level.floor[x][y] = { "type":Level.FLOOR_RED };

						Level.boxes.push({
							"type":Level.BOX_TYPE_PURPLE,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;

					case '6':
						Level.floor[x][y] = { "type":Level.FLOOR_PURPLE };

						Level.boxes.push({
							"type":Level.BOX_TYPE_RED,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;

					case 'D':
						Level.floor[x][y] = { "type":Level.FLOOR_CYAN };

						Level.boxes.push({
							"type":Level.BOX_TYPE_CYAN,
							"state":Level.BOX_STATE_INACTIVE,
							"x":x,
							"y":y,
							"z":0
						});
						break;
				}
			}
		}

		return true;
	}

	function Array2D(xMax, yMax)
	{
		var arr = new Array(xMax);

		for (var i = 0; i < arr.length; i++)
		{
			arr[i] = new Array(yMax)
		}

		return arr;
	}

	/*
		Level Access-Code Handling
	*/
	function encodeLevelKey(states, pyramid)
	{
		codeId = Math.floor(Math.random() * 32);
		var code = codes[codeId];
		var key = codes[0].charAt(codeId);

		var val;
		var checksum = 0;
		for (var i = 0, j = 0; i < states.length; i += 5, j++)
		{
			val = 0;
			if (states.charAt(i + 3) == '1') { val += 1; }
			if (states.charAt(i + 1) == '1') { val += 2; }
			if (states.charAt(i + 4) == '1') { val += 4; }
			if (states.charAt(i + 0) == '1') { val += 8; }
			if (states.charAt(i + 2) == '1') { val += 16; }
			
			checksum += ((j + 1) * val);
			val ^= salt[j];
			key += code.charAt(val);
			if (j == 2 || j == 6 || j == 10) { key += '-'; }
		}
		checksum += pyramid;
		key += code.charAt(pyramid);
		key += code.charAt((checksum % 32) ^ salt[0]);

		return key;
	}

	// returns 'null' if the key is invalid
	function decodeLevelKey(key)
	{
		key = key.replace('-', '', 'g');
		
		codeId = codes[0].indexOf(key.charAt(0));
		if (codeId == -1) { return null; }
		var code = codes[codeId];

		var val;
		var checksum = 0;
		var states = '';
		for (var i = 0; i < key.length - 3; i++)
		{
			val = code.indexOf(key.charAt(i + 1));
			if (val == -1) { return null; }

			val ^= salt[i];
			checksum += ((i + 1) * val);

			states += (val & 8 ? '1' : '0');
			states += (val & 2 ? '1' : '0');
			states += (val & 16 ? '1' : '0');
			states += (val & 1 ? '1' : '0');
			states += (val & 4 ? '1' : '0');
		}

		pyramid = code.indexOf(key.charAt(key.length - 2));
		if (pyramid == -1) { return null; }
		checksum += pyramid;

		var origChecksum = code.indexOf(key.charAt(key.length - 1));
		if (origChecksum == -1) { return null; }
		origChecksum ^= salt[0];

		if ((checksum % 32) != origChecksum)
		{
			return null;
		}

		// Überprüfen ob der Zustand überhaupt möglich ist:
		for (var i = 0; i < states.length; i += 10)
		{
			if (states.charAt(i + 9) == '1' && (states.charAt(i + 7) != '1' || states.charAt(i + 8) != '1')) { return null; }
			if (states.charAt(i + 7) == '1' && (states.charAt(i + 4) != '1' || states.charAt(i + 5) != '1')) { return null; }
			if (states.charAt(i + 8) == '1' && (states.charAt(i + 5) != '1' || states.charAt(i + 6) != '1')) { return null; }
			if (states.charAt(i + 4) == '1' && (states.charAt(i + 0) != '1' || states.charAt(i + 1) != '1')) { return null; }
			if (states.charAt(i + 5) == '1' && (states.charAt(i + 1) != '1' || states.charAt(i + 2) != '1')) { return null; }
			if (states.charAt(i + 6) == '1' && (states.charAt(i + 2) != '1' || states.charAt(i + 3) != '1')) { return null; }
		}

		/* 9 = Max number of pyramids */
		if (pyramid > 9) { return null; }

		return { 'states':states, 'pyramid':pyramid };
	}
})();
