#include "SDL.h"
#include "SDL_image.h"
#include "Include\sge030809-w32\src\sge.h"
#include <iostream>
#include <direct.h>

void Dir_Files_Remove(char *dirpath, char *ext);
SDL_Surface *Surf_Load(char *filename);
int Image_Scan(SDL_Surface *areasurf, int tile_w, int tile_h, int start_x, int start_y, int end_w, int end_h, int start_tile_x, int start_tile_y, int end_tile_w, int end_tile_h);
int Tile_Scan(SDL_Surface *surf, int x, int y, int tile_w, int tile_h);
int Tile_Compair(SDL_Surface *surf);
bool Tile_Check(SDL_Surface *surf, SDL_Surface *tile);
void Tiles_Save(char *savepath);
void World_Save(char *savepath, char *savefile, int world_w, int world_h);
void Idle();
void Info(int aInstruction[]);
SDL_Rect Calculate_Area(int start_x, int start_y, int end_w, int end_h, int start_tile_x, int start_tile_y, int end_tile_w, int end_tile_h, int tile_w, int tile_h, int image_w, int image_h);

using namespace std;
SDL_Surface *screen = NULL;
int gScreen_bpp = 32;

#define TILE_MAX 1200000
#define WORLD_MAX_W 21000
#define WORLD_MAX_H 21000

int gTiles = 0;
SDL_Surface *aTile[TILE_MAX];
int aWorld[WORLD_MAX_W][WORLD_MAX_H];

enum instruction {//0 is program path
	IMAGE_FILE = 1,
	TILE_W,
	TILE_H,
	START_PIXELS_X,
	START_PIXELS_Y,
	END_PIXELS_W,
	END_PIXELS_H,
	START_TILE_X,
	START_TILE_Y,
	END_TILE_W,
	END_TILE_H,
	SCREEN_BPP,
	INSTRUCTION_MAX//	9
};

int main(int argc, char **argv) {
	SDL_Init(SDL_INIT_VIDEO);
	//IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF);

	screen = SDL_SetVideoMode(320, 200, 32, SDL_ANYFORMAT);
	SDL_Surface *surfImage = NULL;

	bool done = false;

	//char *surfPath = "E:/Graphics/Dragon Warrior 3/Maps/dw3-over.PNG";
	char *surfPath = "E:/Graphics/Dragon Warrior 3/Maps/dw1-over.bmp";
	char *aInstruction_temp[INSTRUCTION_MAX];
	int aInstruction[INSTRUCTION_MAX];
	for (int i = 0; i < INSTRUCTION_MAX; i++) {
		if (i < argc)
			aInstruction_temp[i] = argv[i];
		else
			aInstruction_temp[i] = "0";
	}

	for (int i = 2; i < INSTRUCTION_MAX - 1; i++) {
		aInstruction[i] = stoi(aInstruction_temp[i]);
	}

	if (aInstruction[TILE_W] == 0)
		aInstruction[TILE_W] = 16;
	if (aInstruction[TILE_H] == 0)
		aInstruction[TILE_H] = 16;

	// If a argv[IMAGE_FILE] has been provided change default surfPath 
	if (argc > 1)
		surfPath = argv[IMAGE_FILE];

	cout << surfPath << endl;
	surfImage = Surf_Load(surfPath);

	// B/c I had errors loading
	FILE *file = fopen(surfPath, "r");
	if (!file) cout << "PATH NOT FOUND: " << surfPath << endl;
	else cout << "FILE WAS FOUND AT PATH: " << surfPath << endl;
	fclose(file);

	if (surfImage == NULL) {
		cout << "Image NOT FOUND: " << surfPath << endl;
		SDL_Delay(6000);
		return -1;
	}

	Dir_Files_Remove("World\\Tiles\\", "*.bmp");
	Info(aInstruction);

	Image_Scan(surfImage, aInstruction[TILE_W], aInstruction[TILE_H],
		aInstruction[START_PIXELS_X], aInstruction[START_PIXELS_Y],
		aInstruction[END_PIXELS_W], aInstruction[END_PIXELS_H],
		aInstruction[START_TILE_X], aInstruction[START_TILE_Y],
		aInstruction[END_TILE_W], aInstruction[END_TILE_H]
		);
	Tiles_Save("World/");
	//cout << "gTiles: " << gTiles << endl;

	SDL_Rect areaRect = Calculate_Area(aInstruction[START_PIXELS_X], aInstruction[START_PIXELS_Y],
									aInstruction[END_PIXELS_W], aInstruction[END_PIXELS_H], 
									aInstruction[START_TILE_X], aInstruction[START_TILE_Y],
									aInstruction[END_TILE_W], aInstruction[END_TILE_H],
									aInstruction[TILE_W], aInstruction[TILE_H],
									surfImage->w, surfImage->h);

	int world_w = (areaRect.w - areaRect.x) / aInstruction[TILE_W];
	int world_h = (areaRect.h - areaRect.y) / aInstruction[TILE_H];
	if ((areaRect.w - areaRect.x) % aInstruction[TILE_W] > 0) world_w += 1;
	if ((areaRect.h - areaRect.y) % aInstruction[TILE_H] > 0) world_h += 1;

	cout << "areaRect.x: " << areaRect.x << " areaRect.y: " << areaRect.y << endl;
	cout << "areaRect.w: " << areaRect.w << " areaRect.h: " << areaRect.h << endl;
	cout << "Save World_W: " << world_w << " World_H: " << world_h << endl;
	World_Save("World/", "000.txt", world_w, world_h);
	cout << "MAPPARSER DONE" << endl;
	for (int i = 0; i < gTiles; i++)
		if (aTile[i] != 0) SDL_FreeSurface(aTile[i]);

	if (surfImage != NULL) SDL_FreeSurface(surfImage);

	IMG_Quit();
	SDL_Quit();
	return 0;
}// main

void Idle() {
	bool done = 0;
	SDL_Event event;
	while (!done)
	{
		// PollEvent for user Exit
		while (SDL_PollEvent(&event)) {
			switch (event.type) {
			case SDL_QUIT:
				done = true;
			}
		}
	}
}// Idle

bool Tile_Check(SDL_Surface *surf, SDL_Surface *tile)
{
	if (tile != NULL) {
		int x = 0, y = 0;
		for (y = 0; y < tile->h; y++) {
			for (x = 0; x < tile->w; x++) {
				if (sge_GetPixel(surf, x, y) != sge_GetPixel(tile, x, y)) return 0;
			}//END FOR(x)
		}//END FOR(y)
		return 1;
	}
	else return 0;
}// Tile_Check

int Tile_Compair(SDL_Surface *surf)//returns 1 on no match found
{
	int ispic = 0;
	int i = 0;
	int x = 0, y = 0;
	for (i = 0; i < gTiles; i++) {//flip through tilearray[]
		if (sge_GetPixel(surf, x, y) == sge_GetPixel(aTile[i], x, y)) {
			if (Tile_Check(surf, aTile[i])) return i;
		}
	}
	if (gTiles < TILE_MAX - 1) {//if checktile returns 0, add tile to tile[] array
		ispic = gTiles;
		aTile[gTiles] = SDL_DisplayFormat(surf);
		gTiles++;
	}
	return ispic;
}// Tile_Compair

int Tile_Scan(SDL_Surface *surf, int x, int y, int tile_w, int tile_h)
{
	int tileID = -1, px = 0, py = 0;
	Uint32 pc;
	SDL_Surface *surfTile_read = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCCOLORKEY, tile_w, tile_h, gScreen_bpp, 0, 0, 0, 0);
	for (py = 0; py < tile_h; py++)//scan a tile graphic from surf and draw tile on tempsurf
		for (px = 0; px < tile_w; px++) {
			pc = sge_GetPixel(surf, x + px, y + py);
			sge_PutPixel(surfTile_read, px, py, pc);
		}
	tileID = Tile_Compair(surfTile_read);
	if (surfTile_read != NULL) SDL_FreeSurface(surfTile_read);
	surfTile_read = NULL;
	return tileID;
}// Tile_Scan

int Image_Scan(SDL_Surface *areasurf, int tile_w, int tile_h, int start_x, int start_y, int end_w, int end_h, int start_tile_x, int start_tile_y, int end_tile_w, int end_tile_h)
{
	if (tile_w == 0)
		tile_w = 16;
	if (tile_h == 0)
		tile_h = 16;

	SDL_Rect areaRect = Calculate_Area(start_x, start_y, end_w, end_h, start_tile_x, start_tile_y, end_tile_w, end_tile_h, tile_w, tile_h, areasurf->w, areasurf->h);
	cout << "aArea_x: " << areaRect.x << endl;
	cout << "aArea_y: " << areaRect.y << endl;
	cout << "aArea_w: " << areaRect.w << endl;
	cout << "aArea_h: " << areaRect.h << endl;
	//Idle();
	int x = 0, y = 0;
	int xx = 00, yy = 0;
	sge_ClearSurface(screen, 0, 0, 200);

	int world_w, world_h;

	if (areasurf != NULL) {
		world_w = (areaRect.w - areaRect.x) / tile_w;
		world_h = (areaRect.h - areaRect.y) / tile_h;
		cout << "world_w: " << world_w << " " << world_h << endl;
		for (y = 0; y < world_h; y++)
			for (x = 0; x < world_w; x++)
				aWorld[x][y] = -1;
		for (y = areaRect.y; y < areaRect.h; y += tile_h) {
			for (x = areaRect.x; x < areaRect.w; x += tile_w) {
				aWorld[xx][yy] = Tile_Scan(areasurf, x, y, tile_w, tile_h);
				xx++;
			}
			yy++; xx = 0;
		}
	}
	else {
		return -1;
	}
	return 0;
}// Image_Scan

SDL_Surface *Surf_Load(char *filename) {
	SDL_Surface *surf = IMG_Load(filename);
	if (surf != NULL) {
		SDL_Surface *surfScreenBPP = SDL_DisplayFormat(surf);
		SDL_FreeSurface(surf);
		surf = nullptr;
		return surfScreenBPP;
	}
	else {
		surf = SDL_LoadBMP(filename);
		if (surf != NULL) {
			SDL_Surface *surfScreenBPP = SDL_DisplayFormat(surf);
			SDL_FreeSurface(surf);
			surf = nullptr;
			return surfScreenBPP;
		}
		else {
			cout << "IMG_Error(): " << IMG_GetError() << endl;
			cerr << "Surf_Load(): " << filename << endl << "Not found" << endl;
		}
	}
	return NULL;
}// Surf_Load

void Dir_Files_Remove(char *dirpath, char *ext) {
	int files = 0, dirs = 0, i = 0;
	char aChar[1024]; memset(aChar, NULL, sizeof(aChar));
	strcpy(aChar, dirpath);
	strcat(aChar, "*.*");
	char aSys_command[1024]; memset(aSys_command, NULL, sizeof(aSys_command));
	strcpy(aSys_command, "del ");
	strcat(aSys_command, dirpath);
	strcat(aSys_command, ext);

	//cout << "aSys_command: " << aSys_command << endl;
	system(aSys_command);
}// Dir_Files_Remove

void Tiles_Save(char *savepath) {
	//cout << "Tiles_Save: gTiles: " << gTiles << endl;
	int i = 0;
	char tile_path[1024]; memset(tile_path, NULL, sizeof(tile_path));
	char fullpath[1024]; memset(fullpath, NULL, sizeof(fullpath));
	char tile_amount[10]; memset(tile_amount, NULL, sizeof(tile_amount));
	strcpy(tile_path, savepath);
	strcat(tile_path, "Tiles/");
	//cout << "SavePath: " << savepath << endl;

	int rc = _mkdir(savepath);
	rc = _mkdir(tile_path);

	for (i = 0; i < gTiles; i++) {
		if (aTile[i] != NULL) {
			SDL_BlitSurface(aTile[i], 0, screen, 0);
			SDL_Flip(screen);
			strcpy(fullpath, tile_path);// Path
			itoa(i, tile_amount, 10);// Convert
			strcat(fullpath, tile_amount);
			strcat(fullpath, ".bmp");
			SDL_SaveBMP(aTile[i], fullpath);
		}
	}
}// Tiles_Save

void World_Save(char *savepath, char *savefile, int world_w, int world_h) {
	int i = 0, x = 0, y = 0, istr = 0, tilelen = 0;

	#define tileAmountCharBuffer 10
	char tile_amount[tileAmountCharBuffer]; memset(tile_amount, NULL, sizeof(tile_amount));

	// Create padded cell so each cell takes the same amount of character space in the text file
	itoa(gTiles, tile_amount, 10);
	tilelen = strlen(tile_amount) + 1;
	for (i = 0; i < tileAmountCharBuffer - 1; i++)
		tile_amount[i] = ' ';

	mkdir(savepath);
	char fullpath[1024]; memset(fullpath, NULL, sizeof(fullpath));
	strcpy(fullpath, savepath);
	strcat(fullpath, savefile);
	// File Open
	FILE *file = fopen(fullpath, "w");
	// Write Header
	fprintf(file, "%d\n", world_w);
	fprintf(file, "%d\n", world_h);
	fprintf(file, "%d\n", gTiles);
	// Write world
	for (y = 0; y < world_h; y++) {
		for (x = 0; x < world_w; x++) {
			itoa(aWorld[x][y], tile_amount, 10);
			tile_amount[strlen(tile_amount)] = ' ';
			tile_amount[tilelen] = NULL;

			fprintf(file, "%s", tile_amount);
		}// x
		fprintf(file, "\n");
	}// y
	fclose(file);
}// World_Save

void Info(int aInstruction[]) {
	cout << "aInstruction[TILE_W]" << "\t\t" << aInstruction[TILE_W] << endl;
	cout << "aInstruction[TILE_H]" << "\t\t" << aInstruction[TILE_H] << endl;
	cout << "aInstruction[START_PIXELS_X]" << "\t" << aInstruction[START_PIXELS_X] << endl;
	cout << "aInstruction[START_PIXELS_Y]" << "\t" << aInstruction[START_PIXELS_Y] << endl;
	cout << "aInstruction[END_PIXELS_W]" << "\t" << aInstruction[END_PIXELS_W] << endl;
	cout << "aInstruction[END_PIXELS_H]" << "\t\t" << aInstruction[END_PIXELS_H] << endl;
	cout << "aInstruction[START_TILE_X]" << "\t\t" << aInstruction[START_TILE_X] << endl;
	cout << "aInstruction[START_TILE_Y]" << "\t\t" << aInstruction[START_TILE_Y] << endl;
	cout << "aInstruction[END_TILE_W]" << "\t\t" << aInstruction[END_TILE_W] << endl;
	cout << "aInstruction[END_TILE_H]" << "\t\t" << aInstruction[END_TILE_H] << endl;
}// Info

// Joins pixel and tile offsets into single x, y, w, h, pixel offset
SDL_Rect Calculate_Area(int start_x, int start_y, int end_w, int end_h, int start_tile_x, int start_tile_y, int end_tile_w, int end_tile_h, int tile_w, int tile_h, int image_w, int image_h)
{
	start_tile_x = start_tile_x * tile_w;
	start_tile_y = start_tile_y * tile_h;
	end_tile_w = end_tile_w * tile_w;
	end_tile_h = end_tile_h * tile_h;

	start_x += start_tile_x;
	start_y += start_tile_y;
	int calc_end_w = start_x + end_w + end_tile_w;
	int calc_end_h = start_y + end_h + end_tile_h;
	//; If user entered zero'd values for End use max image w, h - the start offset
	if (end_w < 1 && end_tile_w < 1) {
		calc_end_w = image_w - start_x;
		cout << "calc_end_w" << endl;
	}
	if (end_w < 1 && end_tile_w < 1) calc_end_w = image_w;// -start_y;
	if (end_h < 1 && end_tile_h < 1) calc_end_h = image_h;// -start_y;
	SDL_Rect areaRect = { start_x , start_y, calc_end_w , calc_end_h };
	return areaRect;
}// Calculate_Area