/*
    pyRCV2: Preferential vote counting
    Copyright © 2020  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/>.
*/

function clickAdvancedOptions() {
	if (document.getElementById('divAdvancedOptions').style.display === 'none') {
		document.getElementById('divAdvancedOptions').style.display = 'block';
		document.getElementById('btnAdvancedOptions').innerHTML = 'Hide advanced options';
	} else {
		document.getElementById('divAdvancedOptions').style.display = 'none';
		document.getElementById('btnAdvancedOptions').innerHTML = 'Show advanced options';
	}
}

function changePreset() {
	if (document.getElementById('selPreset').value === 'scottish') {
		document.getElementById('selQuotaCriterion').value = 'geq';
		document.getElementById('selQuota').value = 'droop';
		document.getElementById('chkProgQuota').checked = false;
		document.getElementById('chkBulkElection').checked = true;
		document.getElementById('chkBulkExclusion').checked = false;
		document.getElementById('selNumbers').value = 'fixed';
		document.getElementById('txtDP').value = '5';
		document.getElementById('selSurplus').value = 'size';
		document.getElementById('selTransfers').value = 'wig';
		document.getElementById('selPapers').value = 'both';
		document.getElementById('selExclusion').value = 'one_round';
		document.getElementById('selTies').value = 'backwards_random';
	} else if (document.getElementById('selPreset').value === 'stvc') {
		document.getElementById('selQuotaCriterion').value = 'gt';
		document.getElementById('selQuota').value = 'droop_exact';
		document.getElementById('chkProgQuota').checked = true;
		document.getElementById('chkBulkElection').checked = true;
		document.getElementById('chkBulkExclusion').checked = true;
		document.getElementById('selNumbers').value = 'rational';
		document.getElementById('selSurplus').value = 'size';
		document.getElementById('selTransfers').value = 'wig';
		document.getElementById('selPapers').value = 'both';
		document.getElementById('selExclusion').value = 'one_round';
		document.getElementById('selTies').value = 'backwards_random';
	} else if (document.getElementById('selPreset').value === 'senate') {
		document.getElementById('selQuotaCriterion').value = 'geq';
		document.getElementById('selQuota').value = 'droop';
		document.getElementById('chkProgQuota').checked = false;
		document.getElementById('chkBulkElection').checked = true;
		document.getElementById('chkBulkExclusion').checked = true;
		document.getElementById('selNumbers').value = 'fixed';
		document.getElementById('txtDP').value = '0';
		document.getElementById('selSurplus').value = 'order';
		document.getElementById('selTransfers').value = 'uig';
		document.getElementById('selPapers').value = 'both';
		document.getElementById('selExclusion').value = 'by_value';
		document.getElementById('selTies').value = 'backwards_random';
	} else if (document.getElementById('selPreset').value === 'wright') {
		document.getElementById('selQuotaCriterion').value = 'geq';
		document.getElementById('selQuota').value = 'droop';
		document.getElementById('chkProgQuota').checked = false;
		document.getElementById('chkBulkElection').checked = true;
		document.getElementById('chkBulkExclusion').checked = true;
		document.getElementById('selNumbers').value = 'fixed';
		document.getElementById('txtDP').value = '5';
		document.getElementById('selSurplus').value = 'size';
		document.getElementById('selTransfers').value = 'wright';
		document.getElementById('selPapers').value = 'both';
		document.getElementById('selExclusion').value = 'one_round';
		document.getElementById('selTies').value = 'backwards_random';
	} else if (document.getElementById('selPreset').value === 'prsa77') {
		document.getElementById('selQuotaCriterion').value = 'geq';
		document.getElementById('selQuota').value = 'droop';
		document.getElementById('chkProgQuota').checked = false;
		document.getElementById('chkBulkElection').checked = true;
		document.getElementById('chkBulkExclusion').checked = false;
		document.getElementById('selNumbers').value = 'fixed';
		document.getElementById('txtDP').value = '0';
		document.getElementById('selSurplus').value = 'order';
		document.getElementById('selTransfers').value = 'eg';
		document.getElementById('selPapers').value = 'transferable';
		document.getElementById('selExclusion').value = 'parcels_by_order';
		document.getElementById('selTies').value = 'backwards_random';
	}
}

async function clickCount() {
	// Read BLT file
	let bltFile = document.getElementById('bltFile').files[0];
	let text = await bltFile.text();
	
	// Initialise table rows
	let tblResults = document.getElementById('result');
	tblResults.innerHTML = '';
	let candMap = {}; // candidate name -> rows
	
	// Step election
	let worker = new Worker('worker.js');
	let election, elComment, elExhausted1, elExhausted2, elLTF1, elLTF2, elTotal, elQuota;
	
	worker.onmessage = function(evt) {
		if (evt.data.type === 'require_input') {
			let input = window.prompt(evt.data.message);
			if (input !== null) {
				worker.postMessage({'type': 'require_input', 'input': input});
			}
		}
		
		if (evt.data.type === 'init') {
			election = evt.data.election;
			
			// Comment row
			elComment = document.createElement('tr');
			let elTd = document.createElement('td');
			elComment.appendChild(elTd);
			tblResults.appendChild(elComment);
			
			// Candidates
			for (let candidate of election.candidates) {
				let elTr1 = document.createElement('tr');
				let elTr2 = document.createElement('tr');
				
				elTd = document.createElement('td');
				elTd.setAttribute('rowspan', '2');
				elTd.style.borderTop = '1px solid black';
				elTd.innerText = candidate;
				elTr1.appendChild(elTd);
				
				tblResults.appendChild(elTr1);
				tblResults.appendChild(elTr2);
				
				candMap[candidate] = [elTr1, elTr2];
			}
			
			// Exhausted votes row
			elExhausted1 = document.createElement('tr');
			elExhausted1.classList.add('info');
			elExhausted2 = document.createElement('tr');
			elExhausted2.classList.add('info');
			
			elTd = document.createElement('td');
			elTd.setAttribute('rowspan', '2');
			elTd.style.borderTop = '1px solid black';
			elTd.innerText = 'Exhausted';
			elExhausted1.appendChild(elTd);
			
			tblResults.appendChild(elExhausted1);
			tblResults.appendChild(elExhausted2);
			
			// Loss to fraction row
			elLTF1 = document.createElement('tr');
			elLTF1.classList.add('info');
			elLTF2 = document.createElement('tr');
			elLTF2.classList.add('info');
			
			elTd = document.createElement('td');
			elTd.setAttribute('rowspan', '2');
			elTd.style.borderTop = '1px solid black';
			elTd.innerText = 'Loss to fraction';
			elLTF1.appendChild(elTd);
			
			tblResults.appendChild(elLTF1);
			tblResults.appendChild(elLTF2);
			
			// Total row
			elTotal = document.createElement('tr');
			elTotal.classList.add('info');
			elTd = document.createElement('td');
			elTd.style.borderTop = '1px solid black';
			elTd.innerText = 'Total';
			elTotal.appendChild(elTd);
			tblResults.appendChild(elTotal);
			
			// Quota row
			elQuota = document.createElement('tr');
			elQuota.classList.add('info');
			elTd = document.createElement('td');
			elTd.style.borderTop = '1px solid black';
			elTd.style.borderBottom = '1px solid black';
			elTd.innerText = 'Quota';
			elQuota.appendChild(elTd);
			tblResults.appendChild(elQuota);
		}
		
		if (evt.data.type === 'result') {
			let result = evt.data.result;
			
			// Display results
			elTd = document.createElement('td');
			elTd.innerText = result.comment;
			elComment.appendChild(elTd);
			
			for (let [candidate, countCard] of result.candidates) {
				[elTr1, elTr2] = candMap[candidate];
				
				elTd = document.createElement('td');
				elTd.classList.add('count');
				if (countCard.state === py.pyRCV2.model.CandidateState.WITHDRAWN || countCard.state === py.pyRCV2.model.CandidateState.EXCLUDED || countCard.state === py.pyRCV2.model.CandidateState.EXCLUDING) {
					elTd.classList.add('excluded');
				} else if (countCard.state === py.pyRCV2.model.CandidateState.ELECTED || countCard.state === py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED || countCard.state === py.pyRCV2.model.CandidateState.DISTRIBUTING_SURPLUS) {
					elTd.classList.add('elected');
				}
				elTd.style.borderTop = '1px solid black';
				if (countCard.transfers != '0.00' && countCard.transfers != '0') {
					elTd.innerText = countCard.transfers;
				} else {
					elTd.innerHTML = '&nbsp;';
				}
				elTr1.appendChild(elTd);
				
				elTd = document.createElement('td');
				elTd.classList.add('count');
				
				if (countCard.state === py.pyRCV2.model.CandidateState.ELECTED || countCard.state === py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED || countCard.state === py.pyRCV2.model.CandidateState.DISTRIBUTING_SURPLUS) {
					elTd.classList.add('elected');
					elTd.innerText = countCard.votes;
					elTr1.querySelector('td:first-child').classList.add('elected');
				} else {
					elTr1.querySelector('td:first-child').classList.remove('elected');
					
					if (countCard.state === py.pyRCV2.model.CandidateState.WITHDRAWN) {
						elTd.classList.add('excluded');
						elTd.innerText = 'WD';
					} else if (countCard.state === py.pyRCV2.model.CandidateState.EXCLUDED) {
						elTd.classList.add('excluded');
						elTd.innerText = 'Ex';
					} else if (countCard.state === py.pyRCV2.model.CandidateState.EXCLUDING) {
						elTd.classList.add('excluded');
						elTd.innerText = countCard.votes;
					} else {
						elTd.innerText = countCard.votes;
					}
				}
				
				elTr2.appendChild(elTd);
			}
			
			// Display exhausted votes
			elTd = document.createElement('td');
			elTd.classList.add('count');
			elTd.style.borderTop = '1px solid black';
			if (result.exhausted.transfers != '0.00' && result.exhausted.transfers != '0') {
				elTd.innerText = result.exhausted.transfers;
			} else {
				elTd.innerHTML = '&nbsp;';
			}
			elExhausted1.appendChild(elTd);
			
			elTd = document.createElement('td');
			elTd.classList.add('count');
			elTd.innerText = result.exhausted.votes;
			elExhausted2.appendChild(elTd);
			
			// Display loss to fraction
			elTd = document.createElement('td');
			elTd.classList.add('count');
			elTd.style.borderTop = '1px solid black';
			if (result.loss_fraction.transfers != '0.00' && result.loss_fraction.transfers != '-0.00' && result.loss_fraction.transfers != '0') {
				elTd.innerText = result.loss_fraction.transfers;
			} else {
				elTd.innerHTML = '&nbsp;';
			}
			elLTF1.appendChild(elTd);
			
			elTd = document.createElement('td');
			elTd.classList.add('count');
			if (result.loss_fraction.votes == '-0.00') {
				elTd.innerText = '0.00';
			} else {
				elTd.innerText = result.loss_fraction.votes;
			}
			elLTF2.appendChild(elTd);
			
			// Display total
			elTd = document.createElement('td');
			elTd.classList.add('count');
			elTd.style.borderTop = '1px solid black';
			elTd.innerText = result.total;
			elTotal.appendChild(elTd);
			
			// Display quota
			elTd = document.createElement('td');
			elTd.classList.add('count');
			elTd.style.borderTop = '1px solid black';
			elTd.style.borderBottom = '1px solid black';
			elTd.innerText = result.quota;
			elQuota.appendChild(elTd);
		}
	}
	
	worker.onerror = function(evt) {
		window.alert('An unknown error occurred while counting the votes. More details may be available in the browser\'s developer console.');
		throw evt;
	}
	
	worker.postMessage({
		'type': 'init',
		'data': {
			'numbers': document.getElementById('selNumbers').value,
			'fixedDPs': parseInt(document.getElementById('txtDP').value),
			'transfers': document.getElementById('selTransfers').value,
			'options': {
				'quota_criterion': document.getElementById('selQuotaCriterion').value,
				'quota': document.getElementById('selQuota').value,
				'prog_quota': document.getElementById('chkProgQuota').checked,
				'bulk_elect': document.getElementById('chkBulkElection').checked,
				'bulk_exclude': document.getElementById('chkBulkExclusion').checked,
				'surplus_order': document.getElementById('selSurplus').value,
				'papers': document.getElementById('selPapers').value,
				'exclusion': document.getElementById('selExclusion').value,
				'ties': document.getElementById('selTies').value
			},
			'seed': document.getElementById('txtSeed').value,
			'data': text
		}
	});
}

// Provide a default seed
if (document.getElementById('txtSeed').value === '') {
	function pad(x) { if (x < 10) { return '0' + x; } return '' + x; }
	let d = new Date();
	document.getElementById('txtSeed').value = d.getFullYear() + pad(d.getMonth() + 1) + pad(d.getDate());
}
