// CREATE A GIF FOCUSED GIF OR PNG OVER SELECTED fit
// anim variable can be true(for gif) or a number for timestep, for png
// call from interactive-forecast-viewer folder 
// date currently does not work, and defaults to current day, or most recent data
// node create_model_loop_zoom_fit true monarch 20220808 od550_dust spain

const { Cluster } = require('puppeteer-cluster');
const util = require('util');
const path = require('path');
const url = 'http://127.0.0.1:9000/dashboard/'
// const url = 'http://0.0.0.0:7778/dashboard/'
const modelDict = {'od550_dust':'AOD',
    'sconc_dust':'Concentration',
    'dust_depd':'Dry deposition',
    'dust_depw':'Wet deposition',
    'dust_load':'Load',
    'dust_ext_sfc':'Extinction'};

//READ COORDINATES AND CENTER FROM CONF FILE
const relpath = path.relative('js/create_model_loop_zoom_fit.js', 'interactive-forecast-viewer/conf/coords.json');
const coords = require(relpath);

function delay(time) {
    return new Promise(function(resolve) { 
	setTimeout(resolve, time)
    });
}

const RunCluster = async (anim, curmodel, seldate, variable, fit) => {
    const cluster = await Cluster.launch({
	concurrency: Cluster.CONCURRENCY_CONTEXT,
	puppeteerOptions: {
	    headless: true,
	    args: [
		'--no-sandbox',
		'--disable-setuid-sandbox',
	    ]
	},
	maxConcurrency: 4,
    });

    await cluster.task(async ({ page, data: args }) => {
	process.stdout.write("ARGS: " + args + "\n");
	var tstep = args[0];
	var curmodel = args[1];
	var seldate = args[2];
	var variable = args[3];
	var fit = args[4].toLowerCase();
	process.stdout.write("TSTEP: " + tstep + " -- MOD: " + curmodel + " -- DATE: " + seldate + " -- VAR: " + variable +' fit: ' + fit + "\n");
	var width_aspect = parseInt(coords[fit].width);
	var height_aspect = parseInt(coords[fit].height);
	await page.setViewport({ width: width_aspect, height: height_aspect});
	await page.goto(url, {
	    waitUntil: 'networkidle0',
	});
	await page.waitForSelector("#graph-collection");
	// select variable
	try {            
	    const sel = await page.$('#variable-dropdown-forecast');
	    await sel.click();
	    await page.waitForSelector(".Select-menu-outer");
	    const dropdown_variable = modelDict[variable];
	    process.stdout.write("Selected dropdown variable: " + dropdown_variable + '\n');
	    await page.evaluate((dropdown_variable) => {
		const options = [...document.querySelectorAll('.VirtualizedSelectOption')];
		selected_variable = options.find(element => element.textContent === dropdown_variable);
		selected_variable.click();
	    }, dropdown_variable);
	} catch (err) {
	    process.stdout.write("ERR0: " + err + "\n");
	}
	// select all models 
	if (curmodel === "all") {
	    try {            
		process.stdout.write("SELECT ALL MODELS\n");
		for (const model of await page.$$('.custom-control-input')) {
		    const checked = await model.evaluate(elem => elem.checked);
		    process.stdout.write("CHECKED BEFORE: " + checked + "\n");
		    if (!checked) {
			await model.click();
		    }
		}
	    } catch (err) {
		process.stdout.write("ERR1: " + err + "\n");
	    }
	}
	// select only one model 
	else {
	    try {            
		process.stdout.write("SELECT MODEL: " + curmodel + "\n");
		for (const model of await page.$$('.custom-control-input')) {
		    const checked = await model.evaluate(elem => elem.checked);
		    process.stdout.write("CHECKED BEFORE: " + checked + "\n");
		    const value = await model.evaluate(elem => elem.value);
		    process.stdout.write("VALUE: " + value + "\n");
		    if (!checked && value === curmodel) {
			await model.click();
		    }
		    if (checked && value !== curmodel) {
			await model.click();
			await delay(500);
		    }
		}
	    } catch (err) {
		process.stdout.write("ERR2: " + err + "\n");
	    }
	}
	// apply button
	try {
	    for (const model of await page.$$('.custom-control-input')) {
		const checked = await model.evaluate(elem => elem.checked);
		process.stdout.write("CHECKED AFTER: " + checked + "\n");
	    }
	    process.stdout.write("CLICK APPLY BUTTON\n");
	    const btn = await page.$('#models-apply');
	    await btn.click();  // "button#models-apply");
	    await delay(500);
	} catch (err) {
	    process.stdout.write("ERR3: " + err + "\n");
	}
	// apply none fit button
	try {
	    var zoom = coords[fit].zoom;
	    var lat = coords[fit].lat;
	    var lon = coords[fit].lon;
	    process.stdout.write("Zoom: " + zoom  + " Lat " + lat + " Lon " + lon +"\n");

	    // Change hidden inputs and button to visible
	    let zoomInput = await page.$('#country-zoom');
	    await zoomInput.evaluate((el) => el.style.display = 'block');
	    let latInput = await page.$('#country-lat');
	    await latInput.evaluate((el) => el.style.display = 'block');
	    let lonInput = await page.$('#country-lon');
	    await lonInput.evaluate((el) => el.style.display = 'block');
	    let zoomButton = await page.$('#country-focus');
	    await zoomButton.evaluate((el) => el.style.display = 'block');

	    // Add data and click 
	    await page.type('#country-zoom', zoom);
	    await page.type('#country-lat', lat);
	    await page.type('#country-lon', lon);
	    process.stdout.write("CLICK HIDDEN country BUTTON\n");
	    await page.click('#country-focus');

	    // Make elements invisible again
	    await zoomInput.evaluate((el) => el.style.display = 'none');
	    await latInput.evaluate((el) => el.style.display = 'none');
	    await lonInput.evaluate((el) => el.style.display = 'none');
	    await zoomButton.evaluate((el) => el.style.display = 'none');

	} catch (err) {
	    process.stdout.write("ERR4: " + err + "\n");
	}
	var num = "00";
	if (tstep === "false") {
	    process.stdout.write("CURRENT SELECTION: " + tstep + "\n");
	    num = "_curr";
	} else {
	    process.stdout.write("CURRENT TSTEP: " + tstep + "\n");
	    const steps = await page.$$("span.rc-slider-dot");
	    await steps[tstep].click();
	    if (tstep<10) {
		num = "0"+tstep;
	    } else {
		num = tstep;
	    }
	}
	// wait for alert div to disappear to start grabbing elements 
	await page.waitForSelector("#alert-forecast", {hidden: true});
	await page.waitForSelector("#graph-collection");
	const graph = await page.$('#graph-collection');
	// change graph height to fill output gif
	let graphHeight = await page.$('.leaflet-container');
	await graphHeight.evaluate((el) => el.style.height = '93vh');
	// remove timeslider 
	await page.waitForSelector(".navbar-timebar");
	process.stdout.write("REMOVING NAVBAR" + "\n");
	await page.evaluate((sel) => {
	    let toRemove = document.querySelector(sel);
	    toRemove.parentNode.removeChild(toRemove);
	}, '.navbar-timebar');
	// remove zoom panel 
	process.stdout.write("REMOVING ZOOM PANEL(S)" + "\n");
	await page.waitForSelector(".leaflet-bar");
	await page.evaluate((sel) => {
	    let toRemove = document.querySelectorAll(sel);
	    for (let j=0; j<toRemove.length; j++) {
		toRemove[j].parentNode.removeChild(toRemove[j]);
	    }
	}, '.leaflet-bar');

	if (coords[fit].logos == true){
	    try {
		//reveal logos 
		process.stdout.write("REVEALING LOGOS" + "\n");

		//style logos
		let logos = await page.$('#logos');
		await logos.evaluate((el) => el.style.display = 'inline');
		await logos.evaluate((el, margin) => {el.style.marginTop = margin}, coords[fit].marginTop);
		await logos.evaluate((el, padding) => {el.style.paddingRight = padding}, coords[fit].paddingRight);
	    } catch (err) {
		console.log(err);
		process.stdout.write("ERR5:" + err + "\n");
	    }
	};
	// Move disclaimer into the image for the monarch_fit
        let disclaimer = await page.$('.disclaimer');
        await disclaimer.evaluate((el) => el.style.right = '1px');
	// Handle output and take screenshot
	//Filename shouldn't include fit unless it is a specified country
	if (fit == 'monarch_fit' || fit == 'default') {
	    // Change the below to './js/tmp' ... during developement, run script from interactiv...
	    var outputFile = './tmp/' + variable.toLowerCase() + '/' + seldate + '_' + curmodel + '_' + num + '.png';
	} else {
	    // Create a filename that includes the specified country fit
	    // Change the below to './js/tmp' ... during developement, run script from interactiv...
	    var outputFile = './tmp/' + variable.toLowerCase() + '/' + fit + '/' + seldate + '_' + curmodel + '_' + fit + '_' + num + '.png';
	}

	process.stdout.write("TAKE SCREENSHOT => " + outputFile + "\n");
	await graph.screenshot({ path: outputFile });

    });

    if (anim === "true") {
	for (let i=0; i<25; i++) {
	    try {
		process.stdout.write("QUEUEING step:" + i + "\n");
		await cluster.queue([i, curmodel, seldate, variable, fit]);
	    } catch (err) {
		console.log(err);
		process.stdout.write("ERR6:" + err + "\n");
	    }
	}
    } else {
	process.stdout.write("QUEUEING current:" + anim + "\n");
	cluster.queue([anim, curmodel, seldate, variable, fit]);
    }

    await cluster.idle();
    await cluster.close();
}

var anim = process.argv[2];      // default: false;
var curmodel = process.argv[3];  // default: "none";
var seldate = process.argv[4];   // default: "none";
var variable = process.argv[5];  // default: OD550_DUST
var fit = process.argv[6];	 

process.stdout.write("START -> ANIM: " + anim + " CURMODEL: " + curmodel + " DATE: " + seldate + " VAR: " +  variable + " fit: " + fit + "\n");
RunCluster(anim, curmodel, seldate, variable, fit);

