const commandBarElement = document.getElementById('menu-bar');
const toolBarElement = document.getElementById('tool-bar');
const layerBarElement = document.getElementById('layer-bar');
const studioElement = document.getElementById('studio');
const infoBarElement = document.getElementById('info-bar');
const easelElement = document.getElementById('easel');
const brushPreviewElement = document.getElementById('brush-preview');

const dZoom = 0.001;
const dBrushSize = 0.5;
const initialWidth = 800;
const initialHeight = 600;
const maxBrushSize = 500;

let brushColor = 'rgb(0, 0, 0)';
let brushShape = 'square'
let brushSize = 1;
let zoom = 1;
let currentTool = 'brush'
let prevTool = 'brush'

let startX = 0;
let startY = 0;
let endX = 0;
let endY = 0;
let dX = 0;
let dY = 0;
let canvasStartX = 0;
let canvasStartY = 0;
let canvasEndX = 0;
let canvasEndY = 0;
let canvasDX = 0;
let canvasDY = 0;

let isKeyDown = false;
let isMouseDown = false;

// HELPERS {{{

function hexToRgbArray(hex) {
    if (hex.startsWith('#')) {
        hex = hex.slice(1);
    }

    if (hex.length === 3) {
        hex = hex.split('').map(char => char + char).join('');
    }

    const bigint = parseInt(hex, 16);
    return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
}

function colorsMatch(a, b) {
    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
}

function makeButtonElement({icon, name, clickFunction, key}) {
	if (!icon) throw new Error('No icon provided');
	if (!name) throw new Error('No name provided');
	if (!clickFunction) throw new Error('No click function provided');
	if (!key) throw new Error('No key provided');

	const buttonElement = document.createElement('div');
	buttonElement.className = 'button';
	buttonElement.innerHTML = icon;
	buttonElement.title = name;
	buttonElement.addEventListener('click', clickFunction);
	if (key) {
		const keyHint = document.createElement('span');
		keyHint.className = 'key-hint';
		keyHint.innerHTML = key;
		buttonElement.appendChild(keyHint);
	}
	return buttonElement;
}

// }}}

// LAYERS {{{

// factory {{{

function makeCanvas({height=600, width=800}) { // {{{
	const canvas = document.createElement('canvas');
	easelElement.appendChild(canvas);
	canvas.style.imageRendering = 'pixelated';
	canvas.ctx = canvas.getContext('2d');

	canvas.tempCanvas = document.createElement('canvas');
	canvas.tempCtx = canvas.tempCanvas.getContext('2d');

	canvas.disableImageSmoothing = function(ctx) {
		ctx.imageSmoothingEnabled = false;
		if (ctx.imageSmoothingEnabled !== false) {
			ctx.mozImageSmoothingEnabled = false;
			ctx.webkitImageSmoothingEnabled = false;
			ctx.msImageSmoothingEnabled = false;
		}
	};

	canvas.saveTempCanvas = function() {
		canvas.ctx.save();
		canvas.tempCanvas.width = canvas.width;
		canvas.tempCanvas.height = canvas.height;
		canvas.disableTempImageSmoothing(canvas.tempCtx);
		canvas.tempCtx.drawImage(canvas, 0, 0);
	}

	canvas.restoreTempCanvas = function() {
		canvas.ctx.clearRect(0, 0, canvas.width, canvas.height);
		canvas.ctx.drawImage(canvas.tempCanvas, 0, 0);
		canvas.ctx.restore();
	}

	canvas.setHeight = function(height) {
		canvas.height = height;
		canvas.disableImageSmoothing(canvas.ctx);
	};

	canvas.setWidth = function(width) {
		canvas.width = width;
		canvas.disableImageSmoothing(canvas.ctx);
	};

	canvas.getPositionOnCanvas = function(e) {
		const rect = canvas.getBoundingClientRect();
		return {
			x: Math.round((e.clientX - rect.left) / zoom),
			y: Math.round((e.clientY - rect.top) / zoom),
		};
	}

	canvas.drawPixel = function(x, y, color) {
		console.log({x, y, color});
		canvas.ctx.fillStyle = color;
		canvas.ctx.fillRect(x, y, 1, 1);
	}

	canvas.drawLineWithPixels = function(x1, y1, x2, y2, color) {
		const dx = Math.abs(x2 - x1);
		const dy = Math.abs(y2 - y1);
		const sx = x1 < x2 ? 1 : -1;
		const sy = y1 < y2 ? 1 : -1;
		let err = dx - dy;
		while (true) {
			canvas.drawPixel(x1, y1, color); // Draw each pixel along the line
			if (x1 === x2 && y1 === y2) break;
			const e2 = err * 2;
			if (e2 > -dy) { err -= dy; x1 += sx; }
			if (e2 < dx) { err += dx; y1 += sy; }
		}
	}


	canvas.drawShape = function(x, y, shape, size, color) {
		if (size == 1) {
			canvas.drawPixel(x, y, color);
			return;
		}
		canvas.ctx.fillStyle = color;
		if (shape === 'square') {
			canvas.ctx.fillRect(x - Math.floor(size / 2), y - Math.floor(size / 2), size, size);
		}
	}

	canvas.getColorAtPixel = function(data, x, y) {
		const index = (y * canvas.width + x) * 4;
		return [data[index], data[index + 1], data[index + 2], data[index + 3]];
	}

	canvas.setColorAtPixel = function(data, x, y, color) {
		const index = (y * canvas.width + x) * 4;
		data[index] = color[0];
		data[index + 1] = color[1];
		data[index + 2] = color[2];
		data[index + 3] = 255;
	}


	canvas.fill = function(color) {
		canvas.ctx.fillStyle = color;
		canvas.ctx.fillRect(0, 0, canvas.width, canvas.height);
	}

	canvas.floodFill = function(x, y, color) {
		const imageData = canvas.ctx.getImageData(0, 0, canvas.width, canvas.height);
		const data = imageData.data;

		const targetColor = canvas.getColorAtPixel(data, x, y);
		const fillColorArray = hexToRgbArray(color);

		if (colorsMatch(targetColor, fillColorArray)) {
			return;
		}

		const stack = [{x, y}];

		while (stack.length > 0) {
			const {x, y} = stack.pop();
			const currentColor = canvas.getColorAtPixel(data, x, y);

			if (colorsMatch(currentColor, targetColor)) {
				canvas.setColorAtPixel(data, x, y, fillColorArray);

				if (x > 0) stack.push({x: x - 1, y});
				if (x < canvas.width - 1) stack.push({x: x + 1, y});
				if (y > 0) stack.push({x, y: y - 1});
				if (y < canvas.height - 1) stack.push({x, y: y + 1});
			}
		}

		canvas.ctx.putImageData(imageData, 0, 0);
	}

	canvas.toDataUrl = function() {
		const dataURL = canvas.toDataURL();
		const dimensions = `${canvas.width}x${canvas.height}`;
		return {dataURL, dimensions};
	}

	canvas.fromDataUrl = function(dataURL, dimensions) {
		const img = new Image();
		img.src = dataURL;
		img.onload = function() {
			canvas.width = dimensions.split('x')[0];
			canvas.height = dimensions.split('x')[1];
			canvas.style.width = canvas.width * zoom + 'px';
			canvas.style.height = canvas.height * zoom + 'px';
			canvas.ctx.drawImage(img, 0, 0);
		}
	}

	canvas.deleteCanvas = function() {
		canvas.remove();
	}

	canvas.setWidth(width);
	canvas.setHeight(height);

	return canvas;

} // }}}

function makeLayer({height=600, width=800}) { // {{{
	const layer = {}
	layer.canvas = makeCanvas({height, width});
	layer.active = false;
	layer.opacity = 1;
	layer.controllerElement = document.createElement('div');
	layer.controllerElement.className = 'layer-controller';
	layer.controllerElement.addEventListener('click', () => {
		layers.setActive(layer);
	});

	layer.activate = function() {
		layer.active = true;
		layer.controllerElement.classList.add('active');
	}

	layer.deactivate = function() {
		layer.active = false;
		layer.controllerElement.classList.remove('active');
	}

	return layer;
} // }}}

function makeLayers({height=600, width=800}) { // {{{
	const layers = [];
	layers.height = height;
	layers.width = width;

	layers.setHeight = function(height) {
		layers.height = height;
		easelElement.style.height = height + 2 + 'px';
	}

	layers.setHeight(height);

	layers.setWidth = function(width) {
		layers.width = width;
		easelElement.style.width = width + 2 + 'px';
	}

	layers.setWidth(width);

	layers.resetPosition = function() {
		const studioRect = studioElement.getBoundingClientRect();
		easelElement.style.left = `${studioRect.left}px`;
		easelElement.style.top = `${studioRect.top}px`;
	}

	layers.updateControllers = function() {
		layerBarElement.innerHTML = '';
		layers.forEach(layer => {
			layerBarElement.appendChild(layer.controllerElement);
		});
	}

	layers.add = function() {
		const layer = makeLayer({
			height: layers.height,
			width: layers.width,
		});
		layers.push(layer);
		layer.activate();
		layers.updateControllers();
	}

	layers.delete = function(layer) {
		layer.canvas.deleteCanvas();
		layers.splice(layers.indexOf(layer), 1);
		layers.updateControllers();
	}

	layers.deleteAll = function() {
		layers.forEach(layer => layer.deleteCanvas());
		// TODO
	}

	layers.move = function(layer, index) {
		layers.splice(layers.indexOf(layer), 1);
		layers.splice(index, 0, layer);
	}

	layers.setActive = function(layer) {
		layers.forEach(layer => layer.deactivate());
		layer.activate();
	}

	layers.getActive = function() {
		return layers.find(layer => layer.active);
	}

	return layers;
} // }}}

// }}}

const layers = makeLayers({height: initialHeight, width: initialWidth});
layers.add();
layers.add();
layers[0].canvas.fill('rgb(255, 255, 255)');
layers.setActive(layers[1]);

// }}}

// COLOR PREVIEW {{{

function makeColorPreview() {
	const colorPreview = {}
	colorPreview.element = document.createElement('div');
	colorPreview.element.id = 'color-preview';
	colorPreview.element.className = 'puck';
	colorPreview.element.style.backgroundColor = brushColor;
	commandBarElement.appendChild(colorPreview.element);
	colorPreview.update = function() {
		colorPreview.element.style.backgroundColor = brushColor;
	}
}

const colorPreview = makeColorPreview();

// }}}

// COMMANDS {{{

// factory {{{

function makeCommand({name, key, icon, clickFunction}) {
	if (!name) throw new Error('No name provided');
	if (!icon) throw new Error('No icon provided');
	if (!clickFunction) throw new Error('No click function provided');
	if (!key) throw new Error('No key provided');

	const command = {};
	command.name = name;
	command.key = key;
	command.buttonElement = makeButtonElement({icon, name, clickFunction, key});
	commandBarElement.appendChild(command.buttonElement);

	return command
}

function makeCommands() {
	const commands = [];

	commands.add = function({name, key, icon, clickFunction}) {
		const command = makeCommand({name, key, icon, clickFunction});
		commands.push(command);
	}

	return commands;
}


// }}}

const commands = makeCommands();

commands.add({ // flip-horizontally {{{
	name: 'flip-horizontally',
	key: 'f',
	icon: '<i class="fa-solid fa-left-right"></i>',
	clickFunction: function flipCanvasHorizontally() {
		const canvas = layers.getActive().canvas;
		const ctx = canvas.ctx;
		ctx.save();
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		ctx.scale(-1, 1);
		ctx.translate(-canvas.width, 0);
		canvas.restoreTempCanvas();
		ctx.restore();
	}
}); // }}}

commands.add({ // flip-vertically {{{
	name: 'flip-vertically',
	key: 'v',
	icon: '<i class="fa-solid fa-up-down"></i>',
	clickFunction: function flipCanvasVertically() {
		const canvas = layers.getActive().canvas;
		const ctx = canvas.ctx;
		ctx.save();
		canvas.saveTempCanvas();
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		ctx.scale(1, -1);
		ctx.translate(0, -canvas.height);
		canvas.restoreTempCanvas();
		ctx.restore();
	}
}); // }}}

commands.add({ // export {{{
	name: 'export',
	key: 'e',
	icon: '<i class="fa-solid fa-floppy-disk"></i>',
	clickFunction: function exportCanvas() {
		const canvas = layers.getActive().canvas;
		const link = document.createElement('a');
		link.download = 'canvas.png';
		link.href = canvas.toDataURL();
		link.click();
	}
}); // }}}

commands.add({ // import {{{
	name: 'import',
	key: 'i',
	icon: '<i class="fa-regular fa-folder-open"></i>',
	clickFunction: function importCanvas() {
		const canvas = layers.getActive().canvas;
		const ctx = canvas.ctx;
		const input = document.createElement('input');
		input.type = 'file';
		input.accept = 'image/*';
		input.onchange = (e) => {
			const file = e.target.files[0];
			const reader = new FileReader();
			reader.onload = (e) => {
				const img = new Image();
				img.onload = () => {
					canvas.width = img.width;
					canvas.height = img.height;
					ctx.drawImage(img, 0, 0);
				}
				img.src = e.target.result;
			}
			reader.readAsDataURL(file);
		}
		input.click();
	}
}); // }}}

commands.add({ // clear {{{
	name: 'clear',
	key: 'c',
	icon: '<i class="fa-solid fa-trash-can"></i>',
	clickFunction: function clearCanvas() {
		const canvas = layers.getActive().canvas;
		const ctx = canvas.ctx;
		canvas.saveTempCanvas();
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		ctx.fillStyle = 'white';
		ctx.fillRect(0, 0, canvas.width, canvas.height);
	}
}); // }}}

commands.add({ // reset {{{
	name: 'reset',
	key: 't',
	icon: '<i class="fa-solid fa-house"></i>',
	clickFunction: function resetZoom() {
		layers.resetPosition();
		// zoom = 1;
		// canvas.style.width = canvas.width * zoom + 'px';
		// canvas.style.height = canvas.height * zoom + 'px';
		// TODO

	}
}); // }}}

// }}}

// TOOLS {{{

// factory {{{

function makeTool({name, key, icon, mouseDown, mouseMove, mouseUp}) {
	if (!name) throw new Error('No name provided');
	if (!key) throw new Error('No key provided');
	if (!icon) throw new Error('No icon provided');

	const tool = {};
	tool.name = name;
	tool.key = key;
	tool.icon = icon;
	tool.mouseDown = mouseDown;
	tool.mouseMove = mouseMove;
	tool.mouseUp = mouseUp;
	tool.active = false;

	tool.buttonElement = makeButtonElement({
		icon: tool.icon,
		name: tool.name,
		key: tool.key,
		clickFunction: function() {
			tools.activate(tool);
			tool.buttonElement.classList.add('active');
		}
	});
	toolBarElement.appendChild(tool.buttonElement);

	tool.activate = function() {
		currentTool = tool.name;
		tool.active = true;
	}

	tool.deactivate = function() {
		tool.active = false;
		tool.buttonElement.classList.remove('active');
	}


	return tool;
}

function makeTools() {
	const tools = [];

	tools.add = function({name, key, icon, mouseDown, mouseMove, mouseUp}) {
		const tool = makeTool({name, key, icon, mouseDown, mouseMove, mouseUp});
		tools.push(tool);
	}

	tools.activate = function(tool) {
		tools.forEach(tool => tool.deactivate());
		tool.activate();
	}

	return tools;
}

// }}}

const tools = makeTools();

tools.add({ // brush {{{
	name: 'brush',
	key: 'b',
	icon: '<i class="fa-solid fa-paintbrush"></i>',
	mouseDown: function(e) {
		const canvas = layers.getActive().canvas;
		if (brushSize == 1) {
			canvas.drawPixel(canvasStartX, canvasStartY, brushColor);
		} else {
			canvas.drawShape(canvasStartX, canvasStartY, brushShape, brushSize, brushColor);
		}
	},
	mouseMove: function(e) {
		const canvas = layers.getActive().canvas;
		if (brushSize == 1) {
			canvas.drawLineWithPixels(canvasStartX, canvasStartY, canvasEndX, canvasEndY, brushColor);
			return;
		} else {
			canvas.drawShape(canvasEndX, canvasEndY, brushShape, brushSize, brushColor);
		}
		canvasStartX = canvasEndX;
		canvasStartY = canvasEndY;
	},
}); // }}}

tools.add({ // content-move {{{
	name: 'content-move',
	key: 'h',
	icon: '<i class="fa-regular fa-hand"></i>',
	mouseMove: function(e) {
		const canvas = layers.getActive().canvas;
		canvas.ctx.clearRect(0, 0, canvas.width, canvas.height);
		canvas.ctx.fillStyle = 'white';
		canvas.ctx.fillRect(0, 0, canvas.width, canvas.height);
		canvas.restoreTempCanvas();
	},
}); // }}}

tools.add({ // move {{{
	name: 'move',
	key: 'm',
	icon: '<i class="fa-solid fa-arrows-up-down-left-right"></i>',
	mouseDown: function(e) {
		startX = e.clientX - easelElement.offsetLeft;
		startY = e.clientY - easelElement.offsetTop;
	},
	mouseMove: function(e) {
		easelElement.style.left = dX + 'px';
		easelElement.style.top = dY + 'px';
	},
}); // }}}

tools.add({ // zoom {{{
	name: 'zoom',
	key: 'z',
	icon: '<i class="fa-solid fa-magnifying-glass"></i>',
	mouseMove: function(e) {
		// TODO all canvases
		// const canvas = layers.getActive().canvas;
		zoom += dX * dZoom;
		if (zoom < 0.1) zoom = 0.1;
		// canvas.style.height = canvasHeight * zoom + 'px';
		// canvas.style.width = canvasWidth * zoom + 'px';
		startX = endX;
	}
}); // }}}

tools.add({ // bucket-fill {{{
	name: 'bucket-fill',
	key: 'k',
	icon: '<i class="fa-solid fa-fill"></i>',
	mouseDown: function(e) {
		// canvas = layers.getActive().canvas;
		// canvas.floodFill(canvasStartX, canvasStartY, brushColor);
	}
}); // }}}

tools.add({ // color-picker {{{
	name: 'color-picker',
	key: 'a',
	icon: '<i class="fa-solid fa-eye-dropper"></i>',
	mouseDown: function(e) {
		const canvas = layers.getActive().canvas;
		const imageData = canvas.ctx.getImageData(canvasStartX, canvasStartY, 1, 1).data;
		const pickedColor = `rgb(${imageData[0]}, ${imageData[1]}, ${imageData[2]})`;
		brushColor = pickedColor;
		colorPreview.update();
	}
}); // }}}

tools.add({ // brush-size {{{
	name: 'brush-size',
	key: 'd',
	icon: '<i class="fa-regular fa-circle-dot"></i>',
	mouseMove: function(e) {
		brushSize += dX * dBrushSize;
		if (brushSize < 1) brushSize = 1;
		if (brushSize > maxBrushSize) brushSize = maxBrushSize;
		startX = endX;
	}
}); // }}}

tools.add({ // resize {{{
	name: 'resize',
	key: 'r',
	icon: '<i class="fa-solid fa-ruler-combined"></i>',
	mouseMove: function(e) {
		// const canvas = layers.getActive().canvas;
		// let newWidth = canvasWidth + dX / zoom;
		// let newHeight = canvasHeight + dY / zoom;
		// if (newWidth > 0 && newHeight > 0) {
		// 	canvas.setWidth(newWidth);
		// 	canvas.setHeight(newHeight);
		// 	canvas.style.width = newWidth * zoom + 'px';
		// 	canvas.style.height = newHeight * zoom + 'px';
		// 	canvas.ctx.clearRect(0, 0, canvas.width, canvas.height);
		// 	canvas.ctx.fillStyle = backgroundColor;
		// 	canvas.ctx.fillRect(0, 0, canvas.width, canvas.height);
		// 	canvas.ctx.drawImage(tempCanvas, 0, 0);
		// }
	}
}); // }}}

tools.add({ // color-mix {{{
	name: 'color-mix',
	key: 'x',
	icon: '<i class="fa-solid fa-mortar-pestle"></i>',
	mouseMove: function(e) {
		// const canvas = layers.getActive().canvas;
		const imageData = ctx.getImageData(canvasEndX, canvasEndY, 1, 1).data;
		const canvasColor = `rgb(${imageData[0]}, ${imageData[1]}, ${imageData[2]})`;

		const distance = Math.sqrt(Math.pow(e.clientX - startX, 2) + Math.pow(e.clientY - startY, 2));
		const t = Math.min(1, distance / 300);

		const mixedColor = mixbox.lerp(brushColor, canvasColor, t);

		brushColor = mixedColor;

		startX = e.clientX;
		startY = e.clientY;
	}	
}); // }}}

// }}}

// PUCKS {{{

// factory {{{

function createPuck({puckColor, key, editable=true}) {
	if (!puckColor) throw new Error('No puck color provided');

	const puck = {}
	puck.element = document.createElement('div');
	puck.element.style.backgroundColor = puckColor;
	puck.element.className = 'puck';

	if (editable) {
		const deleteHandle = document.createElement('div');
		deleteHandle.className = 'delete-handle';
		deleteHandle.innerHTML = '<i class="fa-solid fa-trash-can"></i>';
		puck.element.appendChild(deleteHandle);
		deleteHandle.addEventListener('click', () => {
			puck.element.remove();
		});
	}

	if (key) {
		const keyHint = document.createElement('div');
		keyHint.className = 'key-hint';
		keyHint.innerHTML = key;
		puck.element.appendChild(keyHint);
	}

	function mixx(startTime) {
		var interval = setInterval(() => {
			const elapsedTime = Date.now() - startTime;
			const t = Math.min(1, elapsedTime / 10000);
			const mixedColor = mixbox.lerp(brushColor, puck.style.backgroundColor, t);
			brushColor = mixedColor;
			colorPreview.update();
			infos.update();
		}, 50);
		return interval;
	}

	puck.element.addEventListener('mousedown', () => {
		const startTime = Date.now();
		var interval = mixx(startTime);
		function onMouseUp() {
			clearInterval(interval);
			document.removeEventListener('mouseup', onMouseUp);
		}
		document.addEventListener('mouseup', onMouseUp);
	});

	puck.keydown = function(e) {
		if (e.key == key) {
			const startTime = Date.now();
			var interval = mixx(startTime);
			function onKeyUp() {
				clearInterval(interval);
				document.removeEventListener('keyup', onKeyUp);
			}
			document.addEventListener('keyup', onKeyUp);
		}
	}

	commandBarElement.appendChild(puck.element);
}

function makePucks() {
	const pucks = [];

	pucks.add = function({puckColor, key, editable}) {
		const puck = createPuck({puckColor, key, editable});
		pucks.push(puck);
	}

	return pucks;
}

// }}}

const pucks = makePucks();

pucks.add({
	puckColor: 'rgb(0, 0, 0)',
	key: '1',
	editable: false,
});

pucks.add({
	puckColor: 'rgb(255, 255, 255)',
	key: '2',
	editable: false,
});

pucks.add({
	puckColor: 'rgb(255, 0, 0)',
	key: '3',
	editable: false,
});

pucks.add({
	puckColor: 'rgb(0, 255, 0)',
	key: '4',
	editable: false,
});

pucks.add({
	puckColor: 'rgb(0, 0, 255)',
	key: '5',
	editable: false,
});

// }}}

// INFO {{{

function makeInfo({name, updateFunction}) {
	if (!name) throw new Error('No name provided');
	if (!updateFunction) throw new Error('No update function provided');

	const info = {};
	info.name = name;
	info.updateFunction = updateFunction;

	info.element = document.createElement('span');
	info.element.className = 'info';

	const key = document.createElement('span');
	key.className = 'key';
	key.innerHTML = info.name + ':';

	const value = document.createElement('span');
	value.className = 'value';
	value.innerHTML = '0';

	info.element.appendChild(key);
	info.element.appendChild(value);

	infoBarElement.appendChild(info.element);

	info.update = function() {
		let v = updateFunction();
		if (v === undefined) v = '?';
		value.innerHTML = v;
	}

	return info;
}

function makeInfos() {
	const infos = []
	infos.add = function({name, updateFunction}) {
		const info = makeInfo({name, updateFunction});
		infos.push(info);
	}
	infos.update = function() {
		infos.forEach(function(info){
			info.update();
		});
	}
	return infos;
}

const infos = makeInfos();

infos.add({
	name: 'zoom',
	updateFunction: function() {
		var percent = zoom * 100;
		return percent.toFixed(0) + '%';
	}
});

infos.add({
	name: 'brush',
	updateFunction: function() {
		return brushSize;
	}
});


infos.add({
	name: 'x',
	updateFunction: function() {
		return canvasEndX;
	}
});


infos.add({
	name: 'y',
	updateFunction: function() {
		return canvasEndY;
	}
});

infos.add({
	name: 'color',
	updateFunction: function() {
		return brushColor;
	}
});

infos.add({
	name: 'width',
	updateFunction: function() {
		return "width";
	}
});

infos.add({
	name: 'height',
	updateFunction: function() {
		return "height";
	}
});

// }}}

// MOUSE EVENT LISTENERS {{{

studioElement.addEventListener('mousedown', (e) => {
	const canvas = layers.getActive().canvas;
	isMouseDown = true;
	startX = e.clientX;
	startY = e.clientY;
	canvasStartX = canvas.getPositionOnCanvas(e).x;
	canvasStartY = canvas.getPositionOnCanvas(e).y;

	for (var i = 0; i < tools.length; i++) {
		var tool = tools[i];
		if (tool.name === currentTool) {
			if (tool.mouseDown) {
				tool.mouseDown(e);
				break;
			}
		}
	}

	infos.update();

});

studioElement.addEventListener('mousemove', (e) => {
	const canvas = layers.getActive().canvas;
	endX = e.clientX;
	endY = e.clientY;
	dX = endX - startX;
	dY = endY - startY;
	canvasEndX = canvas.getPositionOnCanvas(e).x;
	canvasEndY = canvas.getPositionOnCanvas(e).y;
	canvasDX = canvasEndX - canvasStartX;
	canvasDY = canvasEndY - canvasStartY;

	if (currentTool == 'brush-size') {
		brushPreviewElement.style.display = 'block';
		brushPreviewElement.style.width = brushSize + 'px';
		brushPreviewElement.style.height = brushSize + 'px';
		brushPreviewElement.style.left = e.clientX - brushSize / 2 + 'px';
		brushPreviewElement.style.top = e.clientY - brushSize / 2 + 'px';
	}

	if (isMouseDown) {
		for (var i = 0; i < tools.length; i++) {
			var tool = tools[i];
			if (tool.name === currentTool) {
				if (tool.mouseMove) {
					tool.mouseMove(e);
					break;
				}
			}
		}
	}

	infos.update();

});

studioElement.addEventListener('mouseup', () => {
	isMouseDown = false;
	infos.update();
});

studioElement.addEventListener('mouseleave', () => {
	isMouseDown = false;
	brushPreviewElement.style.display = 'none';
	infos.update();
});

// }}}

// KEYBINDINGS {{{

document.addEventListener('keydown', (e) => {
	if (isKeyDown) return;

	tools.forEach(tool => {
		if (tool.key.toLowerCase() === e.key.toLowerCase()) {
			prevTool = currentTool;
			currentTool = tool.name;
		}
	});

	commands.forEach(command => {
		if (command.key.toLowerCase() === e.key.toLowerCase()) {
			command.clickFunction();
		}
	});

	pucks.filter(puck => puck.key).forEach(puck => {
		if (puck.key.toLowerCase() === e.key.toLowerCase()) {
			puck.keydown(e);
		}
	});

	isKeyDown = true;

});

document.addEventListener('keyup', (e) => {
	tools.forEach(tool => {
		if (tool.key.toLowerCase() === e.key) {
			currentTool = prevTool;
		}
	});

	isKeyDown = false;

});

// }}}

layers.resetPosition();