//const width = 2048;
//const height = 2048;
const tileSize = 8;

function getRGBA(data, i) {
	let out = new Uint8Array(4);
	for (let j = i * 4; j < i * 4 + 4; j++) {
		out[j - i * 4] = data[j];
	}
	return out;
}

function setRGBA(data, i, input) {
	for (let j = i * 4; j < i * 4 + 4; j++) {
		data[j] = input[j - i * 4];
	}
}

function toPoint(x2, y2, base, fac, exp, inSize) {
	let isMask = 1;
	x2 = Math.round(x2 / tileSize);
	y2 = Math.round(y2 / tileSize);
	for (let j = 0; j < exp; j++) {
		isMask *= base[(y2 % inSize) * inSize + (x2 % inSize)];

		x2 /= inSize;
		y2 /= inSize;

		x2 = Math.floor(x2);
		y2 = Math.floor(y2);

	}

	isMask *= fac;

	isMask = (isMask - 0.5) * 25 + 0.5;
	isMask = Math.max(isMask, 0);
	isMask = Math.min(isMask, 1);
	return isMask;
}

function Game(inSize, exp, cs) {
	this.exp = exp;
	this.inSize = inSize;
	this.cs = cs;

	this.img = new Image();
	this.base = new Float32Array(inSize * inSize);
	this.frames = 0;
	this.camera = [0, 0];

	this.dead = false;
}

Game.prototype.player = function () {
	let { ctx, fac, base, exp, inSize, camera, cs } = this;
	ctx.fillStyle = 'red';
	ctx.rect(cs / 2 - 2, cs / 2 - 2, 4, 4);
	ctx.fill();

	if (toPoint(camera[0], camera[1], base, fac, exp, inSize) == 0) {
		this.dead = true;
	}

	let cx = Math.floor(camera[0]) / tileSize;
	let cy = Math.floor(camera[1]) / tileSize;

	let sum = 0;

	for (let i in base) {
		sum += base[i]
	}

	sum *= fac;

	let dim = Math.log(sum) / (Math.log(base.length) / 2);

	document.querySelector('.ui-text').textContent = `Coordinates: ${cx},${cy}\nDimensionality: ${dim}`
}

Game.prototype.main = function () {
	var { base, inSize, ctx, cs, frames, exp, camera, dat } = this;
	if (this.dead) {
		document.querySelector('.message').style.display = 'flex';
		return;
	} else {
	}

	this.frames++;

	this.fac = 0.9999 ** frames;
	for (let i = 0; i < cs * cs; i++) {
		let x = i % cs
		let y = Math.floor(i / cs);

		x = x + Math.round(camera[0] - cs / 2);
		y = y + Math.round(camera[1] - cs / 2);

		let isMask = toPoint(x, y, base, this.fac, exp, inSize);
		if (x < 0 || y < 0) {
			setRGBA(dat.data, i, [0, 0, 0, 255])
			continue;
		}
		let rgb = [(Math.round(x / tileSize) % 2) ? 255 : 235, (Math.round(y / tileSize) % 2) ? 255 : 235, 255];

		setRGBA(dat.data, i, [rgb[0] * isMask, rgb[1] * isMask, rgb[2] * isMask, 255])
	}

	ctx.putImageData(dat, 0, 0, 0, 0, cs, cs);

	this.player();
}

Game.prototype.map = function () {
	var { base, inSize, exp } = this;

	//noise.seed(Math.random() * 1000);

	for (let i in base) {
		let x = i % inSize;
		let y = Math.floor(i / inSize);

		base[i] = Math.random();

		base[i] = Math.max(base[i], 0);
		base[i] = Math.min(base[i], 1);
		base[i] = Math.pow(base[i], 0.3);
		base[i] = base[i] * 0.4 + 0.6;
		//base[i] = (Math.random() > 0.5) ? 0 : 1; 
	}

	this.fac = 1;

	let x2 = 0, y2 = 0;

	while (true) {
		x2 = Math.random() * 1e5;
		y2 = Math.random() * 1e5;
		let mask = toPoint(x2, y2, base, this.fac, exp, inSize);
		if (mask == 1) break;
	}
	this.camera = [x2, y2];
}

Game.prototype.loop = function () {
	let that = this;
	setInterval(function () { that.main() }, 1000 / 60);
}

Game.prototype.startGame = function () {
	var canvas = document.querySelector("#canvas");
	canvas.width = this.cs;
	canvas.height = this.cs;

	var ctx = this.ctx = canvas.getContext("2d");

	ctx.imageSmoothingEnabled = false;

	this.dat = ctx.getImageData(0, 0, this.cs, this.cs);

	this.map();
	this.loop();
}

Game.prototype.init = function () {
	let that = this;
	that.startGame();
}

let game = new Game(8, 4, 32 * tileSize)

game.init();