#include "SDL.h"
#include "SDL_opengl.h"

#include <iostream>

#include "config.h"
#include "game.h"
#include "util.h"
#include "random.h"
#include "menu.h"
#include "help.h"
#include "font_ogl.h"
#include "config.h"
#include "audio.h"
#include "skybox.h"
#include "block/cube.h"
#include "radio.h"
#include "block/map2.h"
#include "floor.h"

#include "models/displaylists.h"
#include "tweak/tweak.h"

#include "release.h"

namespace PRJID {



std::string load_audio(std::string dir) {
   std::string path;
   if (dir=="") {
      path="data/";
      std::cout << "  Looking in " << path << std::endl;
      if (Audio::load(path)) return path;
      path="/usr/local/share/";
      path+=PATHNAME;
      path+="/";
      std::cout << "  Looking in " << path << std::endl;
      if (Audio::load(path)) return path;
      path="/usr/share/";
      path+=PATHNAME;
      path+="/";
      std::cout << "  Looking in " << path << std::endl;
      if (Audio::load(path)) return path;
   }
   if (Audio::load(dir)) { return dir; }
   std::cerr << "  Audio files not found ... They are optional however so feel free to ignore this." << std::endl;
	return "";
}

void load_res(std::string dir) {
	dir=load_audio(dir);
	block::Map2::set_path(dir);
	Radio::instance()->load(dir);
}



bool testspeed() {
	Uint32 start,end,took;

	start=SDL_GetTicks();
	ortho2d();
	glColor3f(1,1,1);

	Font_ogl::write("loading...");
	SDL_GL_SwapBuffers();
	ortho2d_off();
	end=SDL_GetTicks();

	took=(end-start);

	if (took<200) return true;

   SDL_Event event;
   while (true) {
		glLoadIdentity();
     	while  (SDL_PollEvent(&event)) {
			if (event.type==SDL_QUIT) return false;
			if (event.type==SDL_MOUSEBUTTONDOWN) return true;
			if (event.type!=SDL_KEYDOWN) continue;
			if (event.key.keysym.sym==SDLK_ESCAPE) { return false; }
			return true;
		}
		ortho2d();
		glTranslatef(0,20,0);
		Font_ogl::write("  ... system slow");
		glTranslatef(0,20,0);
		Font_ogl::write("  probable cause: no properly configured 3d acceleration.");
		glTranslatef(0,20,0);
		Font_ogl::write("  ESC to quit. any other key: continue anyway.");
		ortho2d_off();
		SDL_GL_SwapBuffers();
		SDL_Delay(150);
	}
	return true;
}

SDL_Surface *screen;

bool setmode(int w,int h,bool fullscreen) {
	if(!(screen=SDL_SetVideoMode(w,h,0,SDL_OPENGL|SDL_RESIZABLE | ((fullscreen) ? SDL_FULLSCREEN : 0)))) {
		std::cerr <<"SDL_SetVideoMode error " << w << "x" << h << " " << fullscreen << "  " << SDL_GetError() << std::endl;
		return false;
	}
	Config::resolution(w,h);
	SDL_WM_SetCaption(FULLNAME,"");
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0f,(GLfloat)screen->w/(GLfloat)screen->h,0.10f,405.0f);
   glViewport(0, 0, screen->w, screen->h);
   glMatrixMode(GL_MODELVIEW);

   glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	return true;
}

typedef enum e_menuids {
	M_POP=-1,
	M_NONE=0,
	M_START_EASY=1,
	M_START_MEDIUM=2,
	M_START_HARD=3,
	M_START_NIGHTMARE=4,
	M_QUIT=5
};


int main(int w,int h,bool fullscreen,bool audio,std::string dir) {
   std::cout<<std::endl<<std::endl<<FULLNAME << " "<< VERSION << std::endl;
   std::cout<<"\t Copyright (C) 2006" << std::endl;
   std::cout<<"\t " << EL_URL << std::endl;
   std::cout<<"\t Using libSDL,SDL_mixer,SDL_image under the terms of the GNU LGPL" << std::endl;
	std::cout<<"\t Please consult the README file/website in case of problems/questions." << std::endl;
	std::cout << std::endl;
   /*std::cout<<"This program is free software; you can redistribute it and/or"<<std::endl;
   std::cout<<"modify it under the terms of the GNU General Public License," <<std::endl;
   std::cout<<"version 2, as published by the Free Software Foundation; You"<<std::endl;
   std::cout<<"should have received a copy of the GNU General Public License"<<std::endl;
   std::cout<<"along with this program; if not, write to the Free Software" <<std::endl;
   std::cout<<"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA."<<std::endl;
   std::cout << std::endl << std::endl;*/

	//Tweak::tick();


	if(SDL_Init(SDL_INIT_VIDEO)==-1) {
		std::cerr <<"SDL_Init error SDL_INIT_VIDEO" << std::endl;
		return EXIT_FAILURE;
	}
	atexit(SDL_Quit);
	if (!setmode(w,h,fullscreen)) {
		std::cerr <<"SDL_SetVideoMode error" << std::endl;
		return EXIT_FAILURE;
	}


	std::cout << "Uploading Font. " << std::endl;
	Font_ogl::genlist();
	error();

	std::cout << "Testing speed: " << std::endl;
	if (!testspeed()) { return EXIT_SUCCESS; }
	std::cout << "Starting audio subsys. " << std::endl;
	if (audio) {
		if (!Audio::init()) {
			std::cerr << "  Error in Mix_OpenAudio" << std::endl;
		}
		error();
	} else { Audio::off(); }

	std::cout << "Loading Resources: " << std::endl;
	load_res(dir);


	std::cout << "Uploading Models: " << std::endl;
	block::Cube::gen_dl();
	Skybox::gen_dl();
	Floor::gen_dl();
	models::gen_dl();
	error();

	Audio::play(AS_TITLE,AC_TITLE);

	Random::sseed();

	Game *game=NULL;
	Menu menu(2,C3(245,140));


	menu.add(Menuitem("Start Easy",M_START_EASY));
	menu.add(Menuitem("Start Medium",M_START_MEDIUM));
	menu.add(Menuitem("Start Hard",M_START_HARD));
	menu.add(Menuitem("Start Nightmare",M_START_NIGHTMARE));
	menu.add(Menuitem("Quit",M_QUIT));

   SDL_Event event;
	Uint32 timestamp,oldtimestamp=0;
	Uint32 fpsstart=SDL_GetTicks(); 
	unsigned int frames=0;

	bool handled;

	unsigned int unhandled=0;
	unsigned int showunhandled=0;

	unsigned int delay;
	unsigned int record=0;

	


   while (true) {

     	while  (SDL_PollEvent(&event)) {
			handled=false;
			if (game) { 
				handled=game->handle_event(event); 
			} else {
				e_menuids id=(e_menuids)menu.handle_event(event); 
				unhandled=6;
				switch (id) {
					case M_START_EASY: 
						game=new Game(NULL,D_EASY); 
						menu.reset();
						break;
					case M_START_MEDIUM: 
						game=new Game(NULL,D_MEDIUM); 
						menu.reset();
						break;
					case M_START_HARD: 
						game=new Game(NULL,D_HARD); 
						menu.reset();
						break;
					case M_START_NIGHTMARE: 
						game=new Game(NULL,D_NIGHTMARE); 
						menu.reset();
						break;
					case M_QUIT:
						SDL_Quit();
						return EXIT_SUCCESS;
						break;
					default: break;
				}
			}
			if (!handled) switch (event.type) {
					case SDL_VIDEORESIZE:
						setmode(event.resize.w,event.resize.h,false);
						break;
      			case SDL_QUIT: return EXIT_SUCCESS; break;

					case SDL_KEYDOWN: switch (event.key.keysym.sym) {
						case SDLK_ESCAPE: return EXIT_SUCCESS; break;
						case SDLK_w:
						case SDLK_a:
						case SDLK_s:
						case SDLK_d:
						case SDLK_LEFT:
						case SDLK_RIGHT:
						case SDLK_UP:
						case SDLK_DOWN:
						case SDLK_RETURN:
						case SDLK_p:
						case SDLK_SPACE: break;

						case SDLK_F1:
						case SDLK_h:
							if (showunhandled>0) {showunhandled=0; break; }
							unhandled=6; break;

						case SDLK_r: Config::toggle_mouse_reverse(); break;
						case SDLK_g: Config::toggle_show_gun(); break;
						case SDLK_m: togglemouselock(); break;
						case SDLK_f: SDL_WM_ToggleFullScreen(screen); break;
						case SDLK_F10: screenshot(screen->w,screen->h); break;
						case SDLK_F11: 
							Config::toggle_record();
							record=0;
							break;
						case SDLK_v: Audio::toggle(); break;
						default: 
							//unhandled key
							unhandled++;
							break;
					}
			}
		}
		//if (Random::sget(50)==10) Tweak::tick();
		/*frames++;
		if (Random::sget(200)==10){
			Uint32 timesince;
			timesince=SDL_GetTicks()-fpsstart;
			
			float spf;
			spf=timesince;
			spf/=frames;
			std::cout << " frames: " << timesince << "  " << frames << "  " << spf << std::endl;

			fpsstart=SDL_GetTicks();
			frames=0;
		} */


		glLoadIdentity();
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		if (game) {
			game->handle_state();


			int diff;
			timestamp=SDL_GetTicks();
			diff=timestamp-oldtimestamp;
			oldtimestamp=timestamp;



			game->tick(diff);


			game->draw();
			E_GameState state=game->get_state();
			if (state!=GS_PLAYING&&state!=GS_FINISHED) {
				if (state==GS_NEXTLEVEL) {
					Game *newgame=new Game(game);
					delete game;
					game = newgame;
				} else {
					delete game;
					game=NULL;
				}
			}
			if (unhandled>5) {
				showunhandled=1000;
				unhandled=0;
			}

			if (showunhandled>0) {
				showunhandled--;
				ortho2d();
				glDisable(GL_LIGHTING);
				Help::controls();
				//Help::gameplay();
				glEnable(GL_LIGHTING);
				ortho2d_off();
			}
			delay=0;
		} else {
			if (menu.isactive()==false) { SDL_Quit(); return EXIT_SUCCESS; }
			ortho2d();
			glDisable(GL_LIGHTING);
			menu_bg();
			glEnable(GL_LIGHTING);
			ortho2d_off();

			ortho2d();
			glDisable(GL_LIGHTING);


			Help::title();
			menu.draw();


			Help::gameplay();
			Help::controls();
			glEnable(GL_LIGHTING);
			ortho2d_off();
			delay=20;
		}


		SDL_GL_SwapBuffers();
		/*if (Config::record()) {
			record++;
			screenshot(screen->w,screen->h,record);
		}*/

		SDL_Delay(delay);
		Audio::tick();
		error();

	}
}

} // namespace

int main(int argc,char *argv[]) {
	unsigned int w=800; unsigned int h=600;
	bool fullscreen=false;
	bool audio=true;
	std::string dir="";

	std::istringstream istr;
	if (argc>1) {
		for (int i=1;i<argc;i++) {
			std::string arg(argv[i]);

			if (arg=="-fullscreen") {
				fullscreen=true;
				continue;
			} 
			if (arg=="-noaudio") {
				audio=false;
				continue;
			} 
			if (arg=="-width") {
				if (i==argc-1) {
					std::cerr << "Argument missing for -width " << std::endl;
					return EXIT_FAILURE;
				}
				istr.clear();
				istr.str(argv[i+1]);
				istr >> w;
				i++;
				continue;
			} 
			if (arg=="-height") {
				if (i==argc-1) {
					std::cerr << "Argument missing for -height " << std::endl;
					return EXIT_FAILURE;
				}
				istr.clear();
				istr.str(argv[i+1]);
				istr >> h;
				i++;
				continue;
			} 
			if (arg=="-dir") {
				if (i==argc-1) {
					std::cerr << "Argument missing for -dir " << std::endl;
					return EXIT_FAILURE;
				}
				dir=argv[i+1];
				i++;
				continue;
			}
			std::cerr << "Usage: " << argv[0] << " [ -width xx ] [ -height xx ] [ -fullscreen ] [ -noaudio ] [ -dir datadir ]" << std::endl;
			if (arg!="-help") {
				std::cerr << "Unrecognized argument " << arg << std::endl;
				return EXIT_FAILURE;
			}
			return EXIT_SUCCESS;
		}
	}

	int r;
	r=PRJID::main(w,h,fullscreen,audio,dir);

	if (r==EXIT_SUCCESS) {
		std::cout << std::endl << "   Thank you for playing " << FULLNAME << "." << std::endl;
	}
	return r;
}
