/**************************************************************************
	Copyright (c) 2002 Geir Landrö (drop@destroydrop.com)
	dropMine (Minesweeper game) - www.destroydrop.com/javascripts/mine/
	Version 0.5
**************************************************************************/

// Contains the status for each cell
function cell()
{
	this.exposed		= false;
	this.flagged		= false;
	this.mine				= false;
	this.minesnear	= 0;
}

// The game object
function dropmine(rows, cols, mines)
{
	this.rows				= rows || 9;
	this.cols				= cols || 9;
	this.mines			= mines || 10;
	
	this.currR			= -1;
	this.currC			= -1;
	this.minesleft	= mines || 10;
	
	this.gameon			= true;
	this.firstclick	= false;
	
	this.timer			= 0;
	this.timerid;

	this.grid				= new Array();
	
	// Icon arrays
	this.icons			= new Array(14);
	this.ledicons		= new Array(8);
	this.faceicons	= new Array(4);


	// Starts the game
	this.run = function()
	{
		this.PreloadIcons();
		this.CreateGrid();
		this.PlaceMines();
		
		this.WriteGrid();
	}


	// Loads all icons that are used
	this.PreloadIcons = function()
	{
		// preload icons for cells
		this.icons[0] = new Image();
		this.icons[0].src = "img/cell_0.gif";
		this.icons[1] = new Image();
		this.icons[1].src = "img/cell_1.gif";
		this.icons[2] = new Image();
		this.icons[2].src = "img/cell_2.gif";
		this.icons[3] = new Image();
		this.icons[3].src = "img/cell_3.gif";
		this.icons[4] = new Image();
		this.icons[4].src = "img/cell_4.gif";
		this.icons[5] = new Image();
		this.icons[5].src = "img/cell_5.gif";
		this.icons[6] = new Image();
		this.icons[6].src = "img/cell_6.gif";
		this.icons[7] = new Image();
		this.icons[7].src = "img/cell_7.gif";
		this.icons[8] = new Image();
		this.icons[8].src = "img/cell_8.gif";
		this.icons[9] = new Image();
		this.icons[9].src = "img/cell_mine.gif";
		this.icons[10] = new Image();
		this.icons[10].src = "img/cell_mine_click.gif";
		this.icons[11] = new Image();
		this.icons[11].src = "img/cell_flag.gif";
		this.icons[12] = new Image();
		this.icons[12].src = "img/cell_click.gif";
		this.icons[13] = new Image();
		this.icons[13].src = "img/cell.gif";
		this.icons[14] = new Image();
		this.icons[14].src = "img/cell_flag_wrong.gif";

		// preload the icons for timer, and mines left
		this.ledicons[0] = new Image();
		this.ledicons[0].src = "img/time_0.gif";
		this.ledicons[1] = new Image();
		this.ledicons[1].src = "img/time_1.gif";
		this.ledicons[2] = new Image();
		this.ledicons[2].src = "img/time_2.gif";
		this.ledicons[3] = new Image();
		this.ledicons[3].src = "img/time_3.gif";
		this.ledicons[4] = new Image();
		this.ledicons[4].src = "img/time_4.gif";
		this.ledicons[5] = new Image();
		this.ledicons[5].src = "img/time_5.gif";
		this.ledicons[6] = new Image();
		this.ledicons[6].src = "img/time_6.gif";
		this.ledicons[7] = new Image();
		this.ledicons[7].src = "img/time_7.gif";
		this.ledicons[8] = new Image();
		this.ledicons[8].src = "img/time_8.gif";
		this.ledicons[9] = new Image();
		this.ledicons[9].src = "img/time_9.gif";
		this.ledicons[10] = new Image();
		this.ledicons[10].src = "img/time_minus.gif";

		// preload the icons for the face
		this.faceicons[0] = new Image();
		this.faceicons[0].src = "img/face_0.gif";
		this.faceicons[1] = new Image();
		this.faceicons[1].src = "img/face_1.gif";
		this.faceicons[2] = new Image();
		this.faceicons[2].src = "img/face_2.gif";
		this.faceicons[3] = new Image();
		this.faceicons[3].src = "img/face_3.gif";
		this.faceicons[4] = new Image();
		this.faceicons[4].src = "img/face_4.gif";
	}


	// Creates the grid
	this.CreateGrid = function()
	{
		for (n=0;n<this.rows;n++)
		{
			this.grid[n] = new Array();
			for (k=0;k<this.cols;k++)
			{
				this.grid[n][k] = new cell();  // Create an instance of the cell struct for each location in the grid
			}
		}
	}


	// Places the mines on the grid
	this.PlaceMines = function()
	{
		for (n=0;n<this.mines;n++)
		{
			nR = Math.floor(Math.random()*(this.rows-1))
			nC = Math.floor(Math.random()*(this.cols-1))

			if (!this.grid[nR][nC].mine)
			{
				this.grid[nR][nC].mine = true;

				// Adds +1 to cells that lie next to the mine
				if ( nR != this.rows)
				{
					this.grid[nR+1][nC].minesnear++;
					if (nC != 0)
						this.grid[nR+1][nC-1].minesnear++;
					if (nC != this.cols)
						this.grid[nR+1][nC+1].minesnear++;
				}

				if (nR != 0)
				{
					this.grid[nR-1][nC].minesnear++;
					if (nC != 0)
						this.grid[nR-1][nC-1].minesnear++;
					if (nC != this.cols)
						this.grid[nR-1][nC+1].minesnear++;
				}

				if (nC != 0)
					this.grid[nR][nC-1].minesnear++;
				if (nC != this.cols)
					this.grid[nR][nC+1].minesnear++;

			}
			else // Already a mine at this location, find another one
				--n;
		}
		this.minesleft = this.mines;
	}


	// Outputs the grid
	this.WriteGrid = function()
	{
		var strOut = '';
		strOut += this.WriteTopLayout();
		strOut += '<table id="grid" cellspacing="0">';
		for (n=0;n<this.rows;n++)
		{
			strOut += '<tr>';
			for(k=0;k<this.cols;k++)
			{
				strOut += '<td onmousedown="javascript: mine.CellDown(' + n + ', ' + k + ');this.oncontextmenu=mine.CRC;" onmouseup="javascript: mine.CellUp(' + n + ', ' + k + ');" onmouseout="javascript: mine.CellUp(' + n + ', ' + k + ');" onclick="mine.CellCheck(' + n + ', ' + k + ');">';
				strOut += '<img id="' + n + '_' + k + '" src="img/cell.gif" width="16" height="16" border="0" />';
				strOut += '</td>';
			}
			strOut += '</tr>';
		}
		strOut += '</table>';
		strOut += this.WriteBottomLayout();
		
		document.write(strOut);
		this.MineCount();
	}

	// Restarts the game, sets all vars to default
	this.Restart = function()
	{
		for (n=0;n<this.rows;n++)
		{
			for (k=0;k<this.cols;k++)
			{
				this.grid[n][k].exposed		= false;
				this.grid[n][k].flagged		= false;
				this.grid[n][k].mine			= false;
				this.grid[n][k].minesnear	= 0;
				imgId = document.getElementById(n+'_'+k);
				imgId.src = this.icons[13].src;
			}
		}
		this.currR			= -1;
		this.currC			= -1;
		this.minesleft	= this.mines;
		this.gameon			= true;
		this.firstclick	= false;
		this.timer			= 0;

		this.PlaceMines();
		this.MineCount();
		this.stopTimer();
		this.ClearTimer();
	}


	// The look of the game (top part)
	this.WriteTopLayout = function()
	{
		var strOut = '';
		strOut += '<table id="dropmine" cellspacing="0"><tr><td><table id="leds" cellspacing="0"><tr>';
		strOut += '<td><div class="time"><img id="m1" src="img/time_0.gif" width="13" height="23" border="0"><img id="m2" src="img/time_0.gif" width="13" height="23" border="0"><img id="m3" src="img/time_0.gif" width="13" height="23" border="0"></div></td>';
		strOut += '<td onclick="javascript: mine.Restart();" onmousedown="javascript: mine.FaceDown();" onmouseup="javascript: mine.FaceUp();" align="center"><img id="f" src="img/face_0.gif" width="26" height="26" border="0"></td>';
		strOut += '<td align="right"><div class="time"><img id="t1" src="img/time_0.gif" width="13" height="23" border="0"><img id="t2" src="img/time_0.gif" width="13" height="23" border="0"><img id="t3" src="img/time_0.gif" width="13" height="23" border="0"></div></td>';
		strOut += '</tr></table>';
		return strOut;
	}


	// The look of the game (bottom part)
	this.WriteBottomLayout = function()
	{
		var strOut = '';
		strOut += '</td></tr></table>';
		return strOut;
	}


	// When the user clicks the face
	this.FaceDown = function()
	{
			var faceID	= document.getElementById('f');
			faceID.src	= this.faceicons[4].src;
	}


	// When the user clicks the face
	this.FaceUp = function()
	{
			var faceID	= document.getElementById('f');
			faceID.src	= this.faceicons[0].src;
	}


	// When cell is clicked, change face and cell image
	this.CellDown = function(nR, nC)
	{
		if (this.gameon)
		{
			if (!this.grid[nR][nC].exposed && !this.grid[nR][nC].flagged)
			{
				var imgID		= document.getElementById(nR + '_' + nC);
				var faceID	= document.getElementById('f');
				imgID.src		= this.icons[12].src;
				faceID.src	= this.faceicons[1].src;
			}
			this.currR = nR;
			this.currC = nC;
		}
	}
	
	
	// On mousebutton up, change face pic to same if game still on
	this.CellUp = function(nR, nC)
	{
		if (this.gameon)
		{
			var faceID	= document.getElementById('f');
			faceID.src	= this.faceicons[0].src;
			if (!this.grid[nR][nC].exposed && !this.grid[nR][nC].flagged)
			{
				var imgID		= document.getElementById(nR + '_' + nC);
				imgID.src		= this.icons[13].src;
			}
		}
	}


	// Checks the cell that was clicked on
	this.CellCheck = function(nR, nC)
	{
		if (this.gameon)
		{
			if (!this.firstclick)
			{
				this.firstclick = true;
				this.startTimer();
			}
		
			currCell	= this.grid[nR][nC];

			// If the current cell is not exposed
			if (!currCell.exposed && !currCell.flagged)
			{
				currCell.exposed = true;
				imgID = document.getElementById(nR + '_' + nC);

				// If the current cell is a mine
				if (currCell.mine)
				{
					imgID.src = this.icons[10].src;
					var faceID	= document.getElementById('f');
					faceID.src	= this.faceicons[2].src;

					this.showAllMines(false);
				}
				else
				{
					imgID.src = this.icons[currCell.minesnear].src;
					this.grid[nR][nC].exposed = true;

					if (currCell.minesnear == 0)
						this.showLinkedBlanks(nR, nC);
				}

				this.CheckWin();
			}
		}
	}


	// Check if the user has exposed every cell, except the ones that contain mines
	this.CheckWin = function()
	{
		if (this.gameon)
		{
			var nCount = 0;
			for (n=0;n<this.rows;n++)
			{
				for (k=0;k<this.cols;k++)
				{
					if (this.grid[n][k].exposed)
						nCount++;
				}
			}
			if (nCount == this.rows*this.cols-this.mines)
			{
				this.gameon = false;
				this.minesleft = 0;
				this.MineCount();
				this.showAllMines(true);
				var faceID	= document.getElementById('f');
				faceID.src	= this.faceicons[3].src;
			}
		}
	}


	// Checks if the location is within the grid
	this.inGrid = function(r,c)
	{
		if (r > (this.rows-1) || r < 0 || c > (this.cols-1) || c < 0)
			return false;
		return true;
	}


	// Shows all blank cells that lie next to the blank cell that was clicked on
	this.showLinkedBlanks = function(nR, nC)
	{
		if (this.inGrid((nR+1), nC) && !this.grid[(nR+1)][nC].exposed)
			this.CellCheck((nR+1),nC);

		if (this.inGrid((nR+1), (nC-1)) && !this.grid[(nR+1)][(nC-1)].exposed)
			this.CellCheck((nR+1),(nC-1));

		if (this.inGrid((nR+1), (nC+1)) && !this.grid[(nR+1)][(nC+1)].exposed)
			this.CellCheck((nR+1),(nC+1));

		if (this.inGrid((nR-1), nC) && !this.grid[(nR-1)][nC].exposed)
			this.CellCheck((nR-1),nC);

		if (this.inGrid((nR-1), (nC-1)) && !this.grid[(nR-1)][(nC-1)].exposed)
			this.CellCheck((nR-1),(nC-1));

		if (this.inGrid((nR-1), (nC+1)) && !this.grid[(nR-1)][(nC+1)].exposed)
			this.CellCheck((nR-1),(nC+1));

		if (this.inGrid(nR, (nC-1)) && !this.grid[nR][(nC-1)].exposed)
			this.CellCheck(nR,(nC-1));

		if (this.inGrid(nR, (nC+1)) && !this.grid[nR][(nC+1)].exposed)
			this.CellCheck(nR,(nC+1));
	}


	// Show/flag all mines
	this.showAllMines = function(win)
	{
		for (n=0;n<this.rows;n++)
		{
			for (k=0;k<this.cols;k++)
			{
				if (!this.grid[n][k].mine  && this.grid[n][k].flagged)
				{
					imgID = document.getElementById(n + '_' + k);
					imgID.src = this.icons[14].src;
				}
				if (this.grid[n][k].mine  && !this.grid[n][k].flagged)
				{
					imgID = document.getElementById(n + '_' + k);
					if (win)
						imgID.src = this.icons[11].src;
					else
					{
						if (!this.grid[n][k].exposed)
							imgID.src = this.icons[9].src;
					}
				}	
			}
		}
		this.gameon = false;
		this.stopTimer();
	}

	
	// When the user right clicks the cell is flagged
	this.CellRightClick = function()
	{
		if (this.gameon)
		{
			if (!this.grid[this.currR][this.currC].exposed)
			{
				imgID = document.getElementById(this.currR + '_' + this.currC)
				if (!this.grid[this.currR][this.currC].flagged)
				{
					this.grid[this.currR][this.currC].flagged = true;
					imgID.src = this.icons[11].src;
					this.minesleft--;
				}
				else
				{
					this.grid[this.currR][this.currC].flagged = false;
					imgID.src = this.icons[13].src;
					this.minesleft++;
				}
				this.MineCount();
			}
		}
	}


	// Right click calls this function (is somehow outside the object??)
	this.CRC = function()
	{
		mine.CellRightClick();
		return false;
	}


	// Displays how many mines are left
	this.MineCount = function()
	{
		var m1 = document.getElementById('m1');
		var m2 = document.getElementById('m2');
		var m3 = document.getElementById('m3');

		if (this.minesleft<-99)
		{
			alert('Stop it!  :)');
		}
		else if (this.minesleft<=-10)
		{
			m1.src = this.ledicons[10].src;
			m2.src = this.ledicons[-((this.minesleft%100)-(this.minesleft%10))/10].src;
			m3.src = this.ledicons[-(this.minesleft%10)].src;
		}
		else if (this.minesleft<0)
		{
			m1.src = this.ledicons[0].src;
			m2.src = this.ledicons[10].src;
			m3.src = this.ledicons[-this.minesleft].src;
		}
		else if (this.minesleft>=0 && this.minesleft<10)
		{
			m1.src = this.ledicons[0].src;
			m2.src = this.ledicons[0].src;
			m3.src = this.ledicons[this.minesleft].src;
		}
		else if (this.minesleft>=10 && this.minesleft<100)
		{
			m1.src = this.ledicons[0].src;
			m2.src = this.ledicons[((this.minesleft%100)-(this.minesleft%10))/10].src;
			m3.src = this.ledicons[(this.minesleft%10)].src;
		}
		else if (this.minesleft>=100 && this.minesleft<999)
		{
			m1.src = this.ledicons[((this.minesleft%1000)-(this.minesleft%100))/100].src;
			m2.src = this.ledicons[((this.minesleft%100)-(this.minesleft%10))/10].src;
			m3.src = this.ledicons[(this.minesleft%10)].src;
		}
	}


	// Starts the timer
	this.startTimer = function()
	{
		this.timerid = setInterval('mine.Timer()',1000);
	}


	// Stops the timer
	this.stopTimer = function()
	{
		clearInterval(this.timerid);
	}


	// Displays images according to the timer
	this.Timer = function()
	{
		this.timer++;
		var t1 = document.getElementById('t1');
		var t2 = document.getElementById('t2');
		var t3 = document.getElementById('t3');

		if (this.timer<10)
		{
			t1.src = this.ledicons[0].src;
			t2.src = this.ledicons[0].src;
			t3.src = this.ledicons[this.timer].src;
		}
		else if (this.timer>=10 && this.timer<100)
		{
			t1.src = this.ledicons[0].src
			t2.src = this.ledicons[((this.timer%100)-(this.timer%10))/10].src;
			t3.src = this.ledicons[(this.timer%10)].src;
		}
		else if (this.timer>=100 && this.timer<999)
		{
			t1.src = this.ledicons[((this.timer%1000)-(this.timer%100))/100].src;
			t2.src = this.ledicons[((this.timer%100)-(this.timer%10))/10].src;
			t3.src = this.ledicons[(this.timer%10)].src;
		}
		else if (this.timer>=999)
			this.stopTimer();
	}


	// Clears the timer leds when game is restarted
	this.ClearTimer = function()
	{
		var t1 = document.getElementById('t1');
		var t2 = document.getElementById('t2');
		var t3 = document.getElementById('t3');

		if (this.timer==0)
		{
			t1.src = this.ledicons[0].src;
			t2.src = this.ledicons[0].src;
			t3.src = this.ledicons[0].src;
		}
	}


}
