/***************************************************************************
 *   Copyright (C) 2004 by ian reinhart geiser                             *
 *   ian@geiseri.com                                                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "levelgenerator.h"
#include "util.h"
LevelGenerator::LevelGenerator(int width, int height, int features) : m_attemptFeatures(features), m_width(width), m_height(height)
{
	InitMaze();
	srand( (unsigned)time( NULL ) );
}


LevelGenerator::~LevelGenerator()
{
}

void LevelGenerator::InitMaze( )
{
	m_maze.fill( QVector<int>( height() + 1), width() + 1);
	for(int x = 0; x < width(); x++)
	{
		for(int y = 0; y < height(); y++)
		{
			m_maze[x][y] = WALL;
		}
	}
}

int LevelGenerator::randomNumber( int num )
{
	return int(rand()%num);
}

void LevelGenerator::Fill( int x1, int y1, int x2, int y2, int val )
{
	for(int x = x1; x < x2; x++)
	{
		for(int y = y1; y < y2; y++)
		{
			m_maze[x][y] = val;
		}
	}
}

bool LevelGenerator::IsWall( int x, int y, int & dx, int & dy )
{
	int spaces = 0;

	if(m_maze[x][y] != WALL) return false;

	if(x <= 0 || x >= width()) return false;
	if(y <= 0 || y >= height()) return false;

	if(m_maze[x+1][y] == FLOOR) dx = -1, dy = 0, spaces++;
	if(m_maze[x-1][y] == FLOOR) dx = 1, dy = 0,spaces++;
	if(m_maze[x][y+1] == FLOOR) dx = 0, dy = -1,spaces++;
	if(m_maze[x][y-1] == FLOOR) dx = 0, dy = 1,spaces++;

	if(spaces == 1) return true;
	return false;
}

bool LevelGenerator::CanAdd( int x1, int y1, int x2, int y2 )
{
	for(int x = x1; x < x2; x++)
	{
		for(int y = y1; y < y2; y++)
		{
			if(x <= 0 || x >= width()) return false;
			if(y <= 0 || y >= height()) return false;

			if(m_maze[x][y] != WALL) return false;
		}
	}

	return true;
}

void LevelGenerator::MazeGen( int level )
{
	InitMaze();
	int x;
	int y;
	int sx;
	int sy;
	int px;
	int py;
	int dx;
	int dy;

	//Create initial room
	int roomSize = randomNumber(5) + 1;
	Fill((width()/2)-roomSize,(height()/2)-roomSize,(width()/2)+roomSize,(height()/2)+roomSize,FLOOR);

	for(int i = 0; i < m_attemptFeatures; i++)
	{
		for(;;)
		{
			//find insertion point
			x = randomNumber(width());
			y = randomNumber(height());
			if(IsWall(x,y,dx,dy)) break;
		}

		sx = roomSize +randomNumber(5);
		sy = roomSize +randomNumber(5);

		//make corridor

		if(randomNumber(10) < 2)
		{
			if(randomNumber(2) == 0)
			{
				sx = 1;
				sy *= 2;
			}
			else
			{
				sy = 1;
				sx *= 2;
			}
		}

		if(dx == 0)
		{
			px = x-(sx/2);
			if(dy > 0)
			{
				py = y +dy;
			}
			else
			{
				py = y - sy ;
			}
		}
		else
		{
			py = y-(sy/2);
			if(dx > 0)
			{
				px = x+dx ;
			}
			else
			{
				px = x - sx ;
			}
		}

		if(CanAdd(px-1,py-1,px+sx+1,py+sy+1) == true)
		{
			m_maze[x][y] = FLOOR;
			Fill(px,py,px+sx,py+sy, FLOOR);
		}

	}
	PlaceMonsters( level * 2 );
	PlaceItems( level );
}

int LevelGenerator::cell( int x, int y ) const
{
	return m_maze[x][y];
}

int LevelGenerator::width( ) const
{
	return m_width;
}

int LevelGenerator::height( ) const
{
	return m_height;
}

void LevelGenerator::PlaceMonsters( int number )
{
	for( int idx = 0; idx < number; ++idx)
	{
		int X = randomNumber(width());
		int Y = randomNumber(height());
		while( m_maze[X][Y] == WALL || m_maze[X][Y] == MONSTER || m_maze[X][Y] == ITEM )
		{
			X = randomNumber(width());
			Y = randomNumber(height());
		}
		m_maze[X][Y] = MONSTER;
	}
}

void LevelGenerator::PlaceItems( int number )
{
	for( int idx = 0; idx < number; ++idx)
	{
		int X = randomNumber(width());
		int Y = randomNumber(height());
		while( m_maze[X][Y] == WALL || m_maze[X][Y] == MONSTER || m_maze[X][Y] == ITEM  )
		{
			X = randomNumber(width());
			Y = randomNumber(height());
		}
		m_maze[X][Y] = ITEM;
	}

}


