/*
 * Small SDL example to demonstrate dynamically loading 
 * OpenGL lib and functions
 *
 * (FYI it was supposed to look like snow in the wind or something...)
 *
 * Compile with :
 * gcc testdyngl.c `sdl-config --libs --cflags` -o testdyngl -DHAVE_OPENGL
 *
 * You can specify a different OpenGL lib on the command line, i.e. :
 * ./testdyngl  /usr/X11R6/lib/libGL.so.1.2
 * or
 * ./testdyngl  /usr/lib/libGL.so.1.0.4496
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <io.h>
#include <iostream>
#include <sstream>
#include <cassert>
#include <map>
#include <algorithm>
#include <hash_map>

#include "SDL.h"

#include "SDL_image.h"

#include "glfuncs.h"
#include "colorScreen.h"
#include "Sprite.h"

using namespace std;

static Uint32 WALKBEHIND;
static Uint32 WALKINTO;
static Uint32 WALKINFRONT;
static std::map<Uint32,Sprite *> TEXTURES;
static std::map<Uint32,std::string> OBJECTS;
static std::map<Uint32,Sprite *> PELS;
static vector<Uint32> COLORS;


void loadObjects();
Uint32 loadPixelFile(std::string filename);
void readObjects(std::string dir);
void readTextures(std::string extension);

void showAll(int type, int page);
void showObject(Uint32 pixel, int y);
void showTexture(Uint32 pixel, int y);
void showColl(int y);



int main(int argc,char *argv[])
{		
	//string levelfile = "levels/level";
	//string levelfile = "levels/pipes2";
	//string levelfile = "levels/pipes3";
	string levelfile = "levels/factory";
	
	/*
	List *list = Parser::parse("textures/jesus.txt");
    //cout << newList->getString();

	List *newList = list;
    while(!newList->empty()) {
        cout << newList->getString() << endl;
        newList = newList->rest();
    }
    delete list;

	return 0;
	*/

	SDL_Event event;
	
	int ticks = SDL_GetTicks();

	Screen* screen = Screen::instance();

	glfuncs* f = glfuncs::instance();

	loadObjects();
	
	GLfloat whiteCoords[4];
	SDL_Surface *whiteSurface = f->load_image("whiteBG.png");
	int whiteBG = f->SDL_GL_LoadTexture(whiteSurface, whiteCoords);

	GLfloat scramCoords[4];
	SDL_Surface *scramSurface = f->load_image("scramble.png");
	int scram = f->SDL_GL_LoadTexture(scramSurface, scramCoords);

	int mode = 0;
	int page = 0;
	bool leave = false;

		do
		{
			// Clear OpenGL screen
			f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			SDL_Rect screenRect = screen->getScreenRect();
			screenRect.x = 0;
			screenRect.y = 0;
			screen->drawScreen(whiteBG,whiteCoords,screenRect);

			/*SDL_Rect quad;
			quad.h = 128;
			quad.w = 128;
			quad.x = 240;
			quad.y = 240;
			for(int i = 0; i < 4; i++) {
				screen->drawLevel(texture,texCoords,quad);
				quad.x += 128;
			}*/

			//This runs if we are trying to run frames in too rapid succession
			
			while((SDL_GetTicks() - ticks) < 1000/Screen::FRAMERATE)
			{
				//Just wait until we can do a frame again
				Sleep(0);
			}
			//reset for the next time we want to update
			ticks = SDL_GetTicks();

			showAll(mode,page);

			SDL_Rect scramRect;
			scramRect.w = 51;
			scramRect.h = 81;
			scramRect.x = 5;
			scramRect.y = screen->getScreenRect().h - 80;
			screen->drawScreen(scram,scramCoords,scramRect);


			f->glFinish();
			SDL_GL_SwapBuffers();

			//person.control();
			//screen->control();


			while(SDL_PollEvent(&event))
			{
				if(event.type & SDL_KEYDOWN) {
					switch( event.key.keysym.sym ) 
					{
					case SDLK_ESCAPE:
						leave = true;
						break;
					case SDLK_o:
						mode = 1;
						break;
					case SDLK_t:
						mode = 0;
						break;
					case SDLK_y:
						mode = 3;
						break;
					case SDLK_1:
						page = 0;
						break;
					case SDLK_2:
						page = 1;
						break;
					case SDLK_3:
						page = 2;
						break;
					case SDLK_4:
						page = 3;
						break;
					case SDLK_5:
						page = 4;
						break;
					case SDLK_6:
						page = 5;
						break;
					case SDLK_7:
						page = 6;
						break;
					case SDLK_8:
						page = 7;
						break;
					case SDLK_9:
						page = 8;
						break;
					case SDLK_0:
						page = 9;
						break;
					case SDLK_q:
						page = 10;
						break;
					case SDLK_w:
						page = 11;
						break;
					case SDLK_e:
						page = 12;
						break;
					case SDLK_r:
						page = 13;
						break;
					case SDLK_a:
						page = 14;
						break;
					case SDLK_s:
						page = 15;
						break;
					case SDLK_d:
						page = 16;
						break;
					case SDLK_f:
						page = 17;
						break;
					case SDLK_z:
						page = 18;
						break;
					case SDLK_x:
						page = 19;
						break;
					case SDLK_c:
						page = 20;
						break;
					case SDLK_v:
						page = 21;
						break;
					default:
						break;
					}
				}
			}

			//SDL_Delay(20);
		} while(!leave);
	
	



	//f->KillFont(base);

	SDL_Quit();
	return 0;
}

void loadObjects()
{
	readTextures("png");
	readTextures("txt");
	
	WALKBEHIND = loadPixelFile("levels/walkbehind_p.png");
	WALKINFRONT = loadPixelFile("levels/walkinfront_p.png");
	WALKINTO = loadPixelFile("levels/walkinto_p.png");

	readObjects("characters");
	readObjects("events");
	readObjects("cutscenes");
	readObjects("entities");
	//readTextures("bmp");
}

Uint32 loadPixelFile(std::string filename)
{
	SDL_Surface *surface = glfuncs::instance()->load_image(filename);
	SDL_LockSurface(surface);
	Uint32 pixel=*((Uint32*)surface->pixels);
	SDL_UnlockSurface(surface);
	SDL_FreeSurface(surface);

	/*Sprite * sprite = Sprite::loadSprite(filename);
	sprite->setHeight(8);
	sprite->setWidth(8);

	PELS[pixel] = sprite;
	COLORS.push_back(pixel);*/

	return pixel;
}

void readObjects(std::string dir)
{
	struct _finddata_t file;
	intptr_t hFile;
	string extension = "txt";

	if( (hFile = _findfirst( (dir + "/*." + extension).c_str(), &file )) != -1L ) {
		do {
			string filename(file.name);
			
			string end = filename.substr(filename.size() - 6,2);
			if(end != "_p") {

				filename = dir + "/" + filename;
				//Sprite * sprite = new Sprite(filename, tileWidth, tileHeight);
				string objFile = filename;

				//filename.insert(filename.find("."),"_p");
				filename.erase(filename.find("."),4);
				filename += "_p.png";

				SDL_Surface *surface = glfuncs::instance()->load_image(filename);
				SDL_LockSurface(surface);
 				Uint32 pixel=*((Uint32*)surface->pixels);
				
				//cerr << (int) pixel << endl;

				SDL_UnlockSurface(surface);
				SDL_FreeSurface(surface);

				OBJECTS[pixel] = objFile;
				Sprite * sprite = Sprite::loadSprite(filename);
				sprite->setHeight(8);
				sprite->setWidth(8);
				PELS[pixel] = sprite;
				COLORS.push_back(pixel);
			}
			else
				continue;
		}
		while( _findnext( hFile, &file ) == 0 );

		_findclose( hFile );
	}
}

void readTextures(std::string extension)
{
	struct _finddata_t file;
	intptr_t hFile;

	if( (hFile = _findfirst( ("textures/*." + extension).c_str(), &file )) != -1L ) {
		do {
			string filename(file.name);
			
			string end = filename.substr(filename.size() - 6,2);
			if(end != "_p") {

				filename = "textures/" + filename;
				//Sprite * sprite = new Sprite(filename, tileWidth, tileHeight);
				Sprite * sprite = Sprite::loadSprite(filename);

				//filename.insert(filename.find("."),"_p");
				filename.erase(filename.find("."),4);
				filename += "_p.png";

				SDL_Surface *surface = glfuncs::instance()->load_image(filename);
				SDL_LockSurface(surface);
				Uint32 pixel=*((Uint32*)surface->pixels);
				
				//cerr << (int) pixel << endl;

				SDL_UnlockSurface(surface);
				SDL_FreeSurface(surface);

				TEXTURES[pixel] = sprite;

				sprite = Sprite::loadSprite(filename);
				sprite->setHeight(8);
				sprite->setWidth(8);
				PELS[pixel] = sprite;
				COLORS.push_back(pixel);
			}
			else
				continue;
		}
		while( _findnext( hFile, &file ) == 0 );

		_findclose( hFile );
	}
}

void showAll(int type, int page)
{
	int y=13;
	
	int pagelength = 0;

	int i = 0;
	if(type == 0)
	{
		Screen::instance() ->drawText("TEXTURES:",0,y);
		y+=13;
		pagelength = 15;
	}
	else if(type == 1)
	{
		Screen::instance() ->drawText("OBJECTS:",0,y);
		y+=13;
		pagelength = 40;
	}
	else if(type == 3)
	{
		Screen::instance() ->drawText("COLLISION COLORS:",0,y);
		y+=13;
		showColl(y);
		return;
	}

	int numdrawn = 0;
	for(int i = pagelength*page; (i < COLORS.size())&&(numdrawn <= pagelength); i++)
	{
		//we're showing textures
		if(type == 0 && TEXTURES[COLORS[i]] != NULL)
		{
			showTexture(COLORS[i],y);
			y+= 32;
			numdrawn ++;
		}
		else if(type == 1 && OBJECTS[COLORS[i]]!="")
		{
			showObject(COLORS[i],y);
			y+= 13;
			numdrawn ++;
		}
	}
}

void showObject(Uint32 pixel, int y)
{
	int x=0;
	PELS[pixel]->draw(x,y,Sprite::SCREEN);
	x+= 10;
	y+=10;
	Screen::instance() ->drawText(OBJECTS[pixel],x,y);
	y-=10;
}

void showTexture(Uint32 pixel, int y)
{
	int x=0;
	PELS[pixel]->draw(x,y,Sprite::SCREEN);
	x+= 10;
	TEXTURES[pixel]->draw(x,y,Sprite::SCREEN);
	TEXTURES[pixel]->update();
}

void showColl(int y)
{
	int x=0;
	PELS[WALKBEHIND]->draw(x,y,Sprite::SCREEN);
	x+= 10;
	y+=10;
	Screen::instance() ->drawText("Walk Behind",x,y);
	y+=3;

	x=0;
	PELS[WALKINTO]->draw(x,y,Sprite::SCREEN);
	x+= 10;
	y+=10;
	Screen::instance() ->drawText("Walk Into",x,y);
	y+=3;
}
