import { WebGLRenderer, OrthographicCamera, Scene, Vector2 } from "three";

import { RenderLayer } from "./tilelayer";
import { RenderTileset } from "./tileset";

const CAMERA_UNIT = 100;

export class Renderer {
	constructor(canvas) {
		this._canvas = canvas;
		this.renderer = new WebGLRenderer({
			canvas
		});
		this.camera = new OrthographicCamera(0, CAMERA_UNIT, 0, CAMERA_UNIT, 0.1, CAMERA_UNIT * 10);
		this.camera.position.z = CAMERA_UNIT;
		this.scene = new Scene();

		this._layers = [];
		this._tilesets = [];

		this.update();
	}

	get width() {
		return this._canvas.offsetWidth;
	}

	get height() {
		return this._canvas.offsetHeight;
	}

	update(shouldUpdate = "everything") {
		const should = type => {
			return shouldUpdate === "everything" || shouldUpdate[type];
		};

		if (should("size")) {
			this._updateSize(this.width, this.height);
		}

		if (should("camera")) {
			this.camera.updateProjectionMatrix();
		}

		if (should("tiles")) {
			for (let layer of this._layers) {
				layer.update();
			}
		}

		this.render();
	}

	render() {
		this.renderer.render(this.scene, this.camera);
	}

	changeMap(map) {
		// Completely reset the scene and rebuild it.
		this.scene = new Scene();

		this.map = map;

		this._tilesets = [];
		for (let i = 0; i < this.map.tilesets.length; i++) {
			RenderTileset.load(map.tilesets[i], this)
				.then(renderTileset => {
					this._tilesets[i] = renderTileset;
					this.update();
				}, e => {
					console.error("Something went wrong while loading a texture", e);
				});
		}

		this._layers = map.layers.map(layer => {
			const renderLayer = new RenderLayer(this, layer);
			this.scene.add(renderLayer);
			return renderLayer;
		});
	}

	getTileset(id) {
		return this._tilesets[id];
	}

	getTileAtMouse(position, layerId) {
		const normalizedPosition = new Vector2();
		normalizedPosition.x = (position.x / this.width) * 2 - 1;
		normalizedPosition.y = -(position.y / this.height) * 2 + 1;

		return this._layers[layerId].raycastToTile(normalizedPosition, this.camera);
	}

	_updateSize(width, height) {
		this.renderer.setSize(width, height);
		this.camera.right = width / height * CAMERA_UNIT;
	}
}

@@ -182,16 +182,38 @@
 = 100;%0A%0A
+let testing = false;%0A%0A
 export c
@@ -228,16 +228,152 @@
 derer %7B%0A
+%09static enableTesting() %7B%0A%09%09testing = true;%0A%09%09console.info(%22%5Bdtile-three-renderer%5D Testing mode enabled; WebGL will not be used.%22);%0A%09%7D%0A%0A
 %09constru
@@ -412,16 +412,35 @@
 canvas;%0A
+%09%09if (!testing) %7B%0A%09
 %09%09this.r
@@ -472,16 +472,17 @@
 er(%7B%0A%09%09%09
+%09
 canvas%0A%09
@@ -482,20 +482,25 @@
 anvas%0A%09%09
+%09
 %7D);%0A
+%09%09%7D%0A
 %09%09this.c
@@ -1234,24 +1234,47 @@
 %09render() %7B%0A
+%09%09if (testing) return;%0A
 %09%09this.rende
@@ -2263,24 +2263,43 @@
 , height) %7B%0A
+%09%09if (!testing) %7B%0A%09
 %09%09this.rende
@@ -2326,16 +2326,171 @@
 eight);%0A
+%09%09%7D else %7B%0A%09%09%09this._canvas.style.width = width;%0A%09%09%09this._canvas.style.height = height;%0A%09%09%09this._canvas.width = width;%0A%09%09%09this._canvas.height = height;%0A%09%09%7D%0A
 %09%09this.c

Add support for headless testing