importScripts('opentally.js');

var wasm = wasm_bindgen;

async function initWasm() {
	await wasm_bindgen('opentally_bg.wasm');
	postMessage({'type': 'init', 'version': wasm.version()});
}
initWasm();

var numbers, election, opts, state, stageNum;

onmessage = function(evt) {
	if (evt.data.type === 'countElection') {
		if (evt.data.numbers === 'fixed') {
			numbers = 'Fixed';
			wasm.fixed_set_dps(evt.data.decimals);
		} else if (evt.data.numbers === 'gfixed') {
			numbers = 'GuardedFixed';
			wasm.gfixed_set_dps(evt.data.decimals);
		} else if (evt.data.numbers === 'float64') {
			numbers = 'NativeFloat64';
		} else if (evt.data.numbers === 'rational') {
			numbers = 'Rational';
		} else {
			throw 'Unknown --numbers';
		}
		
		// Init election
		election = wasm['election_from_blt_' + numbers](evt.data.bltData);
		
		if (evt.data.normaliseBallots) {
			wasm['election_normalise_ballots_' + numbers](election);
		}
		
		// Init constraints if applicable
		if (evt.data.conData) {
			wasm['election_load_constraints_' + numbers](election, evt.data.conData);
		}
		
		// Init STV options
		opts = wasm.STVOptions.new.apply(null, evt.data.optsStr);
		
		// Validate options
		opts.validate();
		
		// Describe count
		postMessage({'type': 'describeCount', 'content': wasm['describe_count_' + numbers](evt.data.bltPath, election, opts)});
		
		// Init results table
		postMessage({'type': 'initResultsTable', 'content': wasm['init_results_table_' + numbers](election, opts)});
		
		// Step election
		state = wasm['CountState' + numbers].new(election);
		wasm['count_init_' + numbers](state, opts);
		
		postMessage({'type': 'updateResultsTable', 'result': wasm['update_results_table_' + numbers](1, state, opts)});
		postMessage({'type': 'updateStageComments', 'comment': wasm['update_stage_comments_' + numbers](state)});
		
		stageNum = 2;
		
		resume_count();
		
	} else if (evt.data.type == 'userInput') {
		user_input_buffer = evt.data.response;
		resume_count();
	}
}

function resume_count() {
	for (;; stageNum++) {
		try {
			let isDone = wasm['count_one_stage_' + numbers](state, opts);
			if (isDone) {
				break;
			}
		} catch (ex) {
			if (ex === "RequireInput") {
				return;
			} else {
				throw ex;
			}
		}
		
		postMessage({'type': 'updateResultsTable', 'result': wasm['update_results_table_' + numbers](stageNum, state, opts)});
		postMessage({'type': 'updateStageComments', 'comment': wasm['update_stage_comments_' + numbers](state)});
	}
	
	postMessage({'type': 'updateResultsTable', 'result': wasm['finalise_results_table_' + numbers](state)});
	postMessage({'type': 'finalResultSummary', 'summary': wasm['final_result_summary_' + numbers](state, opts)});
}

var user_input_buffer = null;

function read_user_input_buffer(message) {
	if (user_input_buffer === null) {
		postMessage({'type': 'requireInput', 'message': message});
		return null;
	} else {
		let user_input = user_input_buffer;
		user_input_buffer = null;
		return user_input;
	}
}
