function SudokuClear () {
	if (this.className=='hint') this.className = null;
	for (var digit=1; 9>=digit; digit++) {
		if (this.buttons[digit].className=='hint')
			this.buttons[digit].className=null;
	}
	if (!this.value) return;
	this.board.filled--;
	for (var i=0; this.board.fields.length>i; i++) {
		var f = this.board.fields[i];
		if (f.col!=this.col && f.row!=this.row && f.blk!=this.blk || f==this)
			continue;
		b=f.buttons[this.value];
		if (--b.block) continue;
		b.className=null;
		if (!f.choices++) f.className=null;
	}
	this.buttons[this.value].className=null;
	this.className=null;
	this.value=0;
}

function SudokuSet (value, class) {
	this.Clear();
	if (!value) return;
	this.value=value;
	this.board.filled++;
	this.buttons[this.value].className=class ? class : 'sel';
	this.className='sel';
	for (var i=0; this.board.fields.length>i; i++) {
		var f = this.board.fields[i];
		if (f.col!=this.col && f.row!=this.row && f.blk!=this.blk || f==this)
			continue;
		var b=f.buttons[this.value];
		if (b.block++) continue;
		b.className='ko';
		if (!--f.choices) f.className="ko";
	}
}

function SudokuClick () {
	var field = this.parentNode;
	var value = this.digit;
	var board = field.board;
	if (field.buttons[value].block) {
		return;
	}
	if (board.Mode==1) {
		if (field.value != value) {
			field.fixed = value;
			field.Set (value, 'fix');
		} else {
			field.fixed = 0;
			field.Clear();
		}
		return;
	}
	if (board.Mode==2 && !field.fixed) {
		if (field.value != value) {
			field.Set (value, 'sel');
			if (field.board.filled==81) {
				var secs = Math.round ((new Date().getTime()-field.board.startTime) / 1000);
				var mins = Math.floor (secs/60);
				secs -= mins * 60;
				var used = secs==1 ? "1 Sekunde" : secs+" Sekunden";
				if (mins==1) used = mins+" Minute und "+used;
				if (mins>=2) used = mins+" Minuten und "+used;
				alert ("Sie haben das Sudoku in "+used+" gelöst.");
				board.Mode=3;
			}
		} else {
			field.Clear();
		}
		return;
	}
}

function SudokuErase () {
	for (var i=0; this.fields.length>i; i++) {
		field = this.fields[i];
		field.fixed = 0;
		field.Clear();
	}
	this.className = "sudoku setup";
	this.Mode = 1;
}

function SudokuSetup () {
	for (var i=0; this.fields.length>i; i++) {
		var field = this.fields[i];
		field.Set (field.fixed, 'fix');
	}
	this.className = "sudoku setup";
	this.Mode = 1;
}

function SudokuReset (level) {
	for (var i=0; this.fields.length>i; i++) {
		var field = this.fields[i];
		field.className=null;
		field.Set (field.fixed, 'fix');
	}
	this.startTime = new Date().getTime();
	this.className = "sudoku";
	this.Mode      = 2;
	this.stack.length = 0;
}

function SudokuPreset (code) {
	var match = code.match (/(\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d)/);
	if (!match) return false;
	for (var i=0; this.fields.length>i; i++) {
		var field = this.fields[i];
		field.fixed = parseInt (match[1].substr(i,1));
		field.Set(field.fixed, 'fix');
	}
	this.Reset();
	return true;
}

function SudokuEnter () {
	code = prompt ("Neues Sudoku (81 Ziffern):")
	if (code) this.Preset (code);
}

function SudokuPush () {
	if (this.Mode != 2) return;
	state = new Array ();
	for (var i=0; this.fields.length>i; i++) {
		state.push (this.fields[i].value);
	}
	this.stack.push(state);
}

function SudokuPop () {
	if (this.Mode != 2) return;
	state = this.stack.pop();
	if (!state) {
		alert ("Kein Zustand gespeichert");
		return false;
	}
	for (var i=0; this.fields.length>i; i++) {
		var field = this.fields[i];
		if (!field.fixed) field.Set (state[i]);
	}
}

function SudokuPerma () {
	var query= "sudoku=";
	for (var i=0; this.fields.length>i; i++) {
		query += this.fields[i].value;
	}
	location.search=query;
}

function SudokuHelpS (unit) {
	var count = 0;
	var digitPos=new Array (9);
	for (var index=0; 9>index; index++) digitPos[index]=new Array (10);
	for (var i=0; this.fields.length>i; i++) {
		var field = this.fields[i];
		var index = field[unit];
		if (field.value) {
			digitPos[index][field.value] = 1;
			continue;
		}
		for (var digit=1; 9>=digit; digit++) {
			var button=field.buttons[digit];
			if (button.block) continue;
			if (digitPos[index][digit]) {
				digitPos[index][digit]=2;
			} else {
				digitPos[index][digit]=button;
			}
		}
	}
	for (var index=0; 9>index; index++) {
		for (var digit=1; 9>=digit; digit++) {
			if (typeof(digitPos[index][digit])!='object') continue;
			digitPos[index][digit].className='hint';
			count++;
		}
	}
	return count;
}

function SudokuHelp (minlevel, maxlevel) {
	var count=0;
	for (var i=0; this.fields.length>i; i++) {
		var field = this.fields[i];
		if (field.className=='hint') field.className = null;
		for (var digit=1; 9>=digit; digit++) {
			var button = field.buttons[digit];
			if (button.className=='hint') button.className = null;
		}
	}
	for (var level=minlevel; maxlevel>=level; level++) {
		if (level==1) {
			for (var i=0; this.fields.length>i; i++) {
				var field = this.fields[i];
				if (field.value || field.choices != 1) continue;
				field.className = 'hint';
				count++;
			}
		}
		if (level==2) count += this.HelpS('row');
		if (level==3) count += this.HelpS('col');
		if (level==4) count += this.HelpS('blk');
	}
	if (maxlevel>minlevel && !count) alert ("Leider keine Vorschläge");
}

function SudokuInit() {

	var first;
	var buttons = document.getElementsByTagName('button');
	for (var i=0; buttons.length>i; i++) {
		var button = buttons[i];
		var board = button.parentNode;
		var field = board;
		while (board && board.className != 'sudoku') {
			board = board.parentNode;
		}
		if (!board) continue;
		button.board = board;
		if (field.tagName != 'td') continue;
		if (!board.fields) {
			board.fields = new Array();
			board.filled = 0;
			board.stack = new Array();
			board.Enter = SudokuEnter;
			board.Erase = SudokuErase;
			board.HelpS = SudokuHelpS;
			board.Help  = SudokuHelp;
			board.Perma = SudokuPerma;
			board.Preset= SudokuPreset;
			board.Pop   = SudokuPop;
			board.Push  = SudokuPush;
			board.Reset = SudokuReset;
			board.Setup = SudokuSetup;
		}
		if (!field.buttons) {
			var row = Math.floor (board.fields.length/9);
			var col = board.fields.length%9;
			var blk = row-row%3+Math.floor(col/3);
			field.row = row;
			field.col = col;
			field.blk = blk;
			field.board= board;
			field.buttons = new Array(1);
			field.choices = 9;
			field.fixed=0;
			field.value=0;
			field.Set  = SudokuSet;
			field.Clear= SudokuClear;
			board.fields.push(field);
			if (!first && board.fields.length==81) first=board;
		}
		button.block = 0;
		button.digit = field.buttons.length;
		button.onclick = SudokuClick;
		field.buttons.push(button);
	}

	first.Preset (location.search);
}

if (!document.onLoadFunctions) {
	document.onLoadFunctions = new Array();
	window.onload = function () { for (var i=0; document.onLoadFunctions.length>i;i++) document.onLoadFunctions[i](); }
}

document.onLoadFunctions.push (SudokuInit);

