const [
	EMPTY, SNAKE,
	FOOD, SUPER_FOOD, DECAY_FOOD,
	WALL,
	FIRE, FLAMMABLE, FLAMMABLE_S,
	HOLE, HOLE_S,
	PORTAL_A, PORTAL_A_S, PORTAL_B, PORTAL_B_S, PORTAL_C, PORTAL_C_S, PORTAL_D, PORTAL_D_S,
	KEY, DOOR,
	SWITCH_ON, SWITCH_ON_S, SWITCH_OFF, SWITCH_OFF_S, SPIKES_OFF, SPIKES_OFF_S, SPIKES_ON
]=Array(255).keys();

const tiles={
	EMPTY, SNAKE,
	FOOD, SUPER_FOOD, DECAY_FOOD,
	WALL,
	FIRE, FLAMMABLE, FLAMMABLE_S,
	HOLE, HOLE_S,
	PORTAL_A, PORTAL_A_S, PORTAL_B, PORTAL_B_S, PORTAL_C, PORTAL_C_S, PORTAL_D, PORTAL_D_S,
	KEY, DOOR,
	SWITCH_ON, SWITCH_ON_S, SWITCH_OFF, SWITCH_OFF_S, SPIKES_OFF, SPIKES_OFF_S, SPIKES_ON
};

const tileNames=(() => {
	let tileNames=[];
	Object.keys(tiles).forEach(key => tileNames[tiles[key]]=key);
	return tileNames;
})();

const getName=t =>
	tileNames[t] || `Unknown tile ${t}`;

const forChar=c => {
	switch(c) {
	 	case ' ': return EMPTY;
		case 'f': return FOOD;
		case 'F': return SUPER_FOOD;
		case 'd': return DECAY_FOOD;
		case 'w': return WALL;
		case 'o': return HOLE;
		case 'i': return FIRE;
		case 'I': return FLAMMABLE;
		case 'A': return PORTAL_A;
		case 'B': return PORTAL_B;
		case 'C': return PORTAL_C;
		case 'D': return PORTAL_D;
		case 'k': return KEY;
		case 'K': return DOOR;
		case 's': return SWITCH_OFF;
		case 'S': return SPIKES_ON;
		case 't': return SPIKES_OFF;
	}
	throw TypeError(`'${c}' doesn't correspond to any tile`);
};

const charFor=t => {
	switch(t) {
		case EMPTY:			return ' ';
		case FOOD:			return 'f';
		case SUPER_FOOD:	return 'F';
		case DECAY_FOOD:	return 'd';
		case WALL:			return 'w';
		case HOLE:			return 'o';
		case FIRE:			return 'i';
		case FLAMMABLE:		return 'I';
		case PORTAL_A:		return 'A';
		case PORTAL_B:		return 'B';
		case PORTAL_C:		return 'C';
		case PORTAL_D:		return 'D';
		case KEY:			return 'k';
		case DOOR:			return 'K';
		case SWITCH_OFF:	return 's';
		case SPIKES_ON:		return 'S';
		case SPIKES_OFF:	return 't';
	}
	throw TypeError(`'${getName(t)}' doesn't have a corresponding character'`);
};

const snakeVersion=t => {
	switch(t) {
		case EMPTY:			return SNAKE;
		case HOLE:			return HOLE_S;
		case FLAMMABLE:		return FLAMMABLE_S;
		case PORTAL_A:		return PORTAL_A_S;
		case PORTAL_B:		return PORTAL_B_S;
		case PORTAL_C:		return PORTAL_C_S;
		case PORTAL_D:		return PORTAL_D_S;
		case SWITCH_OFF:	return SWITCH_OFF_S;
		case SWITCH_ON:		return SWITCH_ON_S;
		case SPIKES_OFF:	return SPIKES_OFF_S;
	}
	throw TypeError(`'${getName(t)}' doesn't have a snake version'`);
};

const nonSnakeVersion=t => {
	switch(t) {
		case SNAKE:			return EMPTY;
		case HOLE_S:		return HOLE;
		case FLAMMABLE_S:	return FLAMMABLE;
		case PORTAL_A_S:	return PORTAL_A;
		case PORTAL_B_S:	return PORTAL_B;
		case PORTAL_C_S:	return PORTAL_C;
		case PORTAL_D_S:	return PORTAL_D;
		case SWITCH_OFF_S:	return SWITCH_OFF;
		case SWITCH_ON_S:	return SWITCH_ON;
		case SPIKES_OFF_S:	return SPIKES_OFF;
	}
	throw TypeError(`'${getName(t)}' doesn't have a non-snake version'`);
};

const isSnakeVersion=t => {
	switch(t) {
		case SNAKE:
		case HOLE_S:
		case FLAMMABLE_S:
		case PORTAL_A_S: case PORTAL_B_S: case PORTAL_C_S: case PORTAL_D_S:
		case SWITCH_OFF_S: case SWITCH_ON_S:
		case SPIKES_OFF_S:
			return true;
	}
	return false;
};

const isNonSnakeVersion=t => {
	switch(t) {
		case EMPTY:
		case HOLE:
		case FLAMMABLE:
		case PORTAL_A: case PORTAL_B: case PORTAL_C: case PORTAL_D:
		case SWITCH_OFF: case SWITCH_ON:
		case SPIKES_OFF:
			return true;
	}
	return false;
};

const isSafe=t => {
	switch(t) {
		case EMPTY:
		case HOLE:
		case FLAMMABLE:
		case PORTAL_A: case PORTAL_B: case PORTAL_C: case PORTAL_D:
		case SWITCH_OFF: case SWITCH_ON:
		case SPIKES_OFF:
		case FOOD: case SUPER_FOOD: case DECAY_FOOD:
		case KEY:
			return true;
	}
	return false;
};

const isWall=t => {
	switch(t) {
		case WALL:
		case FIRE:
		case DOOR:
		case SPIKES_ON:
			return true;
	}
	return false;
};

const getType=t => {
	if(isSnakeVersion(t)) return 'snake';
	if(isWall(t)) return 'wall';

	switch(t) {
		case EMPTY:
		case FLAMMABLE:
		case SPIKES_OFF:
			return 'empty';

		case FOOD:
			return 'food';

		case SUPER_FOOD:
		case DECAY_FOOD:
			return 'bonus';

		case HOLE:
			return 'hole';

		case PORTAL_A:
		case PORTAL_B:
		case PORTAL_C:
		case PORTAL_D:
			return 'portal';

		case KEY:
			return 'key';

		case SWITCH_ON:
		case SWITCH_OFF:
			return 'switch';
	}

	throw TypeError(`'${getName(t)}' isn't a valid tile`);
};

const isPortal=t => {
	switch(t) {
		case PORTAL_A:
		case PORTAL_B:
		case PORTAL_C:
		case PORTAL_D:
		case PORTAL_A_S:
		case PORTAL_B_S:
		case PORTAL_C_S:
		case PORTAL_D_S:
			return true;
	}
	return false;
};

return module.exports={
	tiles,
	tileNames, getName,
	forChar, charFor,
	snakeVersion, nonSnakeVersion, isSnakeVersion, isNonSnakeVersion,
	isSafe, isWall, isPortal,
	getType
};
