class HeatMap {
	/* 
		Está clase sirve para la creación de Mapas de Calor en ChartJS, a partir del plugin chartjs-chart-geo:
		--- https://github.com/sgratzl/chartjs-chart-geo ---
		En este caso está planteado para utilizar archivos topo-json 
		--- https://github.com/topojson/topojson ---
	*/

	constructor(countries, subdivision, focus, labels, data, ctx, responsive, colors, displayValues = true, colorNumbers = '#900000') {
		this.countries = countries;		// Países
		this.subdivision = subdivision;	// Divisón territorial (0, 1, 2 ...) subdivisión que se quiere ver (Estados/Regiones, Municipios, etc.)
		this.focus = focus;				// Ampliar una subdivisión en concreto
		this.labels = labels;			// Nombres de cada división
		this.data = data;				// Valores númericos de cada división
		this.ctx = ctx;					// Ruta donde se crea la Chart
		this.responsive = responsive;
		this.colors = colors;
		this.displayValues = displayValues;
		this.colorNumbers = colorNumbers;
	}

	createHeatMap() {
		let chart;
		switch (this.countries) {
			case 'mex':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('mex.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('mex_mun.topo');
				}
				break;
			case 'col':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('col.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('col_mun.topo');
				}
				break;
			case 'dom':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('dom.topo');
				} else if(this.subdivision == 1) {
					//this.fetchTopoJSON('');
				}
				break;
			case 'ecu':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('ecu.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('ecu_can.topo');
				}
				break;
			case 'gtm':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('gtm.topo');
				} else if(this.subdivision == 1) {
					//this.fetchTopoJSON('');
				}
				break;
			case 'hon':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('hon.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('hon_mun.topo');
				}
				break;
			case 'pan':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('pan.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('pan_mun.topo');
				}
				break;
			case 'per':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('per.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('per_pro.topo');
				} else if(this.subdivision == 2) {
					this.fetchTopoJSON('per_dis.topo');
				}
				break;
			case 'slv':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('slv.topo');
				} else if(this.subdivision == 1) {
					//this.fetchTopoJSON('');
				}
				break;
			case 'esp':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('esp.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('esp_pro.topo');
				} else if(this.subdivision == 2) {
					this.fetchTopoJSON('esp_mun.topo');
				}
				break;
			case 'bra':
				if(this.subdivision == 0) {
					this.fetchTopoJSON('bra.topo');
				} else if(this.subdivision == 1) {
					this.fetchTopoJSON('bra.topo');
				} else if(this.subdivision == 2) {
					this.fetchTopoJSON('bra_mun.topo');
				}
				break;
			default:
				break;
		}
	}

	fetchTopoJSON(fileName) {
		/* 
			Al introducir más abajo los datos de mapData se puede utilizar tanto el
			d.propierties.name (nombre de la región), como el d.id (identificador de la región)
		*/
		let mapData = new Map();

		for(let i = 0; i < this.data.length; i++) {
			mapData.set(this.labels[i], this.data[i]);
		}

		ChartGeoChart.register(ChartDataLabelsGeo);
		fetch('./resources/topojson/' + fileName + '.json').then((r) => r.json()).then((data) => {
			// Dependiendo del JSON que se utilice, hay que cambiar el objeto 'data.objects.x' (o modificar el JSON y dejarlos todos iguales)
			let regionObject;
			switch (fileName) {
				case 'mex.topo':
					regionObject = data.objects.mex;
					break;
				case 'mex_mun.topo':
					regionObject = data.objects.mx_muns;
					break;
				case 'col.topo':
					regionObject = data.objects.col;
					break;
				case 'col_mun.topo':
					regionObject = data.objects.mpios;
					break;
				case 'ecu.topo':
					regionObject = data.objects.ecu;
					break;
				case 'ecu_can.topo':
					regionObject = data.objects.cantones_ecuador;
					break;
				case 'gtm.topo':
					regionObject = data.objects.gtm;
					break;
				case 'hon.topo':
					regionObject = data.objects.hnd;
					break;
				case 'hon_mun.topo':
					regionObject = data;
					break;
				case 'pan.topo':
					regionObject = data.objects.pan;
					break;
				case 'pan_mun.topo':
					regionObject = data.objects.pan_mun;
					break;
				case 'per.topo':
					regionObject = data.objects.per;
					break;
				case 'per_pro.topo':
					regionObject = data.objects.peru_provincial_simple;
					break;
				case 'per_dis.topo':
					regionObject = data.objects.peru_distrital_simple;
					break;
				case 'slv.topo':
					regionObject = data.objects.slv;
					break;
				case 'dom.topo':
					regionObject = data.objects.dom;
					break;
				case 'esp.topo':
					regionObject = data.objects.autonomous_regions;
					break;
				case 'esp_pro.topo':
					regionObject = data.objects.provinces;
					break;
				case 'esp_mun.topo':
					regionObject = data.objects.municipios;
					break;
				case 'bra.topo':
					regionObject = data.objects.bra;
					break;
				default:
					break;
			}

			const countries = ChartGeo.topojson.feature(data, regionObject).features;

			// JSON España sin las islas canarias
			// 'https://raw.githubusercontent.com/deldersveld/topojson/master/countries/spain/spain-comunidad.json'
			// const countries = ChartGeo.topojson.feature(data, data.objects.ESP_adm1).features;

			/*
				Si se especifica el find, se puede centrar a partir de una región perteneciente al país,
				Si no se especifica, muestra el país al completo
			*/

			let outlineValue;
			if(this.focus == '') {
				outlineValue = countries; //.find(countries => countries.properties.name === 'Barcelona');
			} else {
				outlineValue = countries.find(countries => countries.properties.name === this.focus);
			}

			let chart = new ChartGeoChart(this.ctx, {
				type: 'choropleth',
				data: {
					labels: countries.map((d) => d.properties.name),
					datasets: [{
						label: 'Regiones',
						outline: outlineValue,
						borderColor: 'black',
						borderWidth: 1,
						data: countries.map((d) => ({feature: d, value: mapData.get(d.properties.name)})),
					}]
				},
				options: {
					responsive: this.responsive,
					plugins: {
						legend: {
							display: false,
						},
						datalabels: {
							display: this.displayValues,
							anchor: 'center',
							align: 'center',
							font: {
								weight: 'bold',
								size: 12
							},
							labels: {
								value: {
									color: this.colorNumbers
								}
							},
							formatter: (v) => mapData.get(v.feature.properties.name) ? mapData.get(v.feature.properties.name) : '0'
						}
					},
					scales: {
						xy: {
						// Como estándar, es mejor usar la proyección mercator, ya que es la que conserva mejor los ángulos
							projection: 'mercator',
						},
						color: {
							// Rango de colores que se utilizan para crear el mapa
							display: false,
							//interpolate: 'blues',
							interpolate: (value) => {
								let color = '';
								if(value <= 0.1) {
									color = this.colors[0];
								} else if(value <= 0.2) {
									color = this.colors[1];
								} else if(value <= 0.3) {
									color = this.colors[2];
								} else if(value <= 0.4) {
									color = this.colors[3];
								} else if(value <= 0.5) {
									color = this.colors[4];
								} else if(value <= 0.6) {
									color = this.colors[5];
								} else if(value <= 0.7) {
									color = this.colors[6];
								} else if(value <= 0.8) {
									color = this.colors[7];
								} else if(value <= 0.9) {
									color = this.colors[8];
								} else if(value <= 1) {
									color = this.colors[9];
								}
								return color;
							},
							legend: {
								position: 'bottom-right',
								align: 'right',
							}
						}
					}
				}
			});
		});
	}
}