var max = 0;
var playing = false;
var array = Array();
var aantal = 20;
var stap = 0;
var huidige_current = -1;
var huidige_active = -1;
var huidige_selected = -1;
var array_sorted = Array();
var timed = false;
// stappen[0] = huidige_current
// stappen[1] = huidige_active
// stappen[2] = info
// stappen[3] = next[]
// stappen[4] = array_sorted[]
// stappen[5] = huidige_selected
var stappen = Array(Array(), Array(), Array(), Array(), Array(), Array());

function WritePlayer() {
	document.write('<input type="button" value="Play" id="PlayButton" onClick="toggle_play();"> - <input type="button" value="Terug naar begin" onClick="pauze(); rewind();"> - <input type="button" value="Vorige Stap..." onClick="pauze(); prev();"> - <input type="button" value="Volgende Stap..." onClick="pauze(); next();"> - <input type="checkbox" id="herhalen"> <label for="herhalen">Herhalen</label> - Snelheid: <input type="text" value="200" id="snelheid" size="1"><div id="sorteer_div">Laden...</div><div><b>Invoergetallen (kommagescheiden): <input type="text" id="input" value=""><input type="button" value="Verander!" onClick="GetInput();"><br />Gesorteerde getallen (kommagescheiden): <input type="text" id="output" value=""></b></div><br /><i>Genereer automatisch: <select id="array_type"><option value="random">Random (willekeurig)</option><option value="sorted">Helemaal goed gesorteerd</option><option value="unsorted">Precies omgekeerd gesorteerd</option><option value="near">Bijna gesorteerd</option><option value="same">Een aantal dezelfde waardes</option></select></i>; Aantal waardes: <input type="text" id="aantal" value="20" size="1" /><input type="button" onClick="auto();" value="Genereer!" />');
}

function rewind(start) {
	stappen = Array(Array(), Array(), Array(), Array(), Array(), Array());
	stap = 0;
	if (huidige_current != -1) { SetCurrent(huidige_current, false); }
	if (huidige_selected != -1) { SetSelected(huidige_selected, false); }
	if (huidige_active != -1) { SetActive(huidige_active, false); }
	huidige_current = -1;
	huidige_selected = -1;
	huidige_active = -1;
	if (start != false) {
		next();
	}
}

function toggle_play() {
	if (playing == false) {
		play();
	} else {
		pauze();
	}
}

function play() {
	var element = GetPlayButton();
	element.value = 'Pauze';
	
	playing = true;
	next();
}

function SetSorted() {
	var i = 0;
	for (i = 0; i < array.length; i++) {
		array_sorted[i] = array[i];
	}
}

function next() {
	if (timed == true && playing == false) { timed = false; return false; }
	if (stap == 0) {
		SetSorted();
		MakeBalken();
		SetOutput();
	}
	unswap();
	switch (algoritme) {
		case 'selection sort':
			selection_sort_next();
			break;
		case 'bubble sort':
			bubble_sort_next();
			break;
		case 'bubble sort 2':
			bubble_sort_2_next();
			break;
		case 'quick sort':
			quick_sort_next();
			break;
		default:
			alert('Geen animatie beschikbaar voor dat algoritme');
			break;
	}
	if (playing == true) {
		timed = true;
		if (herhalen() == false && snelheid() == 0) {
			next();
		} else {
			setTimeout("next();", snelheid());
		}
	}
}

function prev() {
	if (stap > 1) {
		stap--;
		UpdateStap();
		var tmp = Array();
		tmp = stappen.pop();
		ChangeCurrent(tmp[0]);
		ChangeActive(tmp[1]);
		SetInfo(tmp[2]);
		array_sorted = tmp[4];
		SetOutput();
		ChangeSelected(tmp[5]);
	}
}

// Aantal stappen: 0.5 * n^2 + 0.5 * n
function selection_sort_next() {
	var info = '';
	var waarde = 0;
	var next = Array();
	var searching = 0;
	stap++;
	UpdateStap();
	if (stap == 1) {
		waarde = array_sorted[0];
		info = 'Allereerst kijken we wat er als eerste (op plek 1) moet komen. Daarvoor moeten we de hele lijst langs, en kijken we telkens of de waarde kleiner is dan de kleinste tot nog toe gevonden. Nu is de kleinste tot nog toe gevonden gewoon de waarde van de bovenste (' + waarde + ')';
		ChangeCurrent(0);
		next[0] = 'find smallest';	// Actie
		next[1] = 0;				// Kleinste Key
		next[2] = waarde;			// Kleinste Waarde
		next[3] = 0;				// De zojuist gecheckte key
		next[4] = 0;				// De key waar hij in moet
		stappen[3].push(next);
	} else {
		next = stappen[3].pop();
		stappen[3].push(next);
		switch (next[0]) {
			case 'find smallest':
				ChangeActive(next[1]);
				ChangeCurrent(next[4]);
				searching = next[3];
				searching++;
				ChangeActive(searching);
				info = 'Nu gaan we de hele lijst langs, en kijken we of het volgende element (plek ' + (searching + 1).toString() + ') kleiner is dan de kleinste tot nog toe gevonden waarde. ';
				if (array_sorted[searching] < next[2]) {
					info += 'Dat blijkt het geval te zijn (want ' + array_sorted[searching] + ' is kleiner dan ' + next[2] + '), dus veranderen we de kleinste tot nog toe gevonden waarde in de nieuwe waarde (' + array_sorted[searching] + ').'
					next[1] = searching;
					next[2] = array_sorted[searching];
					ChangeSelected(searching);
				} else {
					info += 'Dat blijkt niet het geval te zijn (want ' + array_sorted[searching] + ' is niet kleiner dan ' + next[2] + ').'
				}
				next[3] = searching;
				if (searching == aantal - 1) { next[0] = 'place smallest'; }
				stappen[3].push(next);
				break;
			case 'place smallest':
				if (next[1] != next[4]) {
					info = 'We hebben nu de kleinste waarde gevonden, nu wisselen we die voor de huidige waarde.';
				} else {
					info = 'Dit element is al goed gesorteerd, en hoeven we niet te veranderen.';
				}
				swap(next[4], next[1]);
				if (next[4] == aantal - 2) {
					info += ' Nu is de lijst volledig gesorteerd.';
					if (herhalen() != true) {
						pauze();
					}
					SetInfo(info);
					rewind(false);
				} else {
					next[0] = 'find smallest';			// Actie
					next[1] = ++next[4];				// Kleinste Key
					next[2] = array_sorted[next[4]];	// Kleinste Waarde
					next[3] = next[4];					// De zojuist gecheckte key
					next[4] = next[4];					// De key waar hij in moet
				}
				stappen[3].push(next);
				ChangeActive(-1);
				break;
		}
	}
	stappen[0].push(huidige_current);
	stappen[1].push(huidige_active);
	stappen[2].push(info);
	stappen[4].push(array_sorted);
	stappen[5].push(huidige_selected);
	SetInfo(info);
}

function quick_sort_next() {
	stap++;
	UpdateStap();
	if (stap == 1) {
		next[0] = 'pivot';			// Actie
		next[1] = 0;				// Pivot
		next[2] = 0;				// Pivot die we hierna moeten kiezen
		next[3] = 0;				// Waarde van pivot
		next[4] = 0;				// Waarde die we moeten checken voor kleiner / groter dan de pivot
		next[5] = 0;				// Minimale key
		next[6] = aantal - 1;		// Maximale key
	}
	switch (next[0]) {
		case 'pivot': // Kies een pivot
			info = 'Nu kiezen we een <i>pivot</i>. We nemen gewoon de eerste waarde van de te sorteren lijst.';
			next[1] = next[2];
			next[3] = array_sorted[next[1]];
			next[0] = 'swap';
			next[4] = next[5];
			ChangeSelected(next[1]);
			break;
		case 'swap':
			next[4]++;
			info = 'We gaan nu de hele lijst langs die we moeten sorteren, en contoleren of hij groter of kleiner dan de pivot is. Nu controleren we element ' + next[4] + '.';
			if (next[4] == next[6]) {
				
			}
			break;
	}
	SetInfo(info);
}

function bubble_sort_next() {
	stap++;
	UpdateStap();
	var info = '';
	var next = Array();
	if (stap == 1) {
		next[0] = 'check_bigger';	// Actie
		next[1] = 0;				// Welke gecontroleerd moet worden
		next[2] = 0;				// Veranderd
		info = '';
		stappen[3].push(next);
	} else {
		next = stappen[3].pop();
		stappen[3].push(next);
	}
	switch (next[0]) {
		case 'check_bigger':
			ChangeCurrent(next[1] + 1);
			ChangeActive(next[1]);
			info = 'Nu controleren we of het huidige element (Plek ' + next[1] + ', waarde: ' + array_sorted[next[1]] + ') groter is dan het volgende element (Plek ' + (next[1] + 1).toString() + ', waarde: ' + array_sorted[next[1] + 1] + '). ';
			if (array_sorted[next[1]] > array_sorted[next[1] + 1]) {
				info += 'Dit blijkt het geval te zijn, dus zijn die 2 elementen niet goed gesorteerd. Nu wisselen we die 2 elementen om, zodat ze wel goed gesorteerd zijn. We stellen een variabele \'veranderd\' in, zodat we weten dat de lijst veranderd is. Nu gaan we het volgende element controleren.';
				swap(next[1], next[1] + 1);
				next[2] = 1;
			} else {
				info += 'Dit blijkt niet het geval te zijn, dus zijn die 2 elementen al goed gesorteerd. We hoeven er niets meer aan te doen, en gaan nu het volgende element controleren.';
			}
			next[1]++;
			if (next[1] == aantal - 1) {
				next[0] = 'check_veranderd';
				next[1] = 0;
			}
			break;
		case 'check_veranderd':
			ChangeActive(-1);
			ChangeCurrent(-1);
			info = 'Nu zijn we de hele lijst langsgeweest om elementen beter te sorteren. Nu kijken we of er nog iets veranderd was. ';
			if (next[2] == 1) {
				info += 'Er is inderdaad iets veranderd, dus nu moeten we nog een keer de lijst doorlopen.';
				next[2] = 0;
				next[0] = 'check_bigger';
			} else {
				info += 'Er is niets veranderd, dat betekend dat de lijst nu helemaal goed is gesorteerd.';
				if (herhalen() != true) {
					pauze();
				}
				SetInfo(info);
				rewind(false);
			}
			break;
	}
	stappen[3].push(next);
	stappen[0].push(huidige_current);
	stappen[1].push(huidige_active);
	stappen[2].push(info);
	stappen[4].push(array_sorted);
	stappen[5].push(huidige_selected);
	SetInfo(info);
}

function bubble_sort_2_next() {
	stap++;
	UpdateStap();
	var info = '';
	var next = Array();
	if (stap == 1) {
		next[0] = 'check_bigger';	// Actie
		next[1] = 0;				// Welke gecontroleerd moet worden
		next[2] = 0;				// Veranderd
		next[3] = '';				// Vorige Next[0]
		next[4] = 0;				// Minimale waarde
		next[5] = aantal - 1;		// Maximale waarde
		next[6] = true;				// Eerste keer
		next[7] = -1;				// Toekomstige uiterste waarde
		info = '';
		stappen[3].push(next);
	} else {
		next = stappen[3].pop();
		stappen[3].push(next);
	}
	switch (next[0]) {
		case 'check_smaller':
			ChangeCurrent(next[1] - 1);
			ChangeActive(next[1]);
			next[1]--;
		case 'check_bigger':
			if (next[0] == 'check_bigger') {
				ChangeCurrent(next[1] + 1);
				ChangeActive(next[1]);
				var next_1_oud = next[1];
				next[1]++;
			} else {
				var next_1_oud = next[1] + 1;
			}
			info = 'Nu controleren we of het huidige element (Plek ' + next[1] + ', waarde: ' + array_sorted[next[1]] + ') groter is dan het volgende element (Plek ' + (next[1] + 1).toString() + ', waarde: ' + array_sorted[next[1] + 1] + '). ';
			if ((array_sorted[next_1_oud] > array_sorted[next[1]] && next[0] == 'check_bigger') || (array_sorted[next_1_oud] < array_sorted[next[1]] && next[0] == 'check_smaller')) {
				info += 'Dit blijkt het geval te zijn, dus zijn die 2 elementen niet goed gesorteerd. Nu wisselen we die 2 elementen om, zodat ze wel goed gesorteerd zijn. We stellen een variabele \'veranderd\' in, zodat we weten dat de lijst veranderd is. Nu gaan we het volgende element controleren.';
				swap(next[1], next_1_oud);
				next[2] = 1;
				if (next[0] == 'check_bigger') {
					/* if (next[6] == true) {
						next[6] = false;
						if (next[1] > next[4]) { next[4] = next[1]; }
					} */
					next[7] = next[1];
					// next[6] = false;
					// next[5] = next[1];
					// SetInactive(next[4]);
				} else {
					/* if (next[6] == true) {
						next[6] = false;
						if (next[1] < next[5]) { next[5] = next[1]; }
					} */
					next[7] = next[1];
					// next[4] = next[1];
					// SetInactive(next[5]);
				}
			} else {
				info += 'Dit blijkt niet het geval te zijn, dus zijn die 2 elementen al goed gesorteerd. We hoeven er niets meer aan te doen, en gaan nu het volgende element controleren.';
			}
			if (((next[1] == next[5] || next[1] == aantal - 1) && next[0] == 'check_bigger') || ((next[1] == next[4] || next[1] == 0) && next[0] == 'check_smaller')) {
				next[3] = next[0];
				next[0] = 'check_veranderd';
				next[6] = true;
				if (next[3] == 'check_bigger') {
					if (next[7] != -1) {
						next[5] = next[7];
					}
					next[1] = next[5] - 1;
				} else {
					if (next[7] != -1) {
						next[4] = next[7];
					}
					next[1] = next[4] + 1;
				}
				next[7] = -1;
			}
			break;
		case 'check_veranderd':
			ChangeActive(-1);
			ChangeCurrent(-1);
			info = 'Nu zijn we de hele lijst langsgeweest om elementen beter te sorteren. Nu kijken we of er nog iets veranderd was. ';
			if (next[2] == 1) {
				info += 'Er is inderdaad iets veranderd, dus nu moeten we nog een keer de lijst doorlopen.';
				next[2] = 0;
				if (next[3] == 'check_smaller') {
					next[0] = 'check_bigger';
				} else {
					next[0] = 'check_smaller';
				}
			} else {
				info += 'Er is niets veranderd, dat betekend dat de lijst nu helemaal goed is gesorteerd.';
				if (herhalen() != true) {
					pauze();
				}
				SetInfo(info);
				rewind(false);
			}
			break;
	}
	stappen[3].push(next);
	stappen[0].push(huidige_current);
	stappen[1].push(huidige_active);
	stappen[2].push(info);
	stappen[4].push(array_sorted);
	stappen[5].push(huidige_selected);
	SetInfo(info);
}

function SetInactive(nr) {
	var element = document.getElementById('balk_' + nr);
	element.style.border = "1px dotted #3D6AAA";
	element.style.backgroundColor = "#CDEFF5";
}

function SetInfo(info) {
	document.getElementById('info').innerHTML = info;
}

function UpdateStap() {
	document.getElementById('stap').innerHTML = stap.toString();
}

function snelheid() {
	return document.getElementById('snelheid').value;
}

function herhalen() {
	return document.getElementById('herhalen').checked;
}

function GetCurrent() {
	var i = 0;
	var array = Array();
	for (i = 0; i < aantal; i++) {
		array[i] = (document.getElementById('current_' + i).style.display == 'inline');
	}
	return array;
}

function GetActive() {
	var i = 0;
	var array = Array();
	for (i = 0; i < aantal; i++) {
		array[i] = (document.getElementById('active_' + i).style.display == 'inline');
	}
	return array;
}

function pauze() {
	var element = GetPlayButton();
	element.value = 'Play';
	
	playing = false;
}

function GenerateRandom(aantal) {
	var array = Array();
	array = GenerateSorted(aantal);
	shuffle(array);
	return array;
}

function GenerateSorted(aantal) {
	var array = Array();
	var i = 0;
	for (i = 1; i <= aantal; i++) {
		array.push(i);
	}
	return array;
}

function GenerateUnsorted(aantal) {
	var array = Array();
	var i = 0;
	for (i = aantal; i >= 1; i--) {
		array.push(i);
	}
	return array;
}

function GenerateSame(aantal) {
	var array = Array();
	var i = 0;
	var val = 1;
	for (i = 1; i <= aantal; i++) {
		if (Math.random() > 0.75) { val++; }
		array.push(val);
	}
	shuffle(array);
	return array;
}

function GenerateNearSorted(aantal) {
	var array = Array();
	var i = 0;
	for (i = 1; i <= aantal; i++) {
		array.push(i);
	}
	var tmp = 0;
	for (i = 0; i < aantal - 1; i++) {
		if (array[i] < array[i + 1] && array[i] > array[i - 1] && Math.random() > 0.25) {
			tmp = array[i];
			array[i] = array[i + 1];
			array[i + 1] = tmp;
		}
	}
	return array;
}

function shuffle( array ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // *     example 1: shuffle(['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: true
 
    for(var j, x, i = array.length; i; j = parseInt(Math.random() * i), x = array[--i], array[i] = array[j], array[j] = x);
    return true;
}

function MakeBalken() {
	var element = document.getElementById('sorteer_div');
	var i = 0;
	var inhoud = '';
	var waarde = 0;
	inhoud = '<div id="swap2"><img id="swap2_img" src="swap2.png" /></div><div id="swap3"><img id="swap3_img" src="swap3.png" /></div><div id="swap4"><img id="swap4_img" src="swap4.png" /></div><div id="swap"><img src="swap_top.png" /><br /><img src="swap.png" id="swap_midden" /><br /><img src="swap_bottom.png" id="swap_bottom" /></div>';
	max = 0;
	for (i = 0; i < aantal; i++) {
		if (array[i] > max) { max = array[i]; }
	}
	for (i = 0; i < aantal; i++) {
		waarde = array[i];
		inhoud += '<div id="balk_img_' + i + '" class="balk_voor"><img src="js_sorting_current.png" id="current_' + i + '" /><img src="js_sorting_active.png" id="active_' + i + '" /><img src="js_sorting_selected.png" id="selected_' + i + '" /></div>';
		inhoud += '<div id="balk_' + i + '" class="balk" style="width: ' + ((waarde / max) * 100).toString() + '%;" title="' + waarde + '"></div>';
	}
	inhoud += 'Stap: <span id="stap">0</span>. <i>Uitleg:</i><div id="info_container"><span id="info"><i><font color="#CDEFF5">(nog geen uitleg beschikbaar, druk op Volgende Stap om uitleg te krijgen)</font></i></span><span id="dummy_info">Stap: 1 - Allereerst kijken we wat er als eerste (op plek 1) moet komen. Daarvoor moeten we de hele lijst langs, en kijken we telkens of de waarde kleiner is dan de kleinste tot nog toe gevonden. Nu is de kleinste tot nog toe gevonden gewoon de waarde van de bovenste (x)</span></div>';
	element.innerHTML = inhoud;
}

function GetPlayButton() {
	return document.getElementById('PlayButton');
}

function SetCurrent(nr, value, no_clear_color) {
	if (nr == -1) { return false; }
	var val = '';
	var kleur = '';
	if (value == true) { val = 'inline'; kleur = '#40C0FF'; } else { val = 'none'; kleur = '#DFFFFF' }
	document.getElementById('current_' + nr).style.display = val;
	if (no_clear_color != true) { document.getElementById('balk_' + nr).style.backgroundColor = kleur; }
}

function ChangeCurrent(nr) {
	if (huidige_current != -1) {
		SetCurrent(huidige_current, false);
	}
	huidige_current = nr;
	if (nr != -1) { SetCurrent(nr, true); }
}

function SetActive(nr, value, no_clear_color) {
	if (nr == -1) { return false; }
	var val = '';
	var kleur = '';
	if (value == true) { val = 'inline'; kleur = '#FF8000'; } else { val = 'none'; kleur = '#DFFFFF' }
	document.getElementById('active_' + nr).style.display = val;
	if (huidige_active != huidige_selected && no_clear_color != true) { document.getElementById('balk_' + nr).style.backgroundColor = kleur; }
}

function ChangeActive(nr) {
	if (huidige_active != -1) {
		SetActive(huidige_active, false);
	}
	huidige_active = nr;
	if (nr != -1) { SetActive(nr, true); }
}

function SetSelected(nr, value, no_clear_color) {
	if (nr == -1) { return false; }
	var val = '';
	var kleur = '';
	if (value == true) { val = 'inline'; kleur = '#8040C0'; } else { val = 'none'; kleur = '#DFFFFF' }
	document.getElementById('selected_' + nr).style.display = val;
	if (no_clear_color != true) { document.getElementById('balk_' + nr).style.backgroundColor = kleur; }
}

function ChangeSelected(nr) {
	if (huidige_selected != -1) {
		SetSelected(huidige_selected, false);
	}
	huidige_selected = nr;
	if (nr != -1) { SetSelected(nr, true); }
}

function swap(nr1, nr2) {
	if (nr1 == -1) {
		element.style.display = 'none';
		return false;
	}
	var waarde = 0;
	waarde = array_sorted[nr2];
	document.getElementById('balk_' + nr1).style.width = ((waarde / max) * 100).toString() + '%';
	document.getElementById('balk_' + nr1).title = nr2;
	waarde = array_sorted[nr1];
	document.getElementById('balk_' + nr2).style.width = ((waarde / max) * 100).toString() + '%';
	document.getElementById('balk_' + nr2).title = nr1;
	var tmp = 0;
	tmp = array_sorted[nr1];
	array_sorted[nr1] = array_sorted[nr2];
	array_sorted[nr2] = tmp;
	verschil = nr1 - nr2;
	var laagste = nr2;
	var hoogste = nr1;
	if (verschil < 0) {
		verschil = -verschil;
		hoogste = nr2;
		laagste = nr1;
	}
	switch (verschil) {
		case 0:
			break;
		case 1:
			var element = document.getElementById('swap2_img');
			element.style.top = (laagste * 10).toString() +  'px';
			document.getElementById('swap2').style.display = 'block';
			break;
		case 2:
			var element = document.getElementById('swap3_img');
			element.style.top = (laagste * 10 - 2).toString() +  'px';
			document.getElementById('swap3').style.display = 'block';
			break;
		case 3:
			var element = document.getElementById('swap4_img');
			element.style.top = (laagste * 10 - 2).toString() +  'px';
			document.getElementById('swap4').style.display = 'block';
			break;
		default:
			var element = document.getElementById('swap');
			element.style.display = 'block';
			element.style.top = (laagste * 10 - 3).toString() +  'px';
			element = document.getElementById('swap_midden');
			element.style.height = (10 * verschil - 16).toString() + 'px';
	}
	SetActive(huidige_active, false, true);
	SetCurrent(huidige_current, false, true);
	SetSelected(huidige_selected, false, true);
	SetOutput();
}

function unswap() {
	SetActive(huidige_active, true);
	SetCurrent(huidige_current, true);
	SetSelected(huidige_selected, true);
	document.getElementById('swap2').style.display = 'none';
	document.getElementById('swap3').style.display = 'none';
	document.getElementById('swap4').style.display = 'none';
	document.getElementById('swap').style.display = 'none';
}

function GetInput() {
	rewind(false);
	array = document.getElementById('input').value.split(',');
	aantal = array.length;
	var i = 0;
	for (i = 0; i < aantal; i++) {
		array[i] = array[i] * 1;
	}
	rewind(true);
	SetOutput();
}

function SetOutput() {
	document.getElementById('input').value = array.toString();
	document.getElementById('output').value = array_sorted.toString();
}

function auto() {
	rewind(false);
	aantal = document.getElementById('aantal').value * 1;
	switch (document.getElementById('array_type').value) {
		case 'random':
			array = GenerateRandom(aantal);
			break;
		case 'sorted':
			array = GenerateSorted(aantal);
			break;
		case 'unsorted':
			array = GenerateUnsorted(aantal);
			break;
		case 'near':
			array = GenerateNearSorted(aantal);
			break;
		case 'same':
			array = GenerateSame(aantal);
			break;
	}
	rewind(true);
	SetSorted();
	MakeBalken();
	SetOutput();
}

array = GenerateRandom(aantal);
WritePlayer();
MakeBalken();