/*
    pyRCV2: Preferential vote counting
    Copyright © 2020–2021  Lee Yingtong Li (RunasSudo)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

let candidates = [];
let ballots = [];

let inpFile = document.getElementById('inpFile');
let txtBallotValue = document.getElementById('txtBallotValue');
let tblBallot = document.getElementById('tblBallot');
let selBallots = document.getElementById('selBallots');

selBallots.value = 'new';

function initBallot() {
	// Init ballot table
	tblBallot.innerHTML = '';
	for (let candidate of candidates) {
		let elTr = document.createElement('tr');
		
		let elTd = document.createElement('td');
		let elInput = document.createElement('input');
		elInput.type = 'number';
		elInput.min = '1';
		elInput.style.width = '3em';
		elTd.appendChild(elInput);
		elTr.appendChild(elTd);
		
		// Add listener
		elInput.addEventListener('keyup', function(evt) {
			if (evt.key === 'Enter') {
				evt.preventDefault();
				clickSave();
			}
		});
		
		elTd = document.createElement('td');
		elTd.innerText = candidate;
		elTr.appendChild(elTd);
		
		tblBallot.appendChild(elTr);
	}
}

function clickSave() {
	// Save ballot
	let ballot = {'value': txtBallotValue.value, 'preferences': []};
	for (let elInput of tblBallot.querySelectorAll('input')) {
		ballot['preferences'].push(elInput.value);
	}
	
	if (selBallots.value === 'new') {
		// New ballot
		ballots.push(ballot);
		
		// Add new ballot <option>
		let elOption = document.createElement('option');
		elOption.innerText = 'Ballot ' + ballots.length;
		selBallots.insertBefore(elOption, selBallots.selectedOptions[0]);
	} else if (selBallots.selectedIndex >= 0) {
		// Editing existing ballot
		ballots[selBallots.selectedIndex] = ballot;
		
		// Advance to next ballot
		selBallots.selectedIndex += 1;
	}
	
	// Update ballot entry
	changeBallot();
}

function changeBallot() {
	if (selBallots.value === 'new') {
		// Clear input
		for (let elInput of tblBallot.querySelectorAll('input')) {
			elInput.value = '';
		}
		txtBallotValue.value = '1';
	} else if (selBallots.selectedIndex >= 0) {
		// Update input
		let ballot = ballots[selBallots.selectedIndex];
		let i = 0;
		for (let elInput of tblBallot.querySelectorAll('input')) {
			elInput.value = ballot['preferences'][i];
			i += 1;
		}
		txtBallotValue.value = ballot['value'];
	}
	
	// Move cursor to first input box
	tblBallot.querySelector('input').focus();
	tblBallot.querySelector('input').select();
}

let openMode = 'json';

function clickOpenJSON() {
	openMode = 'json';
	inpFile.value = '';
	inpFile.click();
}

function clickImportBLT() {
	openMode = 'blt';
	inpFile.value = '';
	inpFile.click();
}

async function changeInpFile() {
	if (inpFile.value !== '') {
		if (openMode === 'json') {
			// Open JSON file
			let text = await inpFile.files[0].text();
			let obj = JSON.parse(text);
			
			// Load data
			candidates = obj['candidates'];
			ballots = obj['ballots'];
		} else if (openMode === 'blt') {
			// Open BLT file
			let text = await inpFile.files[0].text();
			
			// Import data
			py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.StringNum);
			let election = py.pyRCV2.blt.readBLT(text);
			
			candidates = [];
			for (let candidate of election.candidates) {
				candidates.push(candidate.py_name);
			}
			
			ballots = [];
			for (let ballot of election.ballots) {
				let js_ballot = {'value': ballot.value.__str__(), 'preferences': []};
				for (let i = 0; i < candidates.length; i++) {
					js_ballot['preferences'].push('');
				}
				
				// Add preference numbers
				for (let i = 0; i < ballot.preferences.length; i++) {
					candidate = ballot.preferences[i];
					js_ballot['preferences'][election.candidates.indexOf(candidate)] = '' + (i + 1);
				}
				
				ballots.push(js_ballot);
			}
		}
		
		// Go to ballot entry screen
		document.getElementById('bltMain').style.display = '';
		document.getElementById('divEditCandidates').style.display = 'none';
		
		// Update ballot entry
		initBallot();
		
		// Update ballot list
		selBallots.innerHTML = '<option value="new" selected>-- New Ballot --</option>';
		selBallots.value = 'new';
		
		for (let i = 0; i < ballots.length; i++) {
			let elOption = document.createElement('option');
			elOption.innerText = 'Ballot ' + (i + 1);
			selBallots.insertBefore(elOption, selBallots.selectedOptions[0]);
		}
		
		inpFile.value = '';
	}
}

function clickSaveJSON() {
	let result = {
		'candidates': candidates,
		'ballots': ballots,
	};
	
	// Download file
	let url = URL.createObjectURL(new File([JSON.stringify(result)], 'ballots.json', {type: 'application/json'}));
	let elA = document.createElement('a');
	elA.href = url;
	elA.download = '';
	elA.click();
}

function clickExportBLT() {
	let election = py.pyRCV2.model.Election();
	
	let result = window.prompt('Enter the number of seats to elect:', '1');
	if (result !== null) {
		election.seats = parseInt(result);
	} else {
		return;
	}
	
	result = window.prompt('Enter the name of the election:');
	if (result !== null) {
		election.name = result;
	} else {
		return;
	}
	
	for (let candidate of candidates) {
		let py_candidate = py.pyRCV2.model.Candidate(candidate);
		election.candidates.push(py_candidate);
	}
	
	// Process ballots
	for (let ballot of ballots) {
		let py_ballot = py.pyRCV2.model.Ballot(py.pyRCV2.numbers.StringNum(ballot['value']), []);
		
		for (let i = 1; i < candidates.length + 1; i++) {
			let candidate = null;
			for (let j = 0; j < candidates.length; j++) {
				if (ballot.preferences[j].trim() === '' + i) {
					candidate = j;
					break;
				}
			}
			
			if (candidate !== null) {
				py_ballot.preferences.push(election.candidates[candidate]);
			} else {
				// No such preference
				break;
			}
		}
		
		election.ballots.push(py_ballot);
	}
	
	// Download file
	let url = URL.createObjectURL(new File([py.pyRCV2.blt.writeBLT(election)], 'election.blt', {type: 'application/json'}));
	let elA = document.createElement('a');
	elA.href = url;
	elA.download = '';
	elA.click();
}

function clickEditCandidates() {
	document.getElementById('bltMain').style.display = 'none';
	document.getElementById('divEditCandidates').style.display = '';
	document.getElementById('txtCandidates').value = candidates.join('\n');
}

function clickSaveCandidates() {
	candidates = [];
	for (let candidate of document.getElementById('txtCandidates').value.split('\n')) {
		if (candidate.trim() !== '') {
			candidates.push(candidate.trim());
		}
	}
	
	// Update ballot entry
	initBallot();
	changeBallot();
	
	document.getElementById('bltMain').style.display = '';
	document.getElementById('divEditCandidates').style.display = 'none';
}
