/*    Zonic the Hog.  A silly Sonic-like game written for Speedhack 2007
 *    Copyright (c) 2007 Steven Wallace / Chedda Cheeze
 *    email: steven.t.wallace @ gmail. com
 *
 *    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.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 
#include <allegro.h>
#include <alleggl.h>
#include "fudgefont.h"
#include "Timer.h"
#include <list>
#include <vector>
#include "GameComponent.h"
#include "Menu.h"
#include "Game.h"
#include "Cutscene.h"
#include "EndOfLevel.h"
#include "Logfile.h"
#include "Joystick.h"
#include "GlCompat.h"
#include "GL/glu.h"

using namespace std;




list<GameComponent*> toProcess;
bool done = false;

int fs_w, fs_h;
int win_w, win_h;
int dw, dh;
int desktop_res_status;
float desktop_ratio;
int fullscreen;


// Load all the game components
Menu menu;
Game game;
Cutscene cutscene;
EndOfLevel endoflevel;

Level *level=0;
Player player, farmer;
Joystick joystick;

BITMAP *buffer=0;
DATAFILE *data=0;


FONT *fMenu=0, *fTitle=0, *fDialog=0;


char *songfile[7] = { "piggies", "backussr", "birthday", "taxman", "obladida", "monkey", "while_my" };
MIDI *midi[7];
int midilength[7];
int currentSong = -1;


int setup_screen(int fullscreen) {
	Logfile::log("Setting screen mode...\n");
	int ret;

	allegro_gl_set(AGL_COLOR_DEPTH, 32);
    allegro_gl_set(AGL_RENDERMETHOD, 1);
    allegro_gl_set(AGL_SUGGEST, AGL_COLOR_DEPTH | AGL_RENDERMETHOD);

	if(fullscreen) {
		if(set_gfx_mode(GFX_OPENGL_FULLSCREEN, fs_w, fs_h, 0, 0) != 0) {
			fullscreen = FALSE;
			if(set_gfx_mode(GFX_OPENGL_WINDOWED, win_w, win_h, 0, 0) != 0) {
				Logfile::log("Couldn't create a window at all!\n");
				allegro_message("FATAL ERROR: Could not create a window.");
				allegro_exit();
				exit(-1);
			}
			else {
				Logfile::log("Using windowed %dx%d mode.\n", win_w, win_h);
				ret = FALSE;
			}
		}
		else {
			Logfile::log("Using fullscreen %dx%d mode.\n", fs_w, fs_h);
			ret = TRUE;
		}
	}
	else {
		if(set_gfx_mode(GFX_OPENGL_WINDOWED, win_w, win_h, 0, 0) != 0) {
			fullscreen = TRUE;
			if(set_gfx_mode(GFX_OPENGL_FULLSCREEN, fs_w, fs_h, 0, 0) != 0) {
				Logfile::log("Couldn't create a window at all!\n");
				allegro_message("FATAL ERROR: Could not create a window.");
				allegro_exit();
				exit(-1);
			}
			else {
				Logfile::log("Using fullscreen %dx%d mode.\n", fs_w, fs_h);
				ret = TRUE;
			}
		}
		else {
			Logfile::log("Using windowed %dx%d mode.\n",win_w,win_h);
			ret = FALSE;
		}
	}
	
	if(buffer) destroy_bitmap(buffer);
	buffer = create_bitmap(SCREEN_W, SCREEN_H);

	// build my antialiasing palette
	RGB pal[256];
	// ramp from light blue (8, 192, 234) to black (0, 0, 0)
	int i;
	for(i=0; i<256; i++) {
		pal[i].r = (unsigned char)(8/4   -   8/255.0 * i/4.0);
		pal[i].g = (unsigned char)(192/4 - 192/255.0 * i/4.0);
		pal[i].b = (unsigned char)(234/4 - 234/255.0 * i/4.0);
	}
	set_palette(pal);
	
	if(data) {
		printf("Unloading datafile at 0x%x\n", data);
		unload_datafile(data);
	}
	data = load_datafile("media/zonic.dat");
	
	install_textures();
	allegro_gl_set_allegro_mode();
	allegro_gl_flip_texture(TRUE);
	allegro_gl_use_mipmapping(FALSE);
	
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glEnable(GL_ALPHA_TEST);
	//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
	
	glClearColor(0.03125, 0.75, 0.9140625, 0);
	
		// Load fonts
	fMenu = my_load_font("fonts/vinet.ttf", 14);
	ASSERT(fMenu);
	
	fTitle = my_load_font("fonts/GiddyupStd.ttf", 32);
	ASSERT(fTitle);
	
	fDialog = my_load_font("fonts/HoboStd.ttf", 18);
	ASSERT(fDialog);

	return ret;
}



// returns the least common divisor of two numbers
int LCD(int a, int b) {
	if(a == b) return a;
	else if(a == 1 || b == 1) return 1;
	else if(a > b) return LCD(a-b, b);
	else return LCD(a, b-a);
}


void get_video_info() {
	// Determine depth
	int depth = desktop_color_depth();
	if(depth == -1) depth = 32;
	set_color_depth(depth);
	printf("%d bpp used.\n", depth);

	// Determine screen dimensions
	desktop_res_status = get_desktop_resolution(&dw, &dh);
	if(desktop_res_status == 0) {
		desktop_ratio = dw / (float)dh;
		fs_w = dw;
		fs_h = dh;
	}
	else {
		desktop_ratio = 4/3.0f;
		fs_w = 800;
		fs_h = 600;
	}
	
	win_w = 800;
	win_h = 600;

}



void save_screenshot(const char *path)
{
	BITMAP *bmp = create_bitmap_ex(32, SCREEN_W,SCREEN_H);
	if(!bmp) return;
	char *buff = new char[4*SCREEN_W*SCREEN_H];
	if(!buff)
	{
		destroy_bitmap(bmp);
		return;
	}

	glReadPixels(0,0,SCREEN_W,SCREEN_H,GL_RGBA,GL_UNSIGNED_BYTE,buff);

	int y;
	for(y=0;y<SCREEN_H;y++)
		memcpy(bmp->line[y],buff+4*SCREEN_W*(SCREEN_H-1-y),4*SCREEN_W);

	save_bitmap(path, bmp, NULL);

	destroy_bitmap(bmp);
	delete buff;
}



int main(int argc, char *argv[]) {
	allegro_init();
	install_allegro_gl();
	install_fudgefont();
	
	
	set_window_title("Zonic the Hog v" VERSION_STR);
	set_display_switch_mode(SWITCH_BACKGROUND);
	

	Timer timer;
	get_video_info();
	fullscreen = setup_screen(FALSE);
	
	install_keyboard();
	install_joystick(JOY_TYPE_AUTODETECT);
	install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL);
	set_volume(255,0);

	
	// Load all the music
	int i;
	for(i=0; i<7; i++) {
		char temp[32];
		snprintf(temp, 32, "media/%s.mid", songfile[i]);
		midi[i] = load_midi(temp);
		
		if(!midi[i]) {
			midilength[i] = 0;
			printf("Error reading %s\n", temp);
		}
		else {
			get_midi_length(midi[i]);
			midilength[i] = -midi_pos;
		}
	}
	
	
	vector<int> keys;
	level = new Level();


	toProcess.push_back(&menu);
	timer.TimeElapsed();
	START_OF_LOOP:
	while(!done) {

		// Check for OpenGL errors
		// This should be put in its own function and only done in debug builds
		int error;
		while( (error=glGetError()) != GL_NO_ERROR) {
			allegro_message("OpenGL Error #%d: %s", error, gluErrorString(error));
		}
		


		poll_joystick();
		
		// Update music
		if(midi_pos < 0) {
			currentSong++;
			if(currentSong > 6) currentSong = 0;
			play_midi(midi[currentSong], FALSE);
		}
		
		
		keys.clear();
		glClear(GL_COLOR_BUFFER_BIT);
		
		// Calculate time since last frame
		float dt = timer.TimeElapsed();
		joystick.Update(dt);
		
		// Copy all keys pressed to the keys list
		while(keypressed()) {
			keys.push_back(readkey() >> 8);
		}

		// Copy joystick settings as well to key list
		if(joystick.Up(true)) keys.push_back(KEY_UP);
		else if(joystick.Down(true)) keys.push_back(KEY_DOWN);
		if(joystick.B0(true)) keys.push_back(KEY_ENTER);
		if(joystick.LastButton(true)) keys.push_back(KEY_ESC);
		
		
		// Cycle through the list of objects to mess with
		list<GameComponent*>::const_iterator it;
		for(it=toProcess.begin(); it!=toProcess.end(); it++) {
			(*it)->SendKeys(&keys);
			if((*it)->Update(dt)) goto START_OF_LOOP;
			(*it)->Draw(screen);
		}
		
		
		// Draw to screen
		glDisable(GL_TEXTURE_2D);
		glColor3ub(0,0,0);
		textprintf_right_ex(screen, font, SCREEN_W-10, 10, -1, -1, "fps: %0.0f", 1/dt);
		textprintf_right_ex(screen, font, SCREEN_W-10, 10, 0, -1, "fps: %0.0f", 1 / dt);
		allegro_gl_flip();

		if(key[KEY_F12]) {
			save_screenshot("zonic.bmp");
			timer.TimeElapsed();
		}
		rest(1);
	}
	
	if(level) delete level;
	if(buffer) destroy_bitmap(buffer);
	if(data) unload_datafile(data);

	return 0;
}
END_OF_MAIN()

