// Conway's Game of Life and Javascript + HTML Quine
// Page source is the same as shown code.
window.onload = function()
{
	const theJs = "";
	const github = "Github"; // My github :)
	// Add the script tag to the webpage
	quine("theJs = \"", /*
*/"<script src='quine.html'></script>"/**/);
	// Add github link to the page
	quine("github = \"", /**/"<b><a href='http://github.com/snowl'>"/**/);
	quine2("\"; //", /**/"</a></b>"/**/);
	// Add XMP tags each place an XMP tag exists
	// This works because the XMP tag within an XMP tag won't be interpreted.
	const xmp = document.getElementsByTagName('xmp');
	for (let i = 0; i < xmp.length; i++)
	{
		xmp[i].style.display = "inline";
		xmp[i].innerHTML = "<" + "xmp>" + xmp[i].innerHTML;
		xmp[i].innerHTML += "<" + "/xmp>";
	}
	// Format nicely (quine completed)
	// Make the website mono-spaced and show line-breaks
	document.body.innerHTML = "<" + "pre style='margin: 8px;'>" + document.body.innerHTML + "<" + "/pre>";
	// Set a margin of 0 so we can have a full-screen canvas
	document.body.style.margin = 0;
	// Below this we can start making Conway's Game of Life
	// Lets create a canvas below our text to have some fun
	const canvas = document.createElement("canvas");
	const ctx = canvas.getContext("2d");
	canvas.style.position = "fixed";
	canvas.style.left = "0px";
	canvas.style.top = "0px";
	canvas.style.zIndex = "-1";
	// Add the canvas to the body of the page
	document.body.appendChild(canvas);
	// Set up a Conway's Game of Life
	let lifeSize = 10, lifeRows, lifeColumns, lifeGame;
	setup();
	// Render conway's game every 30ms
	setInterval(() =>
	{
		// Set up the style of drawn rectangles
		ctx.fillStyle = "#EFEFEF";
		// Clear the screen
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		// Draw the current state of the board
		for (let x = 0; x < lifeRows; x++)
		{
			for (let y = 0; y < lifeColumns; y++)
			{
				if (lifeGame[x][y] == 1)
				{
					ctx.fillRect(x * lifeSize, y * lifeSize, lifeSize, lifeSize);
				}
			}
		}
		// Create a new temporary state
		let tempGame = [];
		for (let x = 0; x < lifeRows; x++)
		{
			tempGame[x] = [];
			for (let y = 0; y < lifeColumns; y++)
			{
				// Get the neighbours of the current state
				let neighbours = getNeighbours(x, y);
				// Check how many neighbours the current cell has
				let aliveNeighbours = 0;
				for (let m = 0; m < 8; m++)
				{
					if (neighbours[m] !== undefined && neighbours[m] == 1)
					{
						aliveNeighbours += 1;
					}
				}
				// If the current cell is dead, toggle on if 3 alive neighbours, otherwise toggle off
				if (lifeGame[x][y] == 0)
				{
					if (aliveNeighbours == 3)
					{
						tempGame[x][y] = 1;
					}
					else
					{
						tempGame[x][y] = 0;
					}
				}
				else
				{
					// Keep cell alive if it has 2 or 3 neigbours, otherwise set it off
					if (aliveNeighbours == 2 || aliveNeighbours == 3)
					{
						tempGame[x][y] = 1;
					}
					else
					{
						tempGame[x][y] = 0;
					}
				}
			}
		}
		// Apply the changes to the board
		lifeGame = tempGame;
	}, 30);
	// Resize the canvas when the window is resized
	window.onresize = setup;
	
	// Press the N key to create a new game
	window.onkeyup = (e) => e.keyCode == 78 && (lifeGame = genGame());
	function setup()
	{
		canvas.width = window.innerWidth;
		canvas.height = window.innerHeight;
		lifeRows = Math.round(canvas.width / lifeSize);
		lifeColumns = Math.round(canvas.height / lifeSize);
		// Recreate a new Conway's Game
		lifeGame = genGame();
	}
	// Set up conway's game of life
	function genGame()
	{
		// Create a new array and populate it with random data
		let lifeGame = [];
		for (let x = 0; x < lifeRows; x++)
		{
			lifeGame[x] = new Array();
			for (let y = 0; y < lifeColumns; y++)
			{
				lifeGame[x][y] = Math.round(Math.random());
			}
 	 	}
	  	return lifeGame;
	}
	// Get the individual neighbours of the current cell
	function getNeighbours(x, y)
	{
		var neighbours = new Array();
		// Only get the cells on left if possible
		if (lifeGame[x - 1] != undefined)
		{
			neighbours.push(lifeGame[x - 1][y - 1]);
			neighbours.push(lifeGame[x - 1][y]);
			neighbours.push(lifeGame[x - 1][y + 1]);
		}
		neighbours.push(lifeGame[x][y - 1]);
		neighbours.push(lifeGame[x][y + 1]);
		// Only get the cells on right if possible
		if (lifeGame[x + 1] != undefined)
		{
			neighbours.push(lifeGame[x + 1][y - 1]);
			neighbours.push(lifeGame[x + 1][y]);
			neighbours.push(lifeGame[x + 1][y + 1]);
		}
		return neighbours;
	}
	//  Wow :)
	function quine(tag, text)
	{
		document.body.innerHTML = document.body.innerHTML.replace(tag, tag + text);
	}
	//  Wow :)
	function quine2(tag, text)
	{
		document.body.innerHTML = document.body.innerHTML.replace(tag, text + tag);
	}
}