/****************************************************************
 * Copyright (C) 2002  Joel Muzzerall
 *
 * 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.
 ******************************************************************/

//************************************************
// A GameLevel is used by the manager to maintain
// levels.  It uses block objects profusely.
// ***********************************************

using namespace std;

#include "Definitions.h"
#include "Block.h"
#include <allegro.h>
#include <fstream>
#include "GameLevel.h"

//************************************************
// The constructor makes a new level of empty
// blocks, and if the array of bitmaps has not
// yet been initialized, it will do so.
//************************************************
GameLevel::GameLevel()
{
	if (GameLevelInit == 0)
		InitGameLevel();

	normals = 0;

	for(int i = 0; i < 20; i++)
		for (int j = 0; j < 14; j++)
			blocks[i][j] = Init_Block(B_empty, B_empty);
}

// ************************************************
// This initializes the game level system by
// loading all of the necessary graphics
// for it from the Blocks.dat file.
// ************************************************
void GameLevel::InitGameLevel()
{
	GameLevelInit = 1;

	DATAFILE *pics = load_datafile("dat/Blocks.dat");
	if (pics == NULL){
		set_gfx_mode(GFX_TEXT, 320, 240, 0, 0);
		allegro_message("Cannot load Blocks.dat");
		rest(5000);
		allegro_exit(); }

		for (int i = 0; i < 19; i++){
			blockPics[i] = create_bitmap(32, 18);
			blit((BITMAP *)pics[i].dat, blockPics[i], 0, 0, 0, 0, 32, 18);}
}

// **************************************************
// This collide method propogates the collision to
// the individual block, returning the correct answer
// to the manager.
// **************************************************
int GameLevel::collide(int x, int y, int dir)
{
	int answer = Block_Collide(dir, blocks[x][y]);

	if (answer == BC_normal){
		normals--;
		if (normals == 0)
			answer = LC_leveldone;
	}

	if (answer == BC_rebound) answer = LC_normal;
	return answer; 
} 

/********************************************************
 * Returns the requested block
 * *****************************************************/
Block *GameLevel::get_block(int x, int y){
	if (x < 0 || y < 0 || x > 19 || y > 13)
		return NULL;
	else return blocks[x][y];
}

/********************************************************
 * Returns the bitmap of the requested block
 * *****************************************************/
BITMAP *GameLevel::get_block_pic(int x, int y){
	if (x < 0 || y < 0 || x > 19 || y > 13)
		return NULL;
	else return blockPics[blocks[x][y]->blockColor];
}

// ******************************************************
// This will draw the level to the given bitmap, one
// block at a time.
// ******************************************************
void GameLevel::draw(BITMAP *buf)
{
	for (int i = 0; i < 20; i++)
		for (int j = 0; j < 14; j++)
			if (blocks[i][j]->type != B_empty){
				// Not actually transparent.  Sorry.
				set_trans_blender(255, 255, 255, 255);
				draw_trans_sprite(buf, blockPics[blocks[i][j]->blockColor], i * 32 + 1, j * 18 + 20);
				solid_mode();
			}
}

// ********************************************************
// This sets the given block to the given type.  It's
// used only by the level editor program, and perhaps a
// random level generator that I may or may not code.
//
// The complicated switching is a result of the conflict
// between type numbering conventions and the order of the
// graphics in the array.
// ********************************************************
void GameLevel::setTo(int x, int y, int type)
{

	int answer = 0;

	switch(type)
	{
		case PB_yellow:
		case PB_blue:
		case PB_cyan:
		case PB_green:
		case PB_orange:
		case PB_pink:
		case PB_purple:
		case PB_red:
			answer = B_normal; break;

		case PB_gold: answer = B_gold; break;
		case PB_indestructable: answer = B_indestructable; break;
		case PBS_down: answer = B_down; break;
		case PBS_up: answer = B_up; break;
		case PBS_life: answer = B_life; break;
		case PBS_fast: answer = B_fast; break;
		case PBS_grow: answer = B_grow; break;
		case PBS_multi: answer = B_multi; break;
		case PBS_shrink: answer = B_shrink; break;
		case PBS_slow: answer = B_slow; break;
		case PBS_uber: answer = B_uber; break;
		case PB_empty:
		default: answer = B_empty; break;
	}

	// Update the amount of normal blocks remaining.
	if ((answer == B_normal) && (blocks[x][y]->type != B_normal))

		normals++;

	if ((answer != B_normal) && (blocks[x][y]->type == B_normal)){
		if(normals == 1)
			return;
		else
			normals--; }

	blocks[x][y] = Init_Block(answer, type);
}

/*****************************************************
 * The save and load methods take a stream argument
 * and save / load the level from said stream
 *****************************************************/
void GameLevel::save(ofstream &fout)
{
	fout.write((char *)&normals, sizeof(normals));
	for (int i = 0; i < 20; i++)
		for (int j = 0; j < 14; j++)
			fout.write((char *)blocks[i][j], sizeof(*blocks[i][j]));
}

void GameLevel::load(ifstream &fin)
{
	int tempColor;

	fin.read((char *)&normals, sizeof(normals));
	for (int i = 0; i < 20; i++)
		for (int j = 0; j < 14; j++){
			if (fin.eof())
				return;
			fin.read((char *)blocks[i][j], sizeof(*blocks[i][j]));}
}
