#include <allegro.h>
#include <fstream>

#include "LevEd.h"

//*************************************************
// The main method.  Kinda goes without having to
// describe, I should hope.
// ************************************************
void main()
{
	// ***** Variables and initialization *****
	init();
	int endProgram = 0;

	int keyInput;
	int blockType;

	variables *vars = new variables();
	vars->currentLevel = 0;
	vars->x = 0;
	vars->y = 0;

	bitmaps *bmps = new bitmaps();
	bmps->buf = create_bitmap(640, 480);
	bmps->buf2 = create_bitmap(640, 480);
	bmps->menu = getMenuGraphic();
	bmps->cursor = getCursorGraphic();

	// ***** Main loop *****
	while (endProgram == 0)
	{
		blockType = -1;

		drawScreen(vars, bmps);
		keyInput = ureadkey(NULL);
		keyManage(vars);

		if(keyInput == 'q' || keyInput == 'Q')
			endProgram = 1;

		switch(keyInput)
		{
			case '1': blockType = PB_yellow; break;
			case '2': blockType = PB_red; break;
			case '3': blockType = PB_purple; break;
			case '4': blockType = PB_pink; break;
			case '5': blockType = PB_orange; break;
			case '6': blockType = PB_green; break;
			case '7': blockType = PB_cyan; break;
			case '8': blockType = PB_blue; break;
			case '9': blockType = PB_gold; break;
			case '0': blockType = PB_indestructable; break;
			case '!': blockType = PBS_multi; break;
			case '@': blockType = PBS_uber; break;
			case '#': blockType = PBS_life; break;
			case '$': blockType = PBS_grow; break;
			case '%': blockType = PBS_shrink; break;
			case '^': blockType = PBS_up; break;
			case '&': blockType = PBS_down; break;
			case '*': blockType = PBS_fast; break;
			case '(': blockType = PBS_slow; break;
			case 'd':
			case 'D': blockType = 100; break;
			case 's':
			case 'S': save(); break;
			case 'l':
			case 'L': load(); break;
			case 'n':
			case 'N': next(vars); break;
			case 'p':
			case 'P': prev(vars); break;
			case 'a':
			case 'A': addLevel(vars); break;

		}

		if(blockType != -1)
			levels[vars->currentLevel]->setTo(vars->x, vars->y, blockType);
	}
}
END_OF_MAIN();


// ************************************************
// The init routine initializes Allegro and the
// necessary parts of it for the Level Editor.
// It also initializes the array of levles.
// ************************************************
void init()
{
	allegro_init();
	set_color_depth(16);
	install_timer();
	install_keyboard();
	set_gfx_mode(GFX_AUTODETECT_WINDOWED, SCN_WIDTH, SCN_HEIGHT, 0, 0);
	jpgalleg_init();

	levels[0] = new GameLevel();

	levels[0]->setTo(0, 0, 1);
	numLevels = 1;
}

/***************************************************
 * The save method saves the levels created to the
 * current directory.  Soon, there will be a way to
 * name them.  For now, they are saved as levels.dat
 ***************************************************/
void save()
{
	ofstream fout("dat//levels.dat", ios::binary);

	fout.write((char *) &numLevels, sizeof(numLevels));

	for(int i = 0; i < numLevels; i++)
		levels[i]->save(fout);

	fout.close();
}

/*********************************************************
 * The load method loads levels from levels.dat.
 *********************************************************/
void load()
{
	ifstream fin("dat//levels.dat", ios::binary);

	fin.read((char *) &numLevels, sizeof(numLevels));

	for(int i = 0; i < numLevels; i++){
		levels[i] = new GameLevel();
		levels[i]->load(fin); }

		fin.close();
}


/****************************************************
 * As self explanitory as these are, you must be told
 * that these methods advance the user to the next
 * level and the previous level.  Oh, and they do
 * nothing if they go past the bounds of the levels.
 ****************************************************/
void next(variables *vars)
{
	if (vars->currentLevel == numLevels - 1)
		return;
	else vars->currentLevel++;
}

void prev(variables *vars)
{
	if (vars->currentLevel == 0)
		return;
	else vars->currentLevel--;
}


/***************************************************
 * addLevel adds a level at the end of the levels,
 * and brings the user there.
 ***************************************************/
void addLevel(variables *vars)
{
	if (numLevels == 50)
		return;
	numLevels++;
	vars->currentLevel = numLevels - 1;
	levels[vars->currentLevel] = new GameLevel();
}

// *************************************************
// These mechanisms are used by the other, higher
// level methods.
// *************************************************
/**
 * getMenuGraphic returns a bitmap that is used by
 * the rest of the program to draw the menu
 **/
BITMAP *getMenuGraphic()
{
	BITMAP *answer = load_bitmap("gfx//default//screens//leved.jpg", NULL);
	if (answer == NULL){
		allegro_message("Could not load leved.jpg");
		allegro_exit();
	}
	
	return answer;
}

/**
 * The getCursorGraphic returns a bitmap that is
 * used by the rest of the program to draw the cursor
 **/
BITMAP *getCursorGraphic()
{
	DATAFILE *temp = load_datafile("dat/Blocks.dat");
	if (temp == NULL){
		set_gfx_mode(GFX_TEXT, 320, 240, 0, 0);
		allegro_message("Cannot load Blocks.dat");
		allegro_exit(); }

		return (BITMAP *) temp[cursorGraphic].dat;
}


/**
 * The drawScreen function draws the screen, given
 * some info from the main method.
 */
void drawScreen(variables *vars, bitmaps *bmps)
{
	clear_bitmap(bmps->buf2);
	char theString[64];
	levels[vars->currentLevel]->draw(bmps->buf2);
	blit(bmps->menu, bmps->buf, 0, 0, 0, 0, 640, 480);
	blit(bmps->buf2, bmps->buf, 0, 20, 0, 0, 640, 252);
	masked_blit(bmps->cursor, bmps->buf, 0, 0, vars->x * 32, vars->y * 18, 32, 18);
	sprintf(theString, "Level: [%d]", vars->currentLevel);
	textout_ex(bmps->buf, font, theString, 380, 275, 10000, -1);
	textout_ex(bmps->buf, font, "Arrow keys to move cursor.", 380, 325, 10000, -1);
	textout_ex(bmps->buf, font, "S to save", 380, 335, 10000, -1);
	textout_ex(bmps->buf, font, "L to load", 380, 345, 10000, -1);
	textout_ex(bmps->buf, font, "Q to quit", 380, 355, 10000, -1);
	textout_ex(bmps->buf, font, "N for next level", 380, 365, 10000, -1);
	textout_ex(bmps->buf, font, "P for previous level", 380, 375, 10000, -1);
	textout_ex(bmps->buf, font, "A to add level", 380, 385, 10000, -1);
	textout_ex(bmps->buf, font, "C to cut level [Not coded]", 380, 395, 10000, -1);
	textout_ex(bmps->buf, font, "Every level NEEDS at least one", 380, 415, 10000, -1);
	textout_ex(bmps->buf, font, "normal, solid colored block.", 380, 425, 10000, -1);
	blit(bmps->buf, screen, 0, 0, 0, 0, 640, 480);
}

/**
 * The keyManage class moves the cursor
 */
void keyManage(variables *vars)
{
	if (key[KEY_UP]) vars->y--;
	if (key[KEY_DOWN]) vars->y++;
	if (key[KEY_LEFT]) vars->x--;
	if (key[KEY_RIGHT]) vars->x++;
	if (vars->y < 0) vars->y = 0;
	if (vars->y > 13) vars->y = 13;
	if (vars->x < 0) vars->x = 0;
	if (vars->x > 19) vars-> x = 19;
}
