///////////////////////////////////////////////////////
// xWinLib Sudoku, written by SM Repetti
// (c) 2008 by SM Repetti, All Rights Reserved
//
var NUM_PRESET = 1;
var NUM_INIT   = 2;

function xwin_Sudoku( ) {
	this.win = null;
	this.winNav = null;
	this.winResults = null;
	this.winTimer = null;
	this.aCell = null;
	this.cellWidth = 60;
	this.cellHeight = 60;
	this.cellMargin = 5;
	this.curCell = null;
	this.difficulty = "";
	
	this.gameStart = null;	
	this.htimer = null;
	
	this.init( );
}

xwin_Sudoku.prototype.init = function( ) {
	var i, j;

	// create the main window	
	this.win = new xWindow( "sudoku" );
	this.win.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER | WS_MOVEABLE;
	this.win.setposition( 0, 0, 750, 592 );
	this.win.displayMode = DISP_CENTERED;
	this.win.transLevel = 70;
	this.win.create( );

	// initialize the cell array
	this.aCell = new Array( 9 );
	for ( i=0; i<9; i++ ) {
		this.aCell[i] = new Array( 9 );
	}

	// create the cells
	for ( i=0; i<9; i++ ) {
		for ( j=0; j<9; j++ ) {
			this.aCell[i][j] = this.cellCreate( i, j );
		}
	}

	// create the side window
	this.winNav = new xWindow( "sudoku_nav" );
	this.winNav.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER | WS_CHILD;
	this.winNav.setposition( 590, 5, 153, 580 );
	this.winNav.bodyClass = "smtxtw";
	this.winNav.oparent = this.win;
	this.winNav.overflow = "hidden";
	this.winNav.padding = 7;
	this.winNav.transLevel = 50;
	this.winNav.action = "<b><font class=title>SUDOKU</font><br>xWinLib<p>" + 
		"<a href='javascript:sudoku.gameNew();'>New Game</a><br>" +
		"<a href='javascript:sudoku.gameReset();'>Reset Game</a><br>" +
		"<a href='javascript:sudoku.gameBackgroundToggle();'>Toggle Background</a></b>" +
		"<div style='position:absolute; left:6; top:310; width:138'>" +
		"Use the ARROW KEYS, MOUSE, or TAB BUTTON to select a cell, then enter a number between 1 and 9. Enter hints by holding down the SHIFT button. Press DELETE or the SPACEBAR to erase an entry." +
		"<p><font color='FFFF80'>Written by SM Repetti using the xWinLib library. <a href='mailto:steve@steverepetti.com?subject=Request Sudoku Custom Version'><font color=white>Click here</font></a> to request a custom commercial version.</font>" +
		"<p><a href=\"javascript:exUndock( '/demos/sudoku/sudoku.js' )\">View source code...</a>" + 
		"</div>";
	this.winNav.create( );

	// create the results window
	this.winResults = new xWindow( "sudoku_results" );
	this.winResults.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER;
	this.winResults.setposition( 6, 130, 138, 138 );
	this.winResults.bodyClass = "smtxtw";
	this.winResults.oparent = this.winNav;
	this.winResults.overflow = "hidden";
	this.winResults.padding = 0;
	this.winResults.transLevel = 100;
	this.winResults.action = "<table id='sResults' border=1 bordercolor='#606060' cellspacing=0 cellpadding=0 class=tblResults>" +
		"<tr height=15><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td><td width=15>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr height=15><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"</table>";
	this.winResults.create( );
	
	// create the timer window
	this.winTimer= new xWindow( "sudoku_timer" );
	this.winTimer.style = WS_NORMAL | WS_TRANSPARENT;
	this.winTimer.setposition( 7, 275, 138, 20 );
	this.winTimer.bodyClass = "smtxtw";
	this.winTimer.oparent = this.winNav;
	this.winTimer.overflow = "hidden";
	this.winTimer.padding = 0;
	this.winTimer.transLevel = 100;
	this.winTimer.action = "00:00.00";
	this.winTimer.create( );

	xlib.eventBind( document, "keydown", keyHandler, true );
	xlib.eventBind( document, "keyup", keyupHandler, false );
};

xwin_Sudoku.prototype.cellCreate = function( r, c ) {
	var w, x, y;
	
	w = new xWindow( "c" + r + c );
	w.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER;
	w.oparent = this.win;
	w.overflow = "hidden";
	w.transLevel = 80;
	
	if ( ( ( r < 3 || r > 5 ) && ( c < 3 || c > 5 ) ) ||
		 ( ( r > 2 && r < 6 ) && ( c > 2 && c < 6 ) ) ) {
		w.transLevel = 50;
	}

	x = ( ( this.cellMargin + this.cellWidth ) * c ) + this.cellMargin;
	y = ( ( this.cellMargin + this.cellHeight ) * r ) + this.cellMargin;

	w.setposition( x, y, this.cellWidth, this.cellHeight );

	w.action = "<div style='position:absolute; left:0; top:0; width:" + this.cellWidth + "; height:" + this.cellHeight + ";'><table id='" + w.name + "_sHint' style='visibility:hidden;' class='hint' cellpadding=0 cellspacing=0>" +
		"<tr width=33% align=center><td width=33%>&nbsp;</td><td width=34%>&nbsp;</td><td width=33%>&nbsp;</td></tr>" +
		"<tr width=34% align=center><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"<tr width=33% align=center><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>" +
		"</table></div>" +
		"<div style='position:absolute; left:0; top:0; width:" + this.cellWidth + "; height:" + this.cellHeight + ";'><table class='num' cellpadding=0 cellspacing=0>" +
		"<tr align=center><td style='visibility:hidden;' id='" + w.name + "_sNum'></td><tr>" +
		"</table></div>";

	w.eClick = clickHandler;
	w.create( );
	
	return( w );
};

xwin_Sudoku.prototype.cellIndex = function( w ) {
	var a, cnt, i;
	
	a = this.aCell;
	for ( i=0; i<9; i++ ) {
		for ( j=0; j<9; j++ ) {
			if ( a[i][j].name == w.name ) {
				return( { "row": i, "col": j } );
			}
		}
	}
	return( null );
};

xwin_Sudoku.prototype.cellSetNum = function( r, c, val, ntype, k ) {
	var w, o, x, a, cname = "num";
	
	w = typeof( r ) == "number" ? this.aCell[r][c] : r;
	if ( ( ntype & NUM_PRESET ) && ( ! strempty( val ) ) ) {
		cname = "numPreset";
		w.eClick = null;
	}
	o = domObject( w.name + "_sNum" );
	if ( ! ( ntype & NUM_PRESET ) && ( o.className == "numPreset" ) ) {
		return;
	}

	if ( strempty( o.innerHTML ) && k && k.isSHIFT ) {
		o = domObject( w.name + "_sHint" );
		x = int( val ) - 1;
		a = [ 1,1,1,2,2,2,3,3,3 ];
		r = a[x];
		a = [ 1,2,3,1,2,3,1,2,3 ];
		c = a[x];

		o = tableCellObj( o, r, c );
		if ( strat( val, o.innerHTML ) ) {
			o.innerHTML = "&nbsp;";
		}
		else {
			o.innerHTML = val;
		}
	}
	else {
		if ( ntype & NUM_INIT ) {
			w.eClick = clickHandler;
		}
		o.className = cname;
		o.innerHTML = val;
		o.style.visibility = strempty( val ) ? "hidden" : "visible";
		if ( cname != "numPreset" ) {
			o = domObject( w.name + "_sHint" );
			o.style.visibility = strempty( val ) ? "visible" : "hidden";
			if ( ! strempty( val ) ) {
				sudoku.gameVerify( );
			}
		}
	}
};

xwin_Sudoku.prototype.cellTab = function( w, k ) {
	var p, x, y, r;

	p = this.cellIndex( w );
	if ( ! p ) { return; }

	switch ( k.code ) {	
	  case KEY_TAB:
	  	x = int( strextract( "" + ( p.col / 3 ), ".", 1 ) ) * 3;
	  	y = int( strextract( "" + ( p.row / 3 ), ".", 1 ) ) * 3;
	  	r = ( { 'x1': x, 'y1': y, 'x2': x+2, 'y2': y+2 } );

		if ( k.isSHIFT ) {
			p.col--; 
			if ( p.col < r.x1 ) {
				p.row--;
				if ( p.row < r.y1 ) {
					p.col = r.x2;
					p.row = r.y2;
				}
				else {
					p.col = r.x2;
				}
			}
		}
		else {
			p.col++; 
			if ( p.col > r.x2 ) {
				p.row++;
				if ( p.row > r.y2 ) {
					p.col = r.x1;
					p.row = r.y1;
				}
				else {
					p.col = r.x1;
				}
			}
		}
	  	break;
	  case KEY_ARROWLEFT:
	  	p.col--; if ( p.col < 0 ) { p.col = 8; }
	  	break;
	  case KEY_ARROWUP:
	  	p.row--; if ( p.row < 0 ) { p.row = 8; }
	  	break;
	  case KEY_ARROWRIGHT:
	  	p.col++; if ( p.col > 8 ) { p.col = 0; }
	  	break;
	  case KEY_ARROWDOWN:
	  	p.row++; if ( p.row > 8 ) { p.row = 0; }
	  	break;
	}

	this.cellToggle( this.aCell[p.row][p.col] );
};

xwin_Sudoku.prototype.cellToggle = function( w ) {

	if ( sudoku.curCell ) {
		if ( sudoku.curCell.name == w.name ) {
			return;
		}
		sudoku.curCell.obj.style.border = "solid 1px black";
		if ( sudoku.curCell.name == w.name ) {
			sudoku.curCell = null;
			return;
		}
	}

	w.obj.style.border = "solid 3px white";
	w.obj.focus( );
	sudoku.curCell = w;
};

xwin_Sudoku.prototype.gameBackgroundToggle = function(  ) {
	this.win.obj.style.background = strat( "white", this.win.obj.style.background ) ? "" : "white";
};

xwin_Sudoku.prototype.gameLoad = function( data ) {
	var a, i, cnt, r=0, c=0;

	if ( ! data ) {
		this.gameNew( 1 );
		return;
	}


	a = data.split( "," );
	this.difficulty = upper( a[81] );
	for ( i=0; i<81; i++ ) {	
		if ( c > 8 ) {
			r++;
			c = 0;
		}
		this.cellSetNum( r, c++, a[i] == "0" ? "" : a[i], NUM_PRESET | NUM_INIT );
	}
	this.cellToggle( this.aCell[0][0] );

	this.gameStart = new Date( );
	this.gameTimer( 1 );

	this.gameVerify( );
};

xwin_Sudoku.prototype.gameNew = function( NoConfirm ) {
	var a;

	if ( ! NoConfirm ) {
		if ( ! confirm( "Are you sure you want to load a new game?" ) ) {
			return;
		}
	}
	
	a = new Array( );

	a[1]  = "0,8,6,0,3,9,4,0,0,0,1,0,0,0,2,0,0,0,0,7,0,0,0,0,0,1,8,0,2,0,0,0,3,0,0,4,0,0,0,6,0,1,0,0,0,6,0,0,5,0,0,0,7,0,7,3,0,0,0,0,0,9,0,0,0,0,9,0,0,0,4,0,0,0,9,3,5,0,1,2,0,easy";
	a[2]  = "0,0,0,0,9,0,3,0,0,2,0,8,3,0,4,0,0,5,0,6,0,0,0,0,0,2,0,0,0,9,0,0,0,1,3,0,0,4,0,9,0,7,0,6,0,0,2,6,0,0,0,8,0,0,0,7,0,0,0,0,0,9,0,9,0,0,6,0,5,7,0,3,0,0,1,0,7,0,0,0,0,easy";
	a[3]  = "3,0,0,0,0,1,8,0,2,0,1,6,0,0,0,0,9,0,0,2,4,0,0,7,0,0,0,0,6,0,0,9,0,2,0,0,0,0,2,0,0,0,6,0,0,0,0,9,0,1,0,0,7,0,0,0,0,6,0,0,5,1,0,0,3,0,0,0,0,4,2,0,7,0,1,3,0,0,0,0,8,easy";
	a[4]  = "0,0,0,9,0,6,0,0,0,0,9,0,0,0,0,0,7,0,6,8,7,0,0,0,4,2,9,0,0,6,8,0,3,5,0,0,5,0,0,0,0,0,0,0,2,0,0,9,7,0,2,1,0,0,1,4,2,0,0,0,7,8,6,0,6,0,0,0,0,0,4,0,0,0,0,6,0,7,0,0,0,easy";
	a[5]  = "6,0,2,7,5,0,0,4,0,0,0,0,9,6,2,0,0,0,0,7,0,4,0,0,0,0,0,0,1,6,0,9,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,7,0,8,5,0,0,0,0,0,0,9,0,3,0,0,0,0,1,8,7,0,0,0,0,8,0,0,3,4,6,0,7,easy"; 
	a[6]  = "0,0,2,9,0,7,5,0,0,0,8,0,0,6,0,0,2,0,1,0,3,0,0,0,4,0,9,0,0,4,3,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,9,2,0,8,1,0,0,2,0,6,0,0,0,7,0,5,0,5,0,0,4,0,0,3,0,0,0,1,7,0,2,6,0,0,easy"; 
	a[7]  = "0,0,0,9,0,6,0,0,0,0,9,0,0,0,0,0,7,0,6,8,7,0,0,0,4,2,9,0,0,6,8,0,3,5,0,0,5,0,0,0,0,0,0,0,2,0,0,9,7,0,2,1,0,0,1,4,2,0,0,0,7,8,6,0,6,0,0,0,0,0,4,0,0,0,0,6,0,7,0,0,0,easy"; 

	a[8]  = "0,0,1,7,0,0,2,0,0,0,7,0,0,8,4,0,0,3,0,0,0,0,0,9,1,0,8,4,0,3,0,0,2,0,0,0,8,0,0,0,0,0,0,0,7,0,0,0,6,0,0,3,0,9,9,0,8,4,0,0,0,0,0,1,0,0,5,2,0,0,8,0,0,0,5,0,0,6,7,0,0,medium";
	a[9]  = "0,9,0,0,0,0,8,0,0,0,0,1,0,0,2,4,6,5,2,0,0,0,7,0,0,0,0,0,0,0,0,0,3,5,0,9,0,6,0,0,0,0,0,3,0,3,0,5,1,0,0,0,0,0,0,0,0,0,6,0,0,0,8,7,1,2,3,0,0,9,0,0,0,0,9,0,0,0,0,7,0,medium";
	a[10] = "9,0,5,0,6,0,0,0,0,0,0,0,0,0,5,8,0,6,0,0,0,0,0,4,0,5,9,0,0,0,0,5,1,3,4,0,0,0,2,0,0,0,6,0,0,0,7,4,6,2,0,0,0,0,3,5,0,1,0,0,0,0,0,8,0,9,3,0,0,0,0,0,0,0,0,0,8,0,7,0,4,medium";
	a[11] = "0,3,0,2,0,4,0,0,8,0,0,9,0,6,0,5,0,0,0,4,0,8,0,0,0,7,0,9,0,0,0,4,0,0,8,0,0,0,3,0,0,0,4,0,0,0,5,0,0,1,0,0,0,3,0,8,0,0,0,7,0,2,0,0,0,1,0,8,0,7,0,0,6,0,0,5,0,1,0,3,0,medium";
	a[12] = "9,0,0,4,0,0,3,0,0,0,0,6,0,5,2,0,0,9,0,0,0,8,0,0,0,2,0,5,0,0,1,8,0,0,0,0,6,4,0,0,0,0,0,5,1,0,0,0,0,9,5,0,0,4,0,8,0,0,0,6,0,0,0,4,0,0,5,2,0,9,0,0,0,0,1,0,0,3,0,0,5,medium";
	a[13] = "6,0,0,0,0,0,8,0,0,0,3,1,8,0,0,6,0,0,2,0,0,9,0,6,3,0,4,0,5,0,0,0,7,0,1,0,0,0,0,0,8,0,0,0,0,0,1,0,3,0,0,0,8,0,1,0,9,2,0,8,0,0,6,0,0,7,0,0,9,2,4,0,0,0,3,0,0,0,0,0,9,medium";
	a[14] = "0,0,0,0,0,1,0,5,0,0,0,4,0,0,0,3,8,0,5,0,0,9,0,0,0,7,0,0,0,9,0,3,0,0,1,0,0,5,1,4,0,6,2,3,0,0,7,0,0,1,0,6,0,0,0,4,0,0,0,3,0,0,9,0,3,6,0,0,0,1,0,0,0,9,0,7,0,0,0,0,0,medium";
	a[15] = "4,5,0,0,6,0,7,1,0,7,0,0,1,0,0,0,6,0,0,0,0,0,0,0,5,0,3,0,2,0,0,3,0,0,0,0,8,0,1,0,0,0,6,0,5,0,0,0,0,5,0,0,9,0,1,0,4,0,0,0,0,0,0,0,6,0,0,0,4,0,0,8,0,3,8,0,1,0,0,5,9,medium";
	a[16] = "0,8,0,7,0,0,4,0,0,0,1,9,0,3,0,0,8,0,0,7,3,0,0,0,2,0,0,5,0,0,8,0,0,0,0,0,0,0,7,4,0,9,1,0,0,0,0,0,0,0,3,0,0,5,0,0,8,0,0,0,6,1,0,0,3,0,0,7,0,5,9,0,0,0,6,0,0,5,0,2,0,medium";
	a[17] = "0,1,0,0,0,0,9,0,0,3,8,0,0,2,9,1,0,0,0,0,4,0,0,8,0,2,0,4,0,0,9,0,3,0,0,0,1,0,0,0,0,0,0,0,4,0,0,0,2,0,1,0,0,7,0,2,0,3,0,0,8,0,0,0,0,8,1,5,0,0,3,2,0,0,6,0,0,0,0,7,0,medium";
	a[18] = "0,5,1,0,0,0,2,7,0,0,3,0,7,2,6,0,4,0,7,0,0,0,0,0,0,0,8,0,0,2,1,0,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,8,1,0,0,2,0,0,0,0,0,0,0,7,0,7,0,9,1,2,0,3,0,0,1,5,0,0,0,9,6,0,medium"; 
	a[19] = "5,0,0,4,0,0,6,8,0,0,2,0,0,0,0,0,0,4,0,6,0,2,0,8,0,0,9,9,0,1,0,0,0,2,6,0,0,0,0,0,1,0,0,0,0,0,5,7,0,0,0,9,0,3,2,0,0,7,0,4,0,5,0,4,0,0,0,0,0,0,9,0,0,1,8,0,0,5,0,0,6,medium"; 

	a[20] = "2,0,0,0,0,0,0,5,0,0,0,0,0,0,7,1,0,0,0,8,4,9,0,0,0,3,0,8,0,0,7,4,0,0,6,5,0,0,0,0,2,0,0,0,0,3,6,0,0,1,8,0,0,4,0,9,0,0,0,6,5,1,0,0,0,2,8,0,0,0,0,0,0,7,0,0,0,0,0,0,9,hard"; 
	a[21] = "0,0,3,0,0,0,0,7,6,0,1,0,5,0,0,0,4,0,5,2,0,0,6,0,0,3,0,0,0,0,1,0,5,0,0,0,0,5,2,0,0,0,1,9,0,0,0,0,8,0,7,0,0,0,0,4,0,0,5,0,0,8,7,0,7,0,0,0,4,0,2,0,9,8,0,0,0,0,4,0,0,hard";
	a[22] = "3,0,5,0,2,0,0,4,1,0,0,9,0,0,1,7,0,0,0,0,0,0,0,0,2,0,0,7,0,0,3,0,0,6,0,0,5,0,0,1,0,2,0,0,3,0,0,8,0,0,9,0,0,5,0,0,3,0,0,0,0,0,0,0,0,4,8,0,0,5,0,0,1,6,0,0,4,0,3,0,9,hard";
	a[23] = "2,0,0,0,3,0,0,7,5,0,5,0,0,0,2,3,8,0,0,0,0,5,0,9,0,0,0,0,0,0,4,0,0,5,0,8,9,0,0,0,0,0,0,0,7,7,0,2,0,0,6,0,0,0,0,0,0,1,0,5,0,0,0,0,2,4,9,0,0,0,6,0,8,9,0,0,6,0,0,0,3,hard"; 
	a[24] = "0,5,0,0,0,3,0,0,4,0,8,0,0,7,2,0,0,0,2,0,3,9,0,8,0,0,1,0,0,6,0,3,0,0,0,9,0,0,0,0,0,0,0,0,0,3,0,0,0,5,0,7,0,0,6,0,0,8,0,4,3,0,7,0,0,0,1,9,0,0,2,0,9,0,0,3,0,0,0,4,0,hard"; 
	a[25] = "0,1,0,0,0,0,0,0,8,6,0,2,0,3,0,0,0,9,0,0,0,1,0,2,4,0,0,0,3,0,4,0,9,8,0,0,0,5,0,0,0,0,0,4,0,0,0,4,3,0,8,0,7,0,0,0,1,2,0,3,0,0,0,8,0,0,0,4,0,6,0,1,9,0,0,0,0,0,0,3,0,hard"; 

	a[26] = "0,0,0,0,0,0,0,0,8,4,0,0,0,7,9,0,5,0,0,5,0,0,0,2,3,9,1,0,0,3,8,0,0,0,0,0,0,2,0,0,0,0,0,8,0,0,0,0,0,0,6,1,0,0,8,7,2,9,0,0,0,3,0,0,1,0,3,5,0,0,0,2,3,0,0,0,0,0,0,0,0,evil";
	a[27] = "0,5,0,0,0,1,6,0,0,3,0,6,0,0,0,0,0,0,0,0,9,3,0,0,2,0,4,0,0,0,0,3,0,1,0,2,0,0,0,8,0,4,0,0,0,8,0,5,0,2,0,0,0,0,6,0,1,0,0,5,3,0,0,0,0,0,0,0,0,9,0,1,0,0,7,2,0,0,0,4,0,evil"; 
 	a[28] = "0,0,0,0,6,8,0,7,0,0,3,2,0,0,0,0,0,0,0,0,6,0,0,3,2,5,0,1,9,0,0,7,0,0,8,0,0,0,0,0,4,0,0,0,0,0,5,0,0,8,0,0,3,4,0,7,9,1,0,0,3,0,0,0,0,0,0,0,0,5,6,0,0,6,0,7,3,0,0,0,0,evil"; 
	a[29] = "0,3,0,6,9,0,0,0,0,5,7,0,0,3,8,0,0,0,0,0,0,0,0,0,6,0,0,4,9,5,3,0,0,0,8,0,0,6,0,0,0,0,0,1,0,0,8,0,0,0,6,5,3,9,0,0,7,0,0,0,0,0,0,0,0,0,8,2,0,0,4,5,0,0,0,0,6,1,0,2,0,evil"; 

	if ( ! NoConfirm ) {
		this.gameReset( 1 );
	}

	x = random( a.length - 1 );
	this.gameLoad( a[x] );
};

xwin_Sudoku.prototype.gameReset = function( NoConfirm ) {
	var a, cnt, i, oHint, o, x, y;

	if ( ! NoConfirm ) {
		if ( ! confirm( "Are you sure you want to reset the current game?" ) ) {
			return;
		}
	}

	aRows = [ 1,1,1,2,2,2,3,3,3 ];
	aCols = [ 1,2,3,1,2,3,1,2,3 ];
	
	a = this.aCell;
	for ( i=0; i<9; i++ ) {
		for ( j=0; j<9; j++ ) {
			if ( domObject( a[i][j].name + "_sNum" ).className != "numPreset" ) {
				this.cellSetNum( a[i][j], 0, "" );
				oHint = domObject( a[i][j].name + "_sHint" );
				for ( x=0; x<3; x++ ) {
					o = tableRowObj( oHint, x+1 );
					for ( y=0; y<3; y++ ){
						o.cells[y].innerHTML = "&nbsp;";
					}
				}
			}
		}
	}

	if ( ! NoConfirm ) {
		this.cellToggle( this.aCell[0][0] );
	}
	this.gameStart = new Date( );
	this.gameVerify( );
};

xwin_Sudoku.prototype.gameResultsRow = function( row, flag ) {
	var i, otable;

	otable = domObject( "sResults" );
	for ( i=1; i<10; i++ ) {
		o = tableCellObj( otable, row+1, i );
		o.style.background = flag ? "#00FF00" : "";
	}
};

xwin_Sudoku.prototype.gameResultsCol = function( col, flag ) {
	var i, otable;

	otable = domObject( "sResults" );
	for ( i=1; i<10; i++ ) {
		o = tableCellObj( otable, i, col+1 );
		if ( flag ) { o.style.background = "#00FF00"; }
	}
};

xwin_Sudoku.prototype.gameResultsBlock = function( a, flag ) {
	var i, otable;

	otable = domObject( "sResults" );
	for ( i=0; i<9; i++ ) {
		o = tableCellObj( otable, a[i][0]+1, a[i][1]+1 );
		if ( flag ) { o.style.background = "#00FF00"; }
	}
};

xwin_Sudoku.prototype.gameTimer = function( flag ) {
	if ( this.htimer ) {
		clearTimeout( this.htimer );
		this.htimer = null;
	}

	if ( flag ) {
		this.htimer = setTimeout( "sudoku.gameTimerUpdate( )", 200 );
	}
};

xwin_Sudoku.prototype.gameTimerUpdate = function( flag ) {
	d = new xDate( );
	sudoku.winTimer.oBody.innerHTML = d.diff( d.date, sudoku.gameStart ) + " &nbsp; <font color='FFFF80'>" + this.difficulty + "</font>";
	setTimeout( "sudoku.gameTimerUpdate( )", 200 );
};

xwin_Sudoku.prototype.gameVerify = function( ) {
	var a, cnt, i, ttl=1, d;

	// verify rows
	for ( i=0; i<9; i++ ) {
		a = [ 0,0,0,0,0,0,0,0,0 ];
		for ( j=0; j<9; j++ ) {
			x = int( "0" + domObject( this.aCell[i][j].name + "_sNum" ).innerHTML ) - 1;
			a[x]=1;
		}

		flag = 1;
		for ( j=0; j<9; j++ ) {
			if ( ! a[j] ) {
				flag = 0;
				break;
			}
		}
		this.gameResultsRow( i, flag );
		if ( ! flag ) { ttl = 0; }
	}

	// verify cols
	for ( i=0; i<9; i++ ) {
		a = [ 0,0,0,0,0,0,0,0,0 ];
		for ( j=0; j<9; j++ ) {
			x = int( "0" + domObject( this.aCell[j][i].name + "_sNum" ).innerHTML ) - 1;
			a[x]=1;
		}

		flag = 1;
		for ( j=0; j<9; j++ ) {
			if ( ! a[j] ) {
				flag = 0;
				break;
			}
		}
		if ( flag ) { this.gameResultsCol( i, flag ); }
		if ( ! flag ) { ttl = 0; }
	}

	// verify blocks
	a = new Array( 9 );
	a[0] = [ [0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2] ];
	a[1] = [ [3,0], [3,1], [3,2], [4,0], [4,1], [4,2], [5,0], [5,1], [5,2] ];
	a[2] = [ [6,0], [6,1], [6,2], [7,0], [7,1], [7,2], [8,0], [8,1], [8,2] ];
	a[3] = [ [0,3], [0,4], [0,5], [1,3], [1,4], [1,5], [2,3], [2,4], [2,5] ];
	a[4] = [ [3,3], [3,4], [3,5], [4,3], [4,4], [4,5], [5,3], [5,4], [5,5] ];
	a[5] = [ [6,3], [6,4], [6,5], [7,3], [7,4], [7,5], [8,3], [8,4], [8,5] ];
	a[6] = [ [0,6], [0,7], [0,8], [1,6], [1,7], [1,8], [2,6], [2,7], [2,8] ];
	a[7] = [ [3,6], [3,7], [3,8], [4,6], [4,7], [4,8], [5,6], [5,7], [5,8] ];
	a[8] = [ [6,6], [6,7], [6,8], [7,6], [7,7], [7,8], [8,6], [8,7], [8,8] ];

	for ( i=0; i<9; i++ ) {
		b = [ 0,0,0,0,0,0,0,0,0 ];
		for ( j=0; j<9; j++ ) {
			pt = a[i][j];
			x = int( "0" + domObject( this.aCell[pt[0]][pt[1]].name + "_sNum" ).innerHTML ) - 1;
			b[x]=1;
		}

		flag = 1;
		for ( j=0; j<9; j++ ) {
			if ( ! b[j] ) {
				flag = 0;
				break;
			}
		}
		if ( flag ) { this.gameResultsBlock( a[i], flag ); }
		if ( ! flag ) { ttl = 0; }
	}

	if ( ttl ) {
		this.gameTimer( 0 );
		d = new xDate( );
		alert( "Congratulations!  You have successfully completed the puzzle.\nYour final time was " + d.diff( d.date, this.gameStart )  );
	}
};

function clickHandler( w, e ) {
	sudoku.cellToggle( w );
}


function keyupHandler( e ) {
	xlib.editClearSelection( e );
}

function keyHandler( e ) {
	var k = xlib.keyGet( e );

	if ( sudoku.curCell	) {
		switch ( k.code ) {
		  case KEY_SPACE:
		  case KEY_DELETE:
		  	sudoku.cellSetNum( sudoku.curCell, 0, "" );
		  	break;
		  case KEY_TAB:
		  case KEY_ARROWLEFT:
		  case KEY_ARROWUP:
		  case KEY_ARROWRIGHT:
		  case KEY_ARROWDOWN:
			sudoku.cellTab( sudoku.curCell, k );
			break;

		  case KEY_BACKSPACE:
			xlib.eventCancelBubble( e );
			return( xlib.eventCancel( e ) );
			
		  default:
			if ( k.code > 48 && k.code < 58 ) {
				sudoku.cellSetNum( sudoku.curCell, 0, "" + ( k.code - 48 ), 0, k );
			}
			else if ( k.code > 96 && k.code < 106 )	{
				// non-shifted num-lock
				sudoku.cellSetNum( sudoku.curCell, 0, "" + ( k.code - 96 ), 0, k );
			}
		}
		
		if ( k.code == KEY_TAB ) {
			xlib.eventCancelBubble( e );
			return( xlib.eventCancel( e ) );
		}
	}
}
