gbMultiplayer = true;
function BG_FancifyText( t, c, space_c, id, bCenterTable )
{
	if (!t) {return '';}
	if (!id) { id=''; }
	if ( !c ) { c = Game.kLetterClass; }
	if ( !space_c ) { space=Game.kLetterSpace;}
	if ( bCenterTable != true ) { bCenterTable = false; }

	var s = 'style="margin-left:' + (bCenterTable?'auto;"':'0px;"');
	var f = '<TABLE border=0 cellpadding=0 cellspacing=0  id="' + id + '" ' + s + '><TR>';
	var tlc = t.toLowerCase();
	var color = 'w';
	for ( var i=0; i<t.length; ++i ) 
	{
		var val = t.charAt(i);
		if ( val != ' ' )
		{
			color = color == 'w' ? 'b' : 'w';
		}
		f += '<TD><DIV class="' + c + (val==' '? ' ' + space_c:'') + '" ' + (val==' '?'': (' style="width:38px;height:38px;position:relative;background-image:url(/img/bg_chip_'+color+'.png)"')) + '><TABLE border=0 cellpadding=0 cellspacing=0 height="100%"><TR><TD style="vertical-align:middle;">' + (val==' '?'&nbsp;':val) + '</TD></TR></TABLE></DIV></TD>';
	}
	f += '</TR></TABLE>';
	return f;
}

Game.FancifyText = function( t, c, space_c, id, bCenterTable )
{
	return BG_FancifyText( t, c, space_c, id, bCenterTable );
};

Game.kTitleLetterClass = 'bg_title_letter';
Game.kLetterClassDisabled= 'bg_title_letter_disabled';
Game.kLetterClassOver 	= 'bg_title_letter_over';
Game.kLetterClassSel 	= 'bg_title_letter_sel';
Game.kLetterClass 		= 'bg_title_letter_link bg_title_letter';
Game.kLetterSpace 		= 'bg_title_letter_link_space';
Game.kTitleLetterSpace 	= 'bg_title_letter_space';
Game.kTitleLeterLinkEmbed='bg_title_letter_link_embeded';
Game.mGameName	= 'BACKGAMMON';

GameVariation.GetTypeName = function ( typeID )
{	
	if ( typeID === undefined ) { typeID = gType; }
	if ( typeID == BackgammonVariation.eType_Classic )	{ return ''; }
};

BackgammonVariation.eType_Classic = 1;

BackgammonVariation.prototype = new GameVariation();
BackgammonVariation.prototype.constructor = BackgammonVariation;
function BackgammonVariation() 
{
	GameVariation.call( this );

	this.mLobbyPage 	= 'games-lobby.pl';
	this.mRoomPage 		= 'backgammon-room.pl';
	this.mGamePage 		= 'backgammon.pl';
	this.mRulesPage		= 'game-rules.pl';
	this.mScoresPage	= 'game-scores.pl';

	this.mID1		= undefined;
	this.mID2		= undefined;
	this.mID3		= undefined;
	
	this.mbTimeable = false;
}

BackgammonVariation.prototype.IsMultiplayerType = function ()
{
	return true;
};
	
BackgammonVariation.prototype.IsMultiplayer = function ()
{
	return true;
};

BackgammonVariation.prototype.GetGameInstanceArgs = function ()
{
	if ( !this.mGameID ) { ErrorOutput('No valid game id for GetGameArgs'); return; }
	
	return GameVariation.prototype.GetGameInstanceArgs.call(this) + '&gid=' + this.mGameID;
};

function ZE_SetupVariation( index, type, name, rulesDivID, id )
{
	if ( index < 0 ) { return; }
	if ( !GameVariation.mVariations ) 
	{ 
		ErrorOutput( 'No variations array setup' ); return; 
	}
	if ( !GameVariation.mVariations[index] ) 
	{ 
		GameVariation.mVariations[index] = new BackgammonVariation(); 
	}
	var v = GameVariation.mVariations[index];

	v.mIndex 		= index;
	v.mType			= type;
	v.mName 		= name;
	v.mElementID	= 'bg_variation_' + name;

	v.mID 			= id;
		
	v.mRulesDivID	= rulesDivID;	
}

function SetConstantSizes(size)
{
	if ( size == 1 )	
	{
		BoardElement.kChipDelta		= 1;
		BoardElement.kChipHeight 	= 19;
		BoardElement.kChipSide		= 5;
		BoardElement.kWidth 		= 17; // point
		BoardElement.kHeight 		= 99;// point
		BoardElement.kPointNumWidth = BoardElement.kWidth + 4;
		BoardElement.kPointNumColor = 'DDBB99';
		BoardBG.kHomeWidth 			= BoardElement.kWidth; //BoardElement.kChipHeight;
		BoardBG.kHomeHeight 		= BoardElement.kHeight;
		BoardBG.kPointNumHomeWidth	= BoardBG.kHomeWidth + 4;
		BoardBG.kFontSize			= 10;
		BoardBG.kBoardPadding		= 4;
		BoardBG.kBoardRowMiddle		= 60; // make bigger than the dice
		Die.kDieWidth 				= 28;
		Die.kDieWidth_Large 		= 42;
		Die.kPipHeight				= 5;
		Die.kPipHeight_Large		= 6;
		DoublingCube.kCubeHeight	= 16; 
	}
	else
	if ( size == 2 )
	{
		BoardElement.kChipDelta		= 2;
		BoardElement.kChipHeight 	= 28;
		BoardElement.kChipSide		= 8;
		BoardElement.kWidth 		= 26; // point
		BoardElement.kHeight 		= 148;// point
		BoardElement.kPointNumWidth = BoardElement.kWidth + 4;
		BoardElement.kPointNumColor = 'DDBB99';//#'E7CFAB';
		BoardBG.kHomeWidth 			= BoardElement.kWidth; //BoardElement.kChipHeight;
		BoardBG.kHomeHeight 		= BoardElement.kHeight
		BoardBG.kPointNumHomeWidth	= BoardBG.kHomeWidth + 4;
		BoardBG.kFontSize			= 11;
		BoardBG.kBoardPadding		= 4;
		BoardBG.kBoardRowMiddle		= 70; // make bigger than the dice
		Die.kDieWidth 				= 39;
		Die.kDieWidth_Large 		= 58;
		Die.kPipHeight				= 6;
		Die.kPipHeight_Large		= 7;
		DoublingCube.kHeight		= 23; 
	}
	else
	{
		BoardElement.kChipDelta		= 3;
		BoardElement.kChipHeight 	= 38;
		BoardElement.kChipSide		= 10;
		BoardElement.kWidth 		= 36; // point
		BoardElement.kHeight 		= 198;// point
		BoardElement.kPointNumWidth = BoardElement.kWidth + 4;
		BoardElement.kPointNumColor = 775522;
		BoardBG.kHomeWidth 			= BoardElement.kWidth; //BoardElement.kChipHeight;
		BoardBG.kHomeHeight 		= BoardElement.kHeight;
		BoardBG.kPointNumHomeWidth	= BoardBG.kHomeWidth + 4;
		BoardBG.kFontSize			= 12;
		BoardBG.kBoardPadding		= 18
		BoardBG.kBoardRowMiddle		= 80; // make bigger than the dice
		Die.kDieWidth 				= 44;
		Die.kDieWidth_Large 		= 62;
		Die.kPipHeight				= 7;
		Die.kPipHeight_Large		= 8;		
		DoublingCube.kHeight		= 31; 
	}
	
}

//-------------------------------------------------------- Backgammon Board Element class --------------------------------------------------------------------------//
BoardElementBG.MapGenericColorToSpecific = function ( color )
{
	return (color == 'A') ? 'b' : 'w';
};

BoardElement.kPadding = 0;
BoardElementBG.prototype = new BoardElement();
BoardElementBG.prototype.constructor = BoardElementBG;
function BoardElementBG( e, row, col )
{
	BoardElement.call( this, e, row, col );
	this.mbMutable = true;
	this.mValue = 0;
	
	this.mChipBaseName = 'bg_chip_';
	this.mChipHeight 	= BoardElement.kChipHeight;
	this.mChipWidth 	= BoardElement.kChipHeight;
	this.mChipColor;
	
	if ( e )
	{
		this.mChipsElement = GetElement( e.id + '_chips' );
		if ( this.mChipsElement )
		{
			this.mChipsElement.innerHTML = '';
		}
	}
}

BoardElementBG.prototype.GetTop = function()
{
	return 0;
};

BoardElementBG.prototype.GetLeft = function()
{
	return 0;
};

BoardElementBG.prototype.SetMutable = function( bOn )
{
	if ( !this.mElement ) { return; }
	
	BoardElement.prototype.SetMutable.call( this, bOn );

//	this.UpdateDisplayState();
};

BoardElementBG.prototype.SetValue = function( val, which, bMutable, bUpdateDisplay )
{
	if ( !which && val ) 				{ return; }
//	if ( !which ) { return; }
	if ( bMutable === undefined ) 		{ bMutable = (val?true:false); }
	if ( bUpdateDisplay === undefined ) { bUpdateDisplay = true; }
	this.mChipColor = which;
	this.mbMutable = true; // make sure it gets reset when SetMutable is called in a few...
	var html;
	if ( bUpdateDisplay )
	{
		html = this.mChipColor ? BoardElementBG.GetHTML_Chips( this, val, this.mChipColor, this.mbUpper ) : '&nbsp;';
	}
	var bSuccess = BoardElement.prototype.SetValue.call( this, val, html );
	this.SetMutable( bMutable );
	return bSuccess;
};

BoardElementBG.prototype.SetHTML = function( html )
{
	if ( html === undefined ) 	{ return; }
	if ( !this.mChipsElement ) 	{ return; } // ErrorOutput( 'BoardElementBG.SetHTML -- either chip element or color is not valid' ); return; }

	this.mChipsElement.innerHTML = html;
	var imgs = this.mChipsElement.getElementsByTagName( 'IMG' );
	for ( var i = 0; i < imgs.length; ++i )
	{
		var img = imgs[i];
		if ( img )
		{
			img.onmousedown = this.mElement.onmousedown;
			img.ondblclick 	= this.mElement.ondblclick;
			img.onmouseover	= this.mElement.onmouseover;
			img.onmouseout	= this.mElement.onmouseout;
		}
	}	
};

BoardElementBG.GetHTML_Chips = function( obj, val, color, bUpper )
{
	var html = '';
	if ( val )
	{
		var w = obj.mChipWidth;
		var h = obj.mChipHeight;
		var d = obj.mChipDelta;
		var overallHeight = (h-d)*val;
		var delta = (h-d);
		if ( overallHeight > BoardElement.kHeight )
		{
			delta = Math.floor( BoardElement.kHeight / (val+1) )+1;
		}
				
		var offset = -1;
		var stuff = obj.mChipBaseName+BoardElementBG.MapGenericColorToSpecific(color); 
		var src = '/img/'+stuff +'.png';
		for ( var i = 0; i < val; ++i )
		{
			html += '<img class="stuff" style="height:'+h+'px; width:'+w+'px; position:absolute; '+(bUpper?'top':'bottom')+':'+offset+'px; right:-1px;" src="'+src+'">';
			offset += delta;
		}
	}
	return html;
};

BoardElementBG.prototype.Select = function ( bSelect )
{
	this.mbSelected = bSelect;
};

BoardElementBG.prototype.OnMouseOver = function ( evt, bValid ) 
{	
	this.mbMouseOver = true;
	this.mbValid = bValid;	
	this.UpdateDisplayState();	
};
	
BoardElementBG.prototype.OnMouseOut = function ( evt ) 
{
	this.mbMouseOver = false;
	this.mbValid = undefined;
	this.UpdateDisplayState();
};

BoardElementBG.prototype.UpdateDisplayState = function()
{
	if ( !this.mElement ) { return; }

	var cname = this.mClassDefault;
	if ( this.mbMouseOver && this.mbValid !== undefined )
	{
		cname = this.mbValid ? this.mClassOver_Valid : this.mClassOver_Invalid;
	}
	else
	if ( this.mbSelected )
	{
		cname = this.mClassSelected;
	}
	this.mElement.style.cursor = (this.mbMutable&&cname!=this.mClassDefault) ? 'pointer' : 'default';
	this.mElement.className = cname;
};


//-------------------------------------------------------- Backgammon board class --------------------------------------------------------------------------//
BoardBG.GetInitialState = function()
{
	var code_1 = 97; // 0x61;
	var code_2 = 65; // 0x41;
	
	var strings = new Array(8);

	strings.push( String.fromCharCode(code_1+1)+'2' );
	strings.push( String.fromCharCode(code_2+6)+'5' );
	strings.push( String.fromCharCode(code_2+8)+'3' );
	strings.push( String.fromCharCode(code_1+12)+'5');
	strings.push( String.fromCharCode(code_2+13)+'5');
	strings.push( String.fromCharCode(code_1+17)+'3');
	strings.push( String.fromCharCode(code_1+19)+'5');
	strings.push( String.fromCharCode(code_2+24)+'2');
																																			
	return strings.join('');
};

BoardBG.kNumRows = 1;
BoardBG.kNumCols = 28; // includes homes/bars
BoardBG.kBlack 		= 'A';
BoardBG.kWhite		= 'a';
BoardBG.kBlackHome 	= 27;
BoardBG.kBlackBar 	= 26;
BoardBG.kWhiteHome 	= 25;
BoardBG.kWhiteBar 	= 0;
BoardBG.kElementIDPrefix = 'bg_board';

BoardBG.prototype = new Board();
BoardBG.prototype.constructor = BoardBG;
function BoardBG( r, c, prefix, bFlipped, factor, parent )
{
	this.mbFlipped = bFlipped;
	this.mElementConstructor = BoardElementBG;
	this.mElementIDPrefix	= prefix;
	this.mBoardFactor = factor;
//	this.mParentElement = parent;
	Board.call( this, r, c, parent );	

// REVISIT -- these ids assume only one board ever exists...

	if ( parent )
	{
		var strings = [];	
		if ( this.mBoardFactor && this.mBoardFactor <= 2 )
		{
			strings.push(				'<DIV id="bg_point_nums_upper" style="padding:1px 0px;">&nbsp;</DIV>' );
		}
		strings.push(					'<DIV style="overflow:hidden; position:relative; border:1px solid #000000; background-color:#211310; padding:'+((this.mBoardFactor && this.mBoardFactor <= 2)?BoardBG.kBoardPadding:1)+'px '+BoardBG.kBoardPadding+'px;">' );
		if ( !this.mBoardFactor || this.mBoardFactor > 2 )
		{
			strings.push(					'<DIV id="bg_point_nums_upper" style="padding:1px 0px;">&nbsp;</DIV>' );
		}
		strings.push(						'<DIV id="bg_board" class="bg_board" style="border:1px solid #000000;"></DIV>');	
	
		if ( !this.mBoardFactor || this.mBoardFactor > 2 )
		{
			strings.push(					'<DIV id="bg_point_nums_lower" style="padding:1px 0px;">&nbsp;</DIV>' );
		}
		strings.push(					'</DIV>' );
		if ( this.mBoardFactor && this.mBoardFactor <= 2 )
		{
			strings.push(				'<DIV id="bg_point_nums_lower" style="padding:1px 0px;">&nbsp;</DIV>' );
		}

		this.mParentElement.innerHTML = strings.join('');
		this.mBoardElement = GetElement( 'bg_board' );
		this.mPointNumsUpperElement = GetElement( 'bg_point_nums_upper' );
		this.mPointNumsLowerElement = GetElement( 'bg_point_nums_lower' );
	}
}

BoardBG.prototype.Init = function( str, bHide )
{
	Board.prototype.Init.call( this, str, bHide ); // constructs and calls InitElement
};

BoardBG.prototype.Show = function( bShow )
{
	Board.prototype.Show.call( this, bShow );
	if ( this.mBoardElement )
	{
		this.mBoardElement.style.visibility = bShow ? 'visible' : 'hidden';
	}
	if ( this.mPointNumsUpperElement )
	{
		this.mPointNumsUpperElement.style.visibility = bShow ? 'visible' : 'hidden';
	}
	
	if ( this.mPointNumsLowerElement )
	{
		this.mPointNumsLowerElement.style.visibility = bShow ? 'visible' : 'hidden';
	}
};

BoardBG.prototype.GetBoardElement = function( index, offset, color )
{
	var bBlack = color == BoardBG.kBlack ? true : false;
	if ( bBlack ) // map it to white coordinates for home and bar
	{
		if ( index == BoardBG.kBlackBar )
		{
			index = BoardBG.kWhiteHome;
		}
		else
		if ( index == BoardBG.kBlackHome )
		{
		 	index = BoardBG.kWhiteBar;
		}
		offset *= -1;
	}
	
	index += offset;
	index = Math.max( Math.min(index, 25), 0 );
	
	if ( bBlack ) // map it back to black coordinates for home and bar
	{
		if ( index == BoardBG.kWhiteHome )
		{
			index = BoardBG.kBlackBar;
		}
		else
		if ( index == BoardBG.kWhiteBar )
		{
			index = BoardBG.kBlackHome;
		}
	}

	return this.GetElement( 0, index );
};


BoardBG.prototype.InitElement = function( obj, row, col, val, bHide )
{
	if ( !obj ) { ErrorOutput( 'Initializing board element without DOM element' ); return; }

	if ( !val ) { val = 0; }

//	DebugOutput( col );
	obj.mPointNum = col;
	obj.mbUpper = (col>=13 && col<=26) ? false : true;
	if ( this.mbFlipped )
	{
		obj.mbUpper = !obj.mbUpper;
	}
	
	obj.mChipHeight	= BoardElement.kChipHeight;
	obj.mChipDelta = BoardElement.kChipDelta;
	if ( col == 0 || col > 24 ) // bar or home
	{
		obj.mClassDefault 		= 'bg_board_home_zone';
		obj.mClassOver_Valid 	= 'bg_board_home_zone_over';
		obj.mClassOver_Invalid 	= 'bg_board_home_zone_over_invalid';
		obj.mClassSelected		= 'bg_board_home_zone_sel';
		if ( col == BoardBG.kBlackHome || col == BoardBG.kWhiteHome )
		{
			obj.mChipBaseName		= 'bg_chip_side_';
			obj.mChipHeight			= BoardElement.kChipSide; 
			obj.mChipDelta			= 0;
		}
	}
	else
	{
		obj.mClassDefault		= obj.mbUpper ? 'bg_point_upper' : 'bg_point_lower';
		obj.mClassOver_Valid 	= 'bg_point_over' ;
		obj.mClassOver_Invalid 	= 'bg_point_over_invalid';
		obj.mClassSelected		= obj.mClassDefault + '_sel';
	}
	
	Board.prototype.InitElement.call( this, obj, row, col, val, bHide );
};

BoardBG.prototype.RemapPoint = function( val, color )
{
	if ( color == BoardBG.kWhite && val>0 && val<25 ) { val = 24 - val + 1; }
	return val;
};

BoardBG.prototype.MoveChip = function( from, to )
{
	if ( !from ) 	{ ErrorOutput( 'Calling BoardBG.MoveChip with no object' ); return; }
	if ( !to )		{ ErrorOutput( 'MoveChip -- No destination!' ); return; }

	if ( to.GetValue() == 1 && to.mChipColor != from.mChipColor ) // Will a chip get hit?
	{
//		var opp = this.mMe == this.mPlayers[ PlayerBG.kIndex_Black ] ? this.mPlayers[ PlayerBG.kIndex_White ] : this.mPlayers[ PlayerBG.kIndex_Black ];
//		if ( !opp ) { ErrorOutput( 'No opponent?' ); this.FatalError(); return; }

		var otherColor = to.mChipColor;
		to.SetValue( 0 );
		var bar = otherColor == BoardBG.kBlack ? BoardBG.kBlackBar : BoardBG.kWhiteBar;
		bar = this.GetElement( 0, bar );
		if ( bar )
		{
			bar.SetValue( bar.GetValue()+1, otherColor, false );
		}
		else
		{
			ErrorOutput( 'No bar found for moving chip to from being hit: otherColor=' + otherColor );
		}	
	}

	
	var val = from.mValue-1;
	var color = from.mChipColor;
	this.OnMouseOut( undefined, from.mElement );
	from.Select( true );
	if ( !this.SetValue( from, val, color ) )
	{ 
		ErrorOutput( 'BoardBG.MoveChip -- unable to set value for obj' );  // might not be mutable
		from.Select( false );
		return; 
	}
	
	to.mbValid = undefined;
	this.OnMouseOut( undefined, to.mElement );
	to.SetMutable( true );
	to.Select( true );
	if ( !this.SetValue( to, to.mValue+1, color ) )	
	{ 
		this.SetValue( from, val+1, color ); // restore if the above fails
		// REVISIT -- need to reset mutable and selected?
		ErrorOutput( 'BoardBG.MoveChip -- unable to set value for other' );  // might not be mutable
		return; 
	}
		
	return true;
};

BoardBG.prototype.SetValue = function( obj, val, color )
{
	if ( !obj ) { ErrorOutput( 'SetValue -- no valid obj' ); return; }
	if ( !obj.mbMutable ) { ErrorOutput( 'SetValue -- obj not mutable' ); return; }
	
	obj.SetValue( val, color );	
	return true;
};

BoardBG.ParsePointNum = function( chrPointNum )
{
	var color;
	var pointNum = chrPointNum.charCodeAt( 0 );
	if ( pointNum > 90 ) // 0x5A == 'Z'
	{
		pointNum -= 97; // 0x61
		color = BoardBG.kWhite;
	}
	else
	{
		pointNum -= 65; // 0x41;
		color = BoardBG.kBlack;
	}
	if ( (pointNum==BoardBG.kWhiteBar || pointNum==BoardBG.kWhiteHome) && color == BoardBG.kBlack )
	{	
		pointNum = pointNum==BoardBG.kWhiteBar ? BoardBG.kBlackHome : BoardBG.kBlackBar;
	}
	return {mColor:color, mPointNum:pointNum};
};

BoardBG.ParseNum = function( chrNum )
{
	var num = chrNum.charCodeAt(0); // numChips or howMuch
	if ( num >= 97 ) // 0x61, lowercase letter, treat as hex
	{
		num -= 87;
	}
	else
	if ( num >= 65 ) // 0x41, uppercase letter, treat as hex
	{
		num -= 55; // A==10, B==11, etc.
	}
	else
	{
		num -= 48; //0x30;
	}
	return num;
};


BoardBG.prototype.GetState = function() // need to remap black bar and black home
{
	var stateStr = '';	
	for ( var i = 0; i <= BoardBG.kBlackHome; ++i )
	{
		var obj = this.GetElement( 0,i );
		if ( !(obj && obj.GetValue()) ) { continue; }
		
		var point = obj.mPointNum;
		if ( i > BoardBG.kWhiteHome )
		{
			point = i==BoardBG.kBlackHome ? BoardBG.kWhiteBar : BoardBG.kWhiteHome;
		}
		
		var colorOffset = obj.mChipColor == BoardBG.kBlack ? 65 : 97;
		point += colorOffset;
		var val = obj.GetValue() + 48;
		val = (val < 65) ? val : (val+55);
		stateStr +=  String.fromCharCode(point) + String.fromCharCode(val);
	}
	return stateStr;
};

BoardBG.prototype.SetState = function( str, myColor )
{
	if ( !str ) { return; }
//	DebugOutput( str );

	var msg = '';
	for ( var index = 0; index < str.length-1; index+=2 )
	{
//		DebugOutput( str[index] );
		var point_color = BoardBG.ParsePointNum( str.charAt(index) );	

		var pointNum = point_color.mPointNum;
		var color = point_color.mColor;
		var numChips = BoardBG.ParseNum( str.charAt(index+1) );
		
		var obj = this.GetElement( 0, pointNum );
		if ( obj && obj.mPointNum == pointNum )
		{			
			obj.SetValue( numChips, color, color==myColor );
//			msg += 'Setting value: pointNum=' + pointNum  +', row=' + i + ', col=' + j + ' with num=' + num + ', color=' + color; // REVISIT -- I.E. can't handle this output?
		}
		else
		{
			ErrorOutput( obj ? ('Setting board state but point num of element doesn\'t match point num of element in string: pointNum=' + pointNum + ', obj.mPointNum=' + obj.mPointNum) : 'Invalid object at pointNum=' + pointNum );
		}
	}

//	if ( msg )	{ DebugOutput( msg ); }	
};

BoardBG.prototype.OnMouseOver = function( evt, eSrc, others )
{
	if ( !(eSrc && eSrc.mBoardElement && eSrc.mBoardElement.mPointNum !== undefined) ) 	{ return; }
	if ( !(others && others.length) )													{ return; }

	this.mMouseOverOthers = others;

	// first one in others determine validity for eSrc
	var bValid;
	for ( var i = 0; i < others.length; ++i )
	{
		var obj = others[i];
		if ( obj )
		{
			var other = obj.mOther;
			if ( other.mElement == eSrc || other.mPointNum === undefined ) { continue; }
			other.OnMouseOver( evt, obj.mbValid );
			if ( bValid === undefined )
			{
				bValid = obj.mbValid;
			}
		}
		else
		{
			ErrorOutput( 'BoardBG.OnMouseOver -- no valid other at index=' + i );
		}
	}
	
	eSrc.mBoardElement.OnMouseOver( evt, bValid );
};

BoardBG.prototype.OnMouseOut = function( evt, eSrc )
{
	if ( !(eSrc && eSrc.mBoardElement && eSrc.mBoardElement.mPointNum !== undefined) ) 	{ return; }
	
	eSrc.mBoardElement.OnMouseOut( evt );
	if ( this.mMouseOverOthers )
	{
		for ( var i = 0; i < this.mMouseOverOthers.length; ++i )
		{
			var obj = this.mMouseOverOthers[i];
			if ( obj )
			{
				var other = obj.mOther;
				if ( other.mElement == eSrc || other.mPointNum === undefined ) { continue; }
				other.OnMouseOut( evt );
			}
			else
			{
				ErrorOutput( 'BoardBG.OnMouseOut -- no valid other at index=' + i );
			}
		}
		this.mMouseOverOthers = undefined;
	}
};

BoardBG.prototype.CreateBoardHTML = function( cubeObj, bPlayerFlipped )
{
	var boardFactor = this.mBoardFactor;
	var pointNumsUpperElement = this.mPointNumsUpperElement;
	var pointNumsLowerElement = this.mPointNumsLowerElement;
	var e = this.mBoardElement;
	if ( !e ) { return; }
	
	var bFlipped 		= this.mbFlipped;
	var cubeValue 		= cubeObj ? cubeObj.mValue : undefined;
	var cubeHeight 		= DoublingCube.kHeight;
	
	e.style.visibility = 'visible';
		
	var html = new Array( 50 );
	html.push( '<TABLE border=0 cellpadding=0 cellspacing=0>' );

	var style 	= ' style="width:'+BoardElement.kWidth+'px; position:relative; height:'+BoardBG.kHomeHeight+'px;"'; 
	var homeStyle = ' style="width:'+(BoardBG.kHomeWidth)+'px; position:relative; height:'+BoardBG.kHomeHeight+'px;"'; 
	
	var black 	= BoardElementBG.MapGenericColorToSpecific(BoardBG.kBlack);
	var white 	= BoardElementBG.MapGenericColorToSpecific(BoardBG.kWhite);
	
	var start 	= bFlipped ? 13 : 1;
	var end 	= bFlipped ? 25 : 13;
	var half 	= bFlipped ? 18 : 6;
	
	var pointClass = 'bg_point_upper';
	
	var numStyle		= ' style="width:'+(BoardElement.kPointNumWidth)+'px;"';
	var htmlPointNums 	= '<TABLE border=0 cellpadding=0 cellspacing=0 style="color:#'+BoardElement.kPointNumColor+'; font-size:'+BoardBG.kFontSize+'px; line-height:'+BoardBG.kFontSize+'px; font-weight:bold;""><TR>';
	var	htmlPointNumHome= '<TD style="width:'+(BoardBG.kPointNumHomeWidth)+'px;">&nbsp;</TD>';

	var cube = '';
	if ( cubeValue )
	{
		var cubeStyle = 'width:'+cubeHeight+'px; height:'+cubeHeight+'px; line-height:'+cubeHeight+'px;';
		cube = '<DIV style="position:relative;"><DIV id="bg_doubling_cube" class="bg_cube" style="'+cubeStyle+'"></DIV></DIV>';
	}
	
	var counter = 12;
	// row 0
	html.push( 	'<TR><TD id='+ (BoardBG.kElementIDPrefix + '_left_opponent') +' style="width:'+BoardBG.kPointNumHomeWidth+'px;" class="bg_board_home_zone"><DIV'+homeStyle+'></DIV></TD>' );
	htmlPointNums += htmlPointNumHome;
	for ( var cols = start; cols < end; ++cols )
	{
		img = (cols%2) ? white : black;
		if ( bFlipped )
		{
			img = img == white ? black : white;
		}
		img = '/img/bg_point_' + img + '_flip'+((boardFactor&&boardFactor<=2)?('_'+boardFactor):'')+'.png';
		
		var index = bFlipped ? cols : (end-cols);
		var id = BoardBG.kElementIDPrefix + '0-' + index;
		//DebugOutput(id);
		html.push( '<TD class="'+pointClass+'" style="background-image:url('+img+');"><DIV id=' + id  + style+'><DIV id="'+id+'_chips"'+style+'>&nbsp;</DIV></DIV></TD>' ); 
//		htmlPointNums += '<TD'+numStyle+'>'+index+'</TD>';
		htmlPointNums += '<TD'+numStyle+'>'+(bPlayerFlipped?counter--:++counter)+'</TD>';
		if ( cols == half )
		{
			id = BoardBG.kElementIDPrefix + '0-' +(bFlipped?BoardBG.kBlackBar:BoardBG.kWhiteBar);
			html.push( '<TD rowspan=2 class="bg_board_home_zone" style="border-bottom:1px solid #5D3030;"><DIV id='+ id +homeStyle+'><DIV id="'+id+'_chips"'+style+'>&nbsp;</DIV></DIV></TD>' );
			htmlPointNums += htmlPointNumHome;
		}
	}
	id = BoardBG.kElementIDPrefix + '0-' + (bFlipped?BoardBG.kWhiteHome:BoardBG.kBlackHome);
	html.push( '<TD class="bg_board_home_zone" style="vertical-align:top;"><DIV id='+ id +homeStyle+'><DIV id="'+id+'_chips"'+style+'>&nbsp;</DIV></DIV></TD></TR>' );
	htmlPointNums += htmlPointNumHome;

	if ( pointNumsUpperElement )
	{
		pointNumsUpperElement.innerHTML = htmlPointNums + '</TR></TABLE>';
	}
	htmlPointNums = '<TABLE border=0 cellpadding=0 cellspacing=0 style="color:#'+BoardElement.kPointNumColor+'; font-size:'+BoardBG.kFontSize+'px; line-height:'+BoardBG.kFontSize+'px; font-weight:bold;"><TR>';

	var diceLeft 	= BoardBG.kElementIDPrefix + 'left_dice_';
	var diceRight 	= BoardBG.kElementIDPrefix + 'right_dice_';
	
	var rollLeft 	= '<DIV style="z-index:500;" id="'+BoardBG.kElementIDPrefix + 'roll_left"></DIV> ';
	var rollRight 	= '<DIV style="z-index:500;" id="'+BoardBG.kElementIDPrefix + 'roll_right"></DIV> ';
	
	// row 1
	html.push( '<TR><TD rowspan=2 class="bg_board_home_count" style="border-top:1px solid #5D3030;border-bottom:1px solid #5D3030;height:'+BoardBG.kBoardRowMiddle+'px;">'+cube+'</TD>' );
	html.push(		'<TD colspan=6 rowspan=2><TABLE id="'+BoardBG.kElementIDPrefix+'_dice_table_left" border=0 cellpadding=0 cellspacing=0><TR style="height:'+Die.kDieWidth+'px;"><TD id="'+(diceLeft+'1')+'" style="width:'+Die.kDieWidth+'px;"></TD><TD id="'+(diceLeft+'2')+'" style="width:'+Die.kDieWidth+'px;"></TD></TR></TABLE>'+rollLeft+'</TD>' );
	html.push( 		'<TD colspan=6 rowspan=2><TABLE id="'+BoardBG.kElementIDPrefix+'_dice_table_right" border=0 cellpadding=0 cellspacing=0><TR style="height:'+Die.kDieWidth+'px;"><TD id="'+(diceRight+'1')+'" style="width:'+Die.kDieWidth+'px;"></TD><TD id="'+(diceRight+'2')+'" style="width:'+Die.kDieWidth+'px;"></TD></TR></TABLE>'+rollRight+'</TD>' );
	id = BoardBG.kElementIDPrefix + 'count-' +(bFlipped?BoardBG.kWhiteHome:BoardBG.kBlackHome);
	html.push( 	'<TD id='+id+' class="bg_board_home_count" style="vertical-align:top; border-top:1px solid #5D3030;"></TD></TR>' );
	
	// row 2
	html.push( '<TR>' ); //<TD class="bg_board_home_count" style="border-bottom:1px solid #5D3030;">&nbsp;</TD>' );
	id = BoardBG.kElementIDPrefix + '0-' + (bFlipped?BoardBG.kWhiteBar:BoardBG.kBlackBar);
	html.push( 		'<TD rowspan=2 class="bg_board_home_zone"><DIV id='+ id +homeStyle+'><DIV id="'+id+'_chips"'+style+'>&nbsp;</DIV></DIV></TD>' );
	id = BoardBG.kElementIDPrefix + 'count-' +(bFlipped?BoardBG.kBlackHome:BoardBG.kWhiteHome);
	html.push( 		'<TD id='+id+' class="bg_board_home_count" style="vertical-align:bottom; border-bottom:1px solid #5D3030;"></TD></TR>' );

	start = bFlipped ? 1 : 13;
	end = bFlipped ? 13 : 25;
	pointClass = 'bg_point_lower';

	half = bFlipped ? 6 : 18;

	var counter = 13;
	// row 3
	html.push( 	'<TR><TD id='+ (BoardBG.kElementIDPrefix + '_left_my') +' class="bg_board_home_zone"><DIV'+homeStyle+'>&nbsp;</DIV></TD>' );
	htmlPointNums += htmlPointNumHome;
	for ( var cols = start; cols < end; ++cols )
	{
		img = (cols%2) ? black : white;
		if ( bFlipped )
		{
			img = img == white ? black : white;
		}
		img = '/img/bg_point_' + img +((boardFactor&&boardFactor<=2)?('_'+boardFactor):'')+'.png';
							
		var index = bFlipped ? (end-cols) : cols;
		var id = BoardBG.kElementIDPrefix + '0-' + index;
		html.push( '<TD class="'+pointClass+'" style="background-image:url('+img+');"><DIV id=' + id  + style+'><DIV id="'+id+'_chips"'+style+'>&nbsp;</DIV></DIV></TD>' ); 
//		htmlPointNums += '<TD'+numStyle+'>'+index+'</TD>';
		htmlPointNums += '<TD'+numStyle+'>'+(bPlayerFlipped?counter++:--counter)+'</TD>';
		if ( cols == half )
		{
			htmlPointNums += htmlPointNumHome;
		}
	}

	id = BoardBG.kElementIDPrefix + '0-' +(bFlipped?BoardBG.kBlackHome:BoardBG.kWhiteHome);
	html.push(	'<TD class="bg_board_home_zone" style="vertical-align:bottom;"><DIV id='+id+homeStyle+'><DIV id="'+id+'_chips"'+style+'>&nbsp;</DIV></DIV></TD></TR>' );
	htmlPointNums += htmlPointNumHome;

	if ( pointNumsLowerElement )
	{
		pointNumsLowerElement.innerHTML = htmlPointNums + '</TR></TABLE>';
	}

	html.push( '</TABLE>' );
	e.innerHTML	= html.join('');
//	e.style.visibility = 'visible';

	if ( cubeObj )
	{
		cubeObj.mElement = GetElement( 'bg_doubling_cube' );
	}
};

DieBG.prototype = new Die();
DieBG.prototype.constructor = DieBG;
function DieBG( el ) 
{
	Die.call( this, el );
}

DieBG.prototype.Set = function( val, color, pipColor, bActive )
{
	var dieClass = 'bg_die';
	var pipClass = 'bg_pip';
	var w = Die.kDieWidth;
	if ( bActive )
	{
		dieClass += '_lg';
	}

	dieClass += '_' +BoardElementBG.MapGenericColorToSpecific(color);
	pipClass += '_' +BoardElementBG.MapGenericColorToSpecific(pipColor);

	Die.prototype.Set.call( this, val, color, pipColor, dieClass, pipClass, bActive );
};


function DoublingCube( v )
{
	this.mValue		= v;
	this.mElement;
}
DoublingCube.kHeight = 16;
