// Namespace

var NULL = null;
var Vitenka = NULL;

function Vitenka_Setup()
{
	if ( Vitenka ) return;

	Vitenka = new Object();

	Vitenka.DefaultId = "Dynamic";
	Vitenka.GetObject = function ( _id )
	{
		if ( !_id ) _id = this.DefaultId;
		if ( "object" == typeof(_id) ) return _id;
		// TODO: Old browser hackery
		return document.getElementById( _id );
	};

	Vitenka.Abstract = new Object();
	Vitenka.Abstract.m_size		= 5;
	Vitenka.Abstract.m_id		= "AbstractRugGame";

	Vitenka.Abstract.Test = function() { alert( "TEST" ); }

	Vitenka.Abstract.GetDefaultSize = function() { return 5 };

	Vitenka.Abstract.GetGridNumber = function ( _x, _y, _size )
	{
		if ( !_size ) _size = this.m_size;
		return (_y * _size ) + _x;
	};

	Vitenka.Abstract.GetGridEltId = function ( _x, _y, _size, _id )
	{
		if ( !_id ) _id = this.m_id;
		if ( !_size ) _size = this.m_size;
		if ( _x < 0 || _x > _size ) return NULL;
		if ( _y < 0 || _y > _size ) return NULL;

		var num = this.GetGridNumber( _x, _y, _size );
		var name = _id + num;
		return name;
	};

	Vitenka.Abstract.m_backgroundColour = "#ffffff";
	Vitenka.Abstract.m_highlightColour  = "#000000";
	Vitenka.Abstract.CreateGrid = function ( _size, _id, _container )
	{
		if ( !_size ) _size = this.GetDefaultSize();
		if ( !_id ) _id = this.m_id;

		var o = Vitenka.GetObject ( _id );
		if ( !o )
		{
			var container = Vitenka.GetObject ( _container );
			if ( container )
			{
				container.innerHTML += "<div id=\""+_id+"\" style=\"background-color:"+this.m_backgroundColour+";\"></div>\n";
			};
			o = Vitenka.GetObject ( _id );
		}
		if ( o )
		{
			this.m_size = _size;
			this.m_id = _id;
			var html = "<table onMouseOut=\"Vitenka.Abstract.ClearFlash();\" class=\"AbstractGridStyle\" rows=" + _size + " cols=" + _size + ">\n";

			this.m_grid = new Array( _size * _size );

			for ( var y = 0; y < _size; y++ )
			{
				html = html + "<tr style=\"AbstractGridStyle\">\n";
				for ( var x = 0; x < _size; x++ )
				{
					var name = this.GetGridEltId( x, y, _size, _id );
					html += "<td onClick=\"Vitenka.Abstract.MouseClickGrid("+x+","+y+");\" onMouseOver=\"Vitenka.Abstract.MouseOverGrid("+x+","+y+");\" class=\"AbstractGridStyle\" id=\"" + name + "\">";
					if ( Vitenka.Debug ) html += "(" + x + "," + y + ")";
					html += "\&nbsp;</td>\n";
					this.m_grid[ this.GetGridNumber(x, y,_size) ] = 0;
				}
				html = html + "</tr>\n";
			}

			html = html + "</table>\n";
		}
		o.innerHTML = html;
	};

	Vitenka.Abstract.MakePieceHtml = function( _w, _h )
	{
		if ( !_w || !_h ) return "";
		if ( _w < 0 || _h < 0 ) return "";

		var scale = 20;

		var w = _w * scale;
		var h = _h * scale;

		return "<div class=\"AbstractGridStyle\" style=\"background-image:url('Abstract_tile.gif'); width:"+w+"; height:"+h+";\" width="+ w + " height="+ h + ">&nbsp</div>\n";
	};

	Vitenka.Abstract.CreatePieces = function()
	{
		var rval = new Array( 3 );
		// Two 3x3 bits
		rval[0] = new Object();
		rval[0].m_width  = 3;
		rval[0].m_height = 3;
		rval[0].m_num = 2;
		// Three 3x2 bits
		rval[1] = new Object();
		rval[1].m_width  = 3;
		rval[1].m_height = 2;
		rval[1].m_num = 3;
		// Four 2x2 bits
		rval[2] = new Object();
		rval[2].m_width  = 2;
		rval[2].m_height = 2;
		rval[2].m_num = 4;

		// Piece display
		for( var i=0; i<rval.length; ++i )
		{
			var w = rval[i].m_width;
			var h = rval[i].m_height;
			rval[i].m_html = this.MakePieceHtml( w, h );
			if ( w != h )
			{
				rval[i].m_html += "<br />\n" + this.MakePieceHtml( h, w );
			}
		}

		return rval;
	};
	Vitenka.Abstract.GetPiece = function( _piece, _player )
	{
		if ( !_player ) _player = this.m_curPlayer;
		if ( _player < 1 || _player > this.m_numPlayers || !this.m_players[_player] ) return;
		return this.m_players[_player].m_pieces[_piece];
	};

	Vitenka.Abstract.GetPlayerId = function ( _player )
	{
		if ( !_player || _player < 1 || _player > this.m_numPlayers ) return NULL;
		return this.m_id + "_player_" + _player;
	};

	Vitenka.Abstract.GetScoreId = function ( _player )
	{
		var id = this.GetPlayerId( _player );
		if ( id ) id += "_score";
		return id;
	};

	Vitenka.Abstract.GetPieceId = function ( _player, _piece )
	{
		var id = this.GetPlayerId( _player );
		if ( id ) id += "_piece_" + _piece;
		return id;
	};

	Vitenka.Abstract.GetPieceNumId = function ( _player, _piece )
	{
		var id = this.GetPieceId( _player, _piece );
		if ( id ) id += "_num";
		return id;
	};

	Vitenka.Abstract.CreatePlayer = function ( _player )
	{
		var rval = new Object();
		rval.m_score = 0;
		rval.m_pieces = this.CreatePieces();
		rval.m_colour = "#c0c0c0";
		switch ( _player )
		{
			case 1:
				rval.m_colour = "#ff4466";
				break;
			case 2:
				rval.m_colour = "#33ee44";
				break;
			case 3:
				rval.m_colour = "#44aadd";
				break;
			case 4:
				rval.m_colour = "#dd33dd";
				break;
		}

		rval.m_ai = 0;		// ai control strategy
		rval.m_html = "";
		var id = this.GetPlayerId( _player );
		rval.m_html += "<div id=\"" + id + "\" style=\"background-color:" + rval.m_colour + ";\" class=\"AbstractGridStyle_Player\">\n";
		// rval.m_html += "<h3>Player " + _player + "</h3>\n";
		var scoreId = this.GetScoreId(_player);
		rval.m_html += "<div id=\""+scoreId+"\">Score: 0</div>\n";
		rval.m_html += "<hr />\n";
		for ( var n=0; n < rval.m_pieces.length; n++ )
		{
			rval.m_html += "<div onClick=\"Vitenka.Abstract.SelectPiece("+n+");\" class=\"AbstractGridStyle_Piece\" id=\"" + this.GetPieceId(_player,n) + "\">";
			var piece = rval.m_pieces[n];
			rval.m_html += "<div id=\"" + this.GetPieceNumId(_player,n) + "\" class=\"Abstract_PieceNum\">" + piece.m_num + " x </div>" + piece.m_html;
			rval.m_html += "</div>";
			rval.m_html += "<br />\n";
		}
		rval.m_html += "</div>\n";

		return rval;
	}

	Vitenka.Abstract.CreatePlayers = function ( _numPlayers, _id, _container )
	{
		if ( !_numPlayers ) _numPlayers = 4;
		if ( _numPlayers < 1 || _numPlayers > 4 ) return;

		if ( !_id ) _id = this.m_id + "_players";

		var o = Vitenka.GetObject ( _id );
		if ( !o )
		{
			var container = Vitenka.GetObject ( _container );
			if ( container )
			{
				container.innerHTML += "<div id=\""+_id+"\" style=\"background-color:"+this.m_backgroundColour+";\"></div>\n";
			};
			o = Vitenka.GetObject ( _id );
		}
		if ( o )
		{
			this.m_players = new Array( _numPlayers + 1 );
			// player '0' is reserved for 'blank'
			this.m_players[0] = new Object();
			this.m_players[0].m_colour = "#ffffff";
			// player -1 is the flsh ok colour
			this.m_players[-1] = new Object();
			this.m_players[-1].m_colour = "#c0c0c0";
			// player -2 is the flsh panic colour
			this.m_players[-2] = new Object();
			this.m_players[-2].m_colour = "#220000";

			this.m_numPlayers = _numPlayers;

			var html = "";
			for( var i=1; i<=_numPlayers; i++ )
			{
				this.m_players[i] = this.CreatePlayer( i );
				html += this.m_players[i].m_html;
			}
			this.m_curPlayer = 0;
			o.innerHTML = html;
		}
	};

	Vitenka.Abstract.NextPlayer = function()
	{
		var old = this.GetPlayerId(this.m_curPlayer);
		if ( old )
		{
			var o = Vitenka.GetObject( old );
			if ( o ) o.style.borderColor = this.m_backgroundColour;
		}
		this.m_curPlayer++;
		if ( this.m_curPlayer > this.m_numPlayers ) this.m_curPlayer = 1;
		var id = this.GetPlayerId(this.m_curPlayer);
		if ( id )
		{
			var o = Vitenka.GetObject( id );
			if ( o ) o.style.borderColor = this.m_highlightColour;
		}
		this.SelectPiece( this.m_selectedPiece );
	};

	Vitenka.Abstract.AddToScore = function ( _player, _delta )
	{
		var id = this.GetScoreId( _player );
		if ( _delta && id )
		{
			var o =Vitenka.GetObject( id );
			if ( o && this.m_players && this.m_players[_player] )
			{
				this.m_players[_player].m_score = _delta + this.m_players[_player].m_score;
				o.innerHTML = "Score: " + this.m_players[_player].m_score;
			}
		}
	};

	Vitenka.Abstract.GetColour = function ( _x, _y )
	{
		if ( !this.m_grid ) return 0;
		if ( _x < 0 || _x >= this.m_size ) return 0;
		if ( _y < 0 || _y >= this.m_size ) return 0;

		return this.m_grid[ this.GetGridNumber( _x, _y ) ];
	};

	Vitenka.Abstract.SetDisplayColour = function( _x, _y, _colour )
	{
		if ( this.m_players && this.m_players[_colour] )
		{
			var displayColour = this.m_players[_colour].m_colour;
			var id = this.GetGridEltId( _x, _y );
			var o = Vitenka.GetObject( id );
			if ( o )
			{
				o.style.backgroundColor = displayColour;
			}
		}
	};

	Vitenka.Abstract.SetColour = function ( _x, _y, _colour )
	{
		if ( !this.m_grid ) return;
		if ( _x < 0 || _x > this.m_size ) return;
		if ( _y < 0 || _y > this.m_size ) return;
		if ( _colour < 0 || _colour > this.m_numPlayers ) return;
		
		var num = this.GetGridNumber( _x, _y );
		var old = this.m_grid[ num ];
		this.m_grid[ num ] = _colour;

		if ( this.m_players )
		{
			this.AddToScore( _colour, 1 );
			if ( old && this.m_players[old] )
			{
				this.AddToScore( old, -1 );
			}
			if ( this.m_players[_colour] )
			{
				this.SetDisplayColour( _x, _y, _colour );
			}
		}
	};

	// Flashing
	Vitenka.Abstract.m_targets = new Array();
	Vitenka.Abstract.m_newTargets = new Array();
	Vitenka.Abstract.m_flash = false;
	Vitenka.Abstract.ClearFlash = function()
	{
		this.m_newTargets = new Array();
		this.m_flash = false;
		this.Flash();
		this.m_targets = new Array();
	}
	Vitenka.Abstract.SetFlash = function( _x, _y, _colour )
	{
		if ( !_colour ) _colour = -1;
		var o = new Object();
		o.x = _x;
		o.y = _y;
		o.c = _colour;
		this.m_newTargets.push( o );
	}
	Vitenka.Abstract.SetRangeFlashing = function( _x, _y, _w, _h, _colour )
	{
		for( var x=_x; x<_x+_w; x++ )
		{
			for( var y=_y; y<_y+_h; y++ )
			{
				this.SetFlash( x, y, _colour );
			}
		}
	};
	Vitenka.Abstract.Flash = function()
	{
		if ( !this.m_flash )
		{
			// Reset them
			for ( var i=0; i<this.m_targets.length; i++ )
			{
				var x = this.m_targets[i].x;
				var y = this.m_targets[i].y;
				this.SetDisplayColour( x, y, this.GetColour( x, y ) );
			}
		}
		// Add to list
		for ( var i=0; i<this.m_newTargets.length; i++ )
		{
			this.m_targets.push( this.m_newTargets[i] );
		}
		this.m_newTargets.splice( 0, this.m_newTargets.length );

		if ( this.m_flash )
		{
			for ( var i=0; i<this.m_targets.length; i++ )
			{
				this.SetDisplayColour( this.m_targets[i].x, this.m_targets[i].y, this.m_targets[i].c );
			}
			this.m_flash = false;
		}
		else
		{
			this.m_flash = true;
		}
	};

	Vitenka.Abstract.FloodFill = function ( _x, _y, _colour, _visited )
	{
		// Move only L/R/U/D not diagonally
		// Is this a valid spot?
		// (Note - we're relying upon GetColour returning an invalid colour that doesn't match _colour
		// when we try to go out of bounds)
		if ( this.GetColour( _x, _y ) == _colour )
		{
			// Have we already visited this?
			for ( var i=0; i<_visited.length; i++ )
			{
				var xy = _visited[i];
				if ( xy.x == _x && xy.y == _y )
				{
					// Ok, we're already in the list, abandon ship.
					return _visited;
				}
			}

			// We're new - add use:
			var xy = new Object();
			xy.x = _x;
			xy.y = _y;
			_visited.push( xy );

			// And flood out from here
			_visited = this.FloodFill( _x-1, _y  , _colour, _visited );
			_visited = this.FloodFill( _x+1, _y  , _colour, _visited );
			_visited = this.FloodFill( _x  , _y-1, _colour, _visited );
			_visited = this.FloodFill( _x  , _y+1, _colour, _visited );
		}
		return _visited;
	}

	Vitenka.Abstract.EntirelyWithin = function( _region, _x, _y, _w, _h )
	{
		for ( var i=0; i<_region.length; ++i )
		{
			var xy = _region[i];
			if ( xy.x < _x || xy.y < _y || xy.x >= _x + _w || xy.y >= _y + _h ) return false;
		}
		return true;
	}

	Vitenka.Abstract.IsLegal = function( _x, _y, _w, _h, _colour )
	{
		if ( !_w || _w < 0 ) return false;
		if ( !_h || _h < 0 ) return false;
		if ( _x + _w > this.m_size || _x < 0 ) return false;
		if ( _y + _h > this.m_size || _y < 0 ) return false;
		if ( !_colour ) _colour = this.m_curPlayer;
		if ( _colour < 1 || _colour > this.m_numPlayers ) return false;

		for ( var x = _x; x < _x + _w; x++ )
		{
			for ( var y = _y; y < _y + _h; y++ )
			{
				var colour = this.GetColour( x, y );
				if ( colour == _colour ) return false;

				// 'Cannot cover whole region'
				// Simple lazy test - floodfill and see if we reach something outside of the area we are covering
				// if not, then illegal move
				// TODO: Don't need to floodfill out from every covered square
				// could, for example, hold a list of ones already flooded into
				// and skip them
				if ( colour > 0 )
				{
					var region = new Array();
					region = this.FloodFill( x, y, colour, region );
					if ( this.EntirelyWithin( region, _x, _y, _w, _h ) ) return false;
				}
			}
		}

		return true;
	};

	Vitenka.Abstract.m_flipped = false;
	Vitenka.Abstract.SelectPiece = function ( _piece, _player, _flip )
	{
		if ( !_player ) _player = this.m_curPlayer;
		if ( this.m_selectedPieceId )
		{
			var o = Vitenka.GetObject( this.m_selectedPieceId );
			if ( o )
			{
				o.style.borderColor = o.style.backgroundColor;
			};
		}
		if ( _piece == this.m_selectedPiece
			&& this.m_lastPlayerToSelectPiece == _player )
		{
			this.m_flipped = !this.m_flipped;
		}
		if ( _flip != undefined ) this.m_flipped = _flip;

		if ( !_player || _player < 1 || _player > this.m_numPlayers ) return;
		var player = this.m_players[_player];
		if ( _piece < 0 || _piece > player.m_pieces.length ) return;
		var piece = player.m_pieces[_piece];
		if ( !piece || !piece.m_num ) return;

		// Ok, we've got a valid piece.
		this.m_selectedPiece = _piece;
		this.m_lastPlayerToSelectPiece = _player;
		var id = this.GetPieceId( _player, _piece);
		if ( id )
		{
			var o = Vitenka.GetObject( id );
			if ( o )
			{
				o.style.borderColor = "#000000";
				this.m_selectedPieceId = id;
			};
		}
	};

	Vitenka.Abstract.CliptoEdge = function ( _x, _y, _piece )
	{
		if ( !_piece ) return;
		if ( !_x || _x < 0 ) _x = 0;
		if ( !_y || _y < 0 ) _y = 0;

		var w = this.GetPieceWidth ( _piece );
		var h = this.GetPieceHeight( _piece );

		if ( _x + w > this.m_size ) _x = this.m_size - w;
		if ( _y + h > this.m_size ) _y = this.m_size - h;
		var rval = new Object();
		rval.x = _x;
		rval.y = _y;
		return rval;
	};

	Vitenka.Abstract.GetPieceWidth = function( _pieceObject )
	{
		if ( !_pieceObject ) return 0;
		return this.m_flipped ? _pieceObject.m_height : _pieceObject.m_width;
	};

	Vitenka.Abstract.GetPieceHeight = function( _pieceObject )
	{
		if ( !_pieceObject ) return 0;
		return this.m_flipped ? _pieceObject.m_width : _pieceObject.m_height;
	};

	Vitenka.Abstract.MouseOverGrid = function( _x, _y )
	{
		if ( this.m_gameOver ) return;
		var piece = this.GetPiece(this.m_selectedPiece);
		var xy = this.CliptoEdge( _x, _y, piece );
		this.ClearFlash();

		var w = this.GetPieceWidth ( piece );
		var h = this.GetPieceHeight( piece );
		var legal = piece && piece.m_num >= 1 && this.IsLegal( xy.x, xy.y, w, h, this.m_curPlayer );

		// TODO: Instead, highlight the REASON why it's illegal
		this.SetRangeFlashing( xy.x, xy.y, w, h, legal ? -1 : -2 );
	};

	Vitenka.Abstract.UseUpPiece = function( _piece, _player )
	{
		if ( !_piece ) _piece = this.m_selectedPiece;
		if ( !_player ) _player = this.m_curPlayer;
		var piece = this.GetPiece(_piece);
		piece.m_num -= 1;
		var id = this.GetPieceNumId( _player, _piece );
		if ( id )
		{
			var o = Vitenka.GetObject( id );
			if ( o )
			{
				o.innerHTML = "" + piece.m_num + " x";
			}
		}
	}

	Vitenka.Abstract.MouseClickGrid = function ( _x, _y )
	{
		if ( this.m_gameOver ) return;
		var legalMove = this.PlayMove( _x, _y, this.m_curPlayer, this.m_selectedPiece, this.m_flipped );

		if ( legalMove )
		{
			this.MovePlayed( _x, _y );
		}
	};

	Vitenka.Abstract.MakeAiMove = function ( _moves )
	{
		if ( this.m_gameOver ) return;

		var move = this.ChooseAIMove( _moves, this.m_players[this.m_curPlayer].m_ai );
		if ( move )
		{
			this.PlayMove( move.x, move.y, this.m_curPlayer, move.piece, move.flip );
			// Note, we're assumign the AI only ever makes legal moves.
			this.MovePlayed( move.x, move.y );
		}
		else if ( this.m_playingDemo )
		{
			this.StopDemo();
		}
	};
	
	Vitenka.Abstract.MovePlayed = function( _x, _y )
	{
		this.NextPlayer();

		if ( this.m_playingDemo ) return;


		// Player has changed, board has changed -legality has almost certainly changed
		// so refresh the selection box
		this.MouseOverGrid( _x, _y );

		var legalMoves = this.GetLegalMoves();

		// And check if that's it
		if ( this.IsGameOver(legalMoves) )
		{
			this.GameOver();
		}
		else if ( this.IsAI() )
		{
			this.MakeAiMove( legalMoves );
		}
	};

	Vitenka.Abstract.PlayMove = function( _x, _y, _player, _pieceNum, _flip )
	{
		var piece = this.GetPiece(_pieceNum,_player);
		var xy = this.CliptoEdge( _x, _y, piece );
		var w = this.GetPieceWidth ( piece );
		var h = this.GetPieceHeight( piece );
		var legal = piece && piece.m_num >= 1 && this.IsLegal( xy.x, xy.y, w, h, this.m_curPlayer );

		if ( legal )
		{
			for( var x=xy.x; x<xy.x+w; x++ )
			{
				for( var y=xy.y; y<xy.y+h; y++ )
				{
					this.SetColour( x, y, _player );
				}
			}
			this.UseUpPiece( _pieceNum, _player );
		}
		return legal;
	};

	Vitenka.Abstract.IsAI = function()
	{
		return this.m_players[this.m_curPlayer].m_ai > 0;
	};

	Vitenka.Abstract.ChooseAIMove = function( _moves, _aiLevel )
	{
		if ( !_moves ) _moves = this.GetLegalMoves();
		if ( !_aiLevel ) _aiLevel = this.m_players[this.m_curPlayer].m_ai;
		
		if ( !_moves || !_moves.length ) return;
		switch ( _aiLevel )
		{
			case 1:
			{
				// Choose a random move
				var r = Math.random();
				r = r * (_moves.length);
				r = Math.floor( r );
				return _moves[r];
			}
			case 2:
			{
				// Choose a random move from the largest available piece
				var m = _moves.length;
				// NOTE: This relies upon the current order the
				// moves array is filled out in GetLegalMoves
				var largestPiece = _moves[0].piece;
				for ( var i=1; i<_moves.length; i++ )
				{
					if ( _moves[i].piece > largestPiece )
					{
						m = i-1;
						break;
					}
				}
				var r = Math.random();
				r = r * (m);
				r = Math.floor( r );
				return _moves[r];
			}
		}
	};

	Vitenka.Abstract.GetLegalMoves = function()
	{
		var rval = new Array();

		// For each piece that you have some of, is there any valid place to go?
		var player = this.m_players[this.m_curPlayer];

		// TODO: Reverse order would be better, usually you have some 2x2 and those
		// are obviously easiest to place
		for ( var p=0; p<player.m_pieces.length; ++p )
		{
			var piece = player.m_pieces[p];
			if ( !piece || piece.m_num < 1 ) continue;
			var h = this.GetPieceHeight(piece);
			var w = this.GetPieceWidth (piece);
			// Ok, is there anywhere it can go?
			for ( var x=0; x<=this.m_size - w; ++x )
			{
				for ( var y=0; y<=this.m_size - h; ++y )
				{
					if ( this.IsLegal( x, y, w, h, this.m_curPlayer ) )
					{
						var move = new Object();
						move.x = x;
						move.y = y;
						move.piece = p;
						move.flip = false;
						rval.push( move );
					}
				}
			}
			// And try it flipped?
			if ( h != w )
			{
				w = this.GetPieceHeight(piece);
				h = this.GetPieceWidth (piece);
				for ( var x=0; x<this.m_size - w; ++x )
				{
					for ( var y=0; y<this.m_size - h; ++y )
					{
						if ( this.IsLegal( x, y, w, h, this.m_curPlayer ) )
						{
							var move = new Object();
							move.x = x;
							move.y = y;
							move.piece = p;
							move.flip = true;
							rval.push( move );
						}
					}
				}
			}
		};

		return rval;
	};

	Vitenka.Abstract.IsGameOver = function(_moves)
	{
		if ( !_moves ) _moves = this.GetLegalMoves();
		return 0 == _moves.length;
	};

	Vitenka.Abstract.GameOver = function()
	{
		this.m_gameOver = true;
		//Who won?
		var text = "Game Over\n(No legal moves remain)\n";
		var highestScore = -1;
		var highestPlayers = new Array();
		for ( var p=1; p<=this.m_numPlayers; ++p )
		{
			var score = this.m_players[p].m_score;
			if ( highestScore == score ) highestPlayers.push( p );
			if ( highestScore < score )
			{
				highestPlayers = new Array();
				highestScore = score;
				highestPlayers.push( p );
			}
		}
		
		if ( highestPlayers.length == 1 )
		{
			text += "Player " + highestPlayers[0] + " Won!";
			this.AddToHighScore( highestPlayers[0] );
		}
		else if ( !highestPlayers.length )
		{
			text += "No one won.  That's unpossible!";
		}
		else
		{
			text += "It's a tie between ";
			for ( var i=0; i<highestPlayers.length-1; i++ )
			{
				this.AddHighScore( highestPlayers[i] );
				text += "Player " + highestPlayers[i] + ", ";
			}
			text += "and Player " + highestPlayers[highestPlayers.length-1];
			this.AddToHighScore( highestPlayers[highestPlayers.length-1] );
		}

		alert( text );
	};
	
	Vitenka.Abstract.CreateHighScores = function ( _numPlayers, _id )
	{
		if ( !_id ) _id = this.m_id;
		var o = Vitenka.GetObject ( _id );

		if ( !this.m_highScore )
		{
			this.m_highScore = new Array(5);
			this.m_highScore[1] = 0;
			this.m_highScore[2] = 0;
			this.m_highScore[3] = 0;
			this.m_highScore[4] = 0;
		}

		if ( o )
		{
			var html = "<div id=\"RunningScore\" align=\"center\">\n";

			if ( !_numPlayers ) _numPlayers = 4;
			for ( var i=1; i<=_numPlayers; i++ )
			{
				var col = this.m_players[i].m_colour;

				html += "<div class=\"AbstractGridStyle_Player\" style=\"background-color:"+col+";\">\n";
				html += "Player " + i + "\n";
				html += "<div style=\"div.Abstract_PieceNum\" id=\"" + this.GetHighScoreId(i) + "\">"+this.m_highScore[i]+" wins</div>\n";
				html += "</div>\n";
			}

			html += "</div>\n</div>\n";
			o.innerHTML += html;
		}
	};

	Vitenka.Abstract.AddToHighScore = function ( _playerNum, _amount )
	{
		if ( !_playerNum ) _playerNum = this.m_curPlayer;
		if ( !_amount ) _amount = 1;
		var id = this.GetHighScoreId( _playerNum );
		if ( id )
		{
			var o = Vitenka.GetObject( id );
			if ( o )
			{
				this.m_highScore[_playerNum]++;
				o.innerHTML = "" + this.m_highScore[_playerNum] + " wins";
			}
		}
	};
	
	Vitenka.Abstract.GetHighScoreId = function ( _playerNum )
	{
		if ( !_playerNum || _playerNum < 1 || _playerNum > this.m_numPlayers ) return;
		return this.m_id + "_HighScore_" + _playerNum;
	};

	Vitenka.Abstract.DemoStep = function()
	{
		this.MakeAiMove();
	};

	Vitenka.Abstract.RunDemo = function ( _numPlayers, _size, _delay )
	{
		if ( !_delay ) _delay = 800;

		this.CreateGame( _numPlayers, _size );

		this.m_playingDemo = true;
		for( var i=1; i<=this.m_numPlayers; i++ ) this.m_players[i].m_ai = (i%2)+1;
		clearInterval( this.m_interval )
		this.m_interval = setInterval( "Vitenka.Abstract.DemoStep()", _delay );
	};

	Vitenka.Abstract.StopDemo = function ()
	{
		if ( this.m_playingDemo )
		{
			clearInterval( this.m_interval );
			this.m_playingDemo = false;
		}
	};

	Vitenka.Abstract.CreateGame = function( _numPlayers, _size, _id, _container )
	{
		this.CreatePlayers(_numPlayers, _id, _container );
		this.CreateGrid( _size, _id, _container );
		this.CreateHighScores( _numPlayers, _id );
		this.NextPlayer();
		this.SelectPiece( 0 );
		this.m_playingDemo = false;
		this.m_gameOver = false;
	};

	// And have the flasher be our timer
	clearInterval( this.m_interval )
	this.m_interval = setInterval( "Vitenka.Abstract.Flash()", 500 );
};

