"use strict";

import chroma from 'chroma-js';

import Config from '../Config.mjs';

import VoronoiOverlay from './VoronoiOverlay.mjs';
import VoronoiCell from './VoronoiCell.mjs';

import Gauge from '../Gauge.mjs';
import Specs from './OverlaySpecs.mjs';

import Vector2 from '../Helpers/Vector2.mjs';
import GetFromUrl from '../Helpers/GetFromUrl.mjs';
import { round_date_interval } from '../Helpers/DateHelper.mjs';

class VoronoiManager {
	
	constructor(in_device_data, in_map) {
		this.device_data = in_device_data;
		this.map = in_map;
		
		this.layer = null;
		
		this.last_datetime = new Date();
		this.last_reading_type = "PM25";
	}
	
	async setup() {
		this.setup_guage();
		await this.setup_overlay();
	}
	
	async setup_overlay() {
		this.overlay = new VoronoiOverlay();
		await this.set_data(new Date(), "PM25"); // TODO: Make this customisable? Probably elsewhere though, as this is a reasonable default
	}
	
	setup_guage() {
		this.guage = new Gauge(document.getElementById("canvas-guage"));
	}
	
	// ------------------------------------------------------------------------
	
	async update_reading_type(new_reading_type) {
		await this.set_data(this.last_datetime, new_reading_type);
	}
	async update_datetime(new_datetime) {
		await this.set_data(new_datetime, this.last_reading_type);
	}
	
	async set_data(datetime, reading_type) {
		this.last_datetime = datetime;
		this.last_reading_type = reading_type;
		
		round_date_interval(this.last_datetime, Config.date_rounding_interval);
		
		this.spec = Specs[reading_type] || Specs["unknown"];
		if(typeof this.spec.chroma == "undefined")
			this.spec.chroma = chroma.scale(Object.values(this.spec.gradient))
				.domain(Object.keys(this.spec.gradient));
		this.guage.set_spec(this.spec);
		this.guage.render();
		
		
		let dataset = null;
		try {
			dataset = JSON.parse(await GetFromUrl(
				`${Config.api_root}?action=fetch-data&datetime=${encodeURIComponent(datetime.toISOString())}&reading_type=${encodeURIComponent(reading_type)}`
			));
		}
		catch(error) { // string
			document.querySelector("main").classList.remove("working-visual");
			alert(error);
			throw new Error(error);
		}
		
		let result = [];
		for(let row of dataset) {
			let device = this.device_data.get_by_id(row.device_id);
			if(typeof device.latitude != "number" || typeof device.longitude != "number")
				continue;
			result.push(new VoronoiCell(
				new Vector2(
					device.longitude,
					device.latitude
				),
				// See https://gka.github.io/chroma.js/
				this.spec.chroma(row.value).toString()
			));
		}
		
		this.overlay.set_cells(result);
		
		if(this.layer !== null)
			this.layer.remove(); // Remove the old layer if it exists
		// Generate & add the new layer
		this.layer = this.overlay.generate_layer();
		this.layer.addTo(this.map);
	}
}

export default VoronoiManager;