/*


			aMaze v1.0
			by Håkan Lundgren
			2010-10-18

*/


var values = {
			mazeRows:			20,
			mazeCols:			20,
			drawSize:			10,
			solidWalls:			false };


var components = {
			mazeRows: {			type:			'number',
								label:			'Rows' },
			mazeCols: {			type:			'number',
								label:			'Columns' },
			drawSize: {			type:			'number',
								label:			'Cell Size',
								units:			'point' },
			solidWalls:	{		type:			'checkbox',
								label:			'Solid Walls',
								onChange:		function( value ) {
													solidWalls = value; } } };


values = Dialog.prompt( 'aMaze v1.0', components, values );


var lineStyle = {
			fillColor:			null,
			strokeColor:		'#000000',
			strokeWidth:		values.solidWalls ? values.drawSize / 2 : 1,
			strokeCap:			'square' };


// Init cells and orientations
var cell = new Array();
var mazeCellStack = new Array();
var neighboringCellStack = new Array();


// 									Down, Up, Left, Right
var oppositeDirection =				[ 1, 0, 3, 2 ];
var directionDelta = {			x:	[ 0, 0, -1, 1 ],
								y:	[ 1, -1, 0, 0 ] };


// Init maze cells in grid
for ( i = 0; i < values.mazeRows; i++ ){
			cell[i] = new Array();
			for ( j = 0; j < values.mazeCols; j++ ){
						cell[i][j] = {	visited: false,
										walls: [ 1, 1, 1, 1 ],
										neighbors: [ 0, 1, 2, 3 ] };
			}
}


// Store the random starting coordinates in the stack
mazeCellStack = [ { x: Math.floor( Math.random() * values.mazeCols ), y: Math.floor( Math.random() * values.mazeRows ) } ];


// Visited cells counter
var visitedCells = 0;


// Maze generation routine
while ( visitedCells < ( values.mazeRows * values.mazeCols ) ){


			// Set X & Y coordinates from the top entry in stack
			xCell = mazeCellStack[mazeCellStack.length - 1].x;
			yCell = mazeCellStack[mazeCellStack.length - 1].y;
			visitedCells++;


			// Check if cell has any unvisited neighbors
			while ( cell[yCell][xCell].neighbors.length > 0 ){
						// The cell is set as visited
						cell[yCell][xCell].visited = true;


						// Choose a random neighbor from the remaining unvisited neighbors
						randomNeighbor = Math.floor( Math.random() * cell[yCell][xCell].neighbors.length );
						newDir = cell[yCell][xCell].neighbors.splice( randomNeighbor, 1 );


						// Neighboring coordinates
						newX = xCell + directionDelta.x[newDir];
						newY = yCell + directionDelta.y[newDir];


						// Test to verify that new coordinates lies within the grid
						if ( newY >= 0 && newX >= 0 && newY < values.mazeRows && newX < values.mazeCols ){

			
									// Has the new cell been visited...
									if ( cell[newY][newX].visited == false ){


												// ...if not, knock down wall FROM the old cell...
												cell[yCell][xCell].walls[newDir] = 0;


												// ...and the opposite wall in the new cell
												cell[newY][newX].walls[oppositeDirection[newDir]] = 0;


												// Put the new coordinates in the stack
												mazeCellStack.push( { x: newX, y: newY } );


												// Make the new coordinates the current
												xCell = newX;
												yCell = newY;												
									}
						}
			}

			// Remove the latest entry from the stack since it has no more neighbors
			mazeCellStack.pop();
}



// Draw Maze
for ( i = 0; i < values.mazeRows; i++ ){
			for ( j = 0; j < values.mazeCols; j++ ){
						
						
						// Cell corner-variables
						bottomLeftCorner = new Point( j * values.drawSize, -i * values.drawSize);
						bottomRightCorner = new Point(( j + 1 ) * values.drawSize, -i * values.drawSize );
						topLeftCorner = new Point( j * values.drawSize, ( -i + 1) * values.drawSize );
						topRightCorner = new Point(( j + 1 ) * values.drawSize, ( -i + 1) * values.drawSize );


						// Bottom wall
						if ( cell[i][j].walls[0] == 1 ){
							drawWalls( bottomLeftCorner, bottomRightCorner ); }


						// Top wall
						if ( cell[i][j].walls[1] == 1 ){
							drawWalls( topLeftCorner, topRightCorner ); }


						// Left wall
						if ( cell[i][j].walls[2] == 1 ){
							drawWalls( topLeftCorner, bottomLeftCorner ); }


						// Right wall
						if ( cell[i][j].walls[3] == 1 ){
							drawWalls( topRightCorner, bottomRightCorner ); }
			}
}


function drawWalls( pt1, pt2 ){
			var line = new Path.Line( pt1, pt2 );
			line.style = lineStyle;
			line.expand();
}