/* MoleInvasion - Copyright (C) - Guillaume Chambraud (linuxprocess@free.fr)

  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. */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>

#include "MoleInvasion.h"
#include "worldmap.h"
#include "editor_texts.h"

int needreload;
int mousex,mousey,show_FPS;

worldmap world_infos;
myList * all_level_desc=NULL;

/* moves */
char key_up=0, key_down=0, key_left=0, key_right=0, key_shift=0, key_control=0;
/* for sprites */
char sprite_action=0;

/* fichier de travail */
char world_dir_name[256];
char world_file_name[512];

void how_to_use(int exit_code)
{
	printf("\n");
	printf("\tMoleInvasion - Copyright (C) Guillaume Chambraud (linuxprocess@free.fr)\n");
	printf("\n");
	printf("\tThis program is free software; you can redistribute it and/or modify\n");
	printf("\tit under the terms of the GNU General Public License as published by\n");
	printf("\tthe Free Software Foundation; either version 2 of the License, or\n");
	printf("\t(at your option) any later version.\n");
	printf("\n");
	printf("\tThis program is distributed in the hope that it will be useful,\n");
	printf("\tbut WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	printf("\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	printf("\tGNU General Public License for more details.\n");
	printf("\n");
	printf("\tYou should have received a copy of the GNU General Public License\n");
	printf("\talong with this program; if not, write to the Free Software\n");
	printf("\tFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n");
	printf("\n");
	printf("\tMole Invasion World Editor\n");
	printf("\t--------------------------\n");
	printf("\n");
	printf("\t\tOptions :\n");
	printf("\t-f            => fullscreen mode\n");
	printf("\t-h            => this tiny help\n");
	printf("\t-fps          => print FPS on tty\n");
	printf("\t-bpp=X        => set BPP (8,16,24,32) same as current X by default\n");
	printf("\tdir_name      => full world directory name for both reading and writing\n");
	printf("\t\tCommands :\n");
	printf("\t'f'           => toggle fullscreen\n");
	printf("\t'left click'  => drag slot OR select destination if keypress\n");
	printf("\t'left key'    => left click for selecting left destination\n");
	printf("\t'right key'   => left click for selecting right destination\n");
	printf("\t'up key'      => left click for selecting up destination\n");
	printf("\t'down key'    => left click for selecting down destination\n");
	printf("\n");
	exit(exit_code);
}

#define SLOT_W	30
#define SLOT_H	10
int findSprite(int mousex,int mousey)
{	int x,y;
	level_desc *sprite;
	unsigned int i;

	/* on détermine l'emplacement correspondant */
	x=mousex;
	y=mousey;

	for(i=0;i<all_level_desc->size;i++)
	{	sprite=GetPosList(all_level_desc,i);
		if(sprite->posX-SLOT_W/2 <= x && sprite->posX+SLOT_W/2 >= x
		&& sprite->posY-SLOT_H/2 <= y && sprite->posY+SLOT_H/2 >= y)
		{	return i;
		}
	}
	return -1;
}

static void quitandsave( int code )
{	
	if( strlen(world_file_name)>0 && wantToSave(world_file_name))
	{	while(1)
		{	if(confirmToSaveWorld(world_infos))
			{	if(save_worldfile(world_file_name,all_level_desc,world_infos) == 0)
				{	simpleMessage("[DONE]");
					break;
				}
				else
				{	simpleMessage("[PROBLEM]");
				}
			}
			else
				break;
		}
	}
	SDL_Quit();
	quit( code );
}

static void handle_key( SDL_keysym* keysym, int down )
{
	switch( keysym->sym )
	{case SDLK_ESCAPE:  quitandsave( 0 );	break;
	case SDLK_LEFT:     key_left=down;	break;
	case SDLK_RIGHT:    key_right=down;	break;
	case SDLK_UP:	    key_up=down;	break;
	case SDLK_DOWN:     key_down=down;	break;
	case SDLK_LSHIFT:   key_shift=down;	break;
	case SDLK_LCTRL:    key_control=down;	break;
	case SDLK_f:	    if(down)
				SDL_WM_ToggleFullScreen(g_SDL_screen);
			    break;
	default: break;
	}
}

int process_events( void )
{	SDL_Event event;
	static level_desc *selected=NULL;
	static int is_draging=0;
	int tmp;

	while( SDL_PollEvent( &event ) )
	{	switch( event.type )
		{case SDL_KEYDOWN:	handle_key( &event.key.keysym,1 );	break;
		case SDL_KEYUP:		handle_key( &event.key.keysym,0 );	break;
		case SDL_MOUSEMOTION:	SDL_GetMouseState(&mousex, &mousey);	break;
        	case SDL_QUIT:		quitandsave( 0 );	break;
		case SDL_MOUSEBUTTONDOWN:
			switch(event.button.button)
			{case SDL_BUTTON_LEFT    :sprite_action=1;		break;
			}
			break;
		case SDL_MOUSEBUTTONUP:
			switch(event.button.button)
			{case SDL_BUTTON_LEFT    :sprite_action=0;		break;
			}
			break;
        	}
	}
	
	if(sprite_action)
	{	if(selected && (key_up || key_down || key_left || key_right) )
		{	/* selection d'un sprite destination */
			tmp=findSprite(mousex,mousey);
			if(tmp>=0)
			{	level_desc *olddest;
				level_desc *dest=GetPosList(all_level_desc,tmp);
				if(key_up && dest!=selected)
				{	olddest=GetPosListById(all_level_desc,selected->move_up);
					selected->move_up = dest->level_id;
					if(olddest)olddest->move_down=0;
					olddest=GetPosListById(all_level_desc,dest->move_down);
					dest->move_down   = selected->level_id;
					if(olddest)olddest->move_up=0;
				}
				if(key_down && dest!=selected)
				{	olddest=GetPosListById(all_level_desc,selected->move_down);
					selected->move_down = dest->level_id;
					if(olddest)olddest->move_up=0;
					olddest=GetPosListById(all_level_desc,dest->move_up);
					dest->move_up   = selected->level_id;
					if(olddest)olddest->move_down=0;
				}
				if(key_left && dest!=selected)
				{	olddest=GetPosListById(all_level_desc,selected->move_left);
					selected->move_left = dest->level_id;
					if(olddest)olddest->move_right=0;
					olddest=GetPosListById(all_level_desc,dest->move_right);
					dest->move_right   = selected->level_id;
					if(olddest)olddest->move_left=0;
				}
				if(key_right && dest!=selected)
				{	olddest=GetPosListById(all_level_desc,selected->move_right);
					selected->move_right = dest->level_id;
					if(olddest)olddest->move_left=0;
					olddest=GetPosListById(all_level_desc,dest->move_left);
					dest->move_left   = selected->level_id;
					if(olddest)olddest->move_right=0;
				}
				needreload=1;
			}
		}
		else
		{	if(!is_draging)
			{	/* selection d'un sprite */
				tmp=findSprite(mousex,mousey);
				if(tmp>=0)
				{	if(selected)
						selected->level_status=OPEN;
					selected=GetPosList(all_level_desc,tmp);
					is_draging=1;
				}
			}
			if(is_draging && selected)
			{	/* deplacement du sprite */
				selected->level_status=MODIFY;
				selected->posX=mousex;
				selected->posY=mousey;
			}
		}
	}
	else if(is_draging)
	{	needreload=1;
		is_draging=0;
	}

	return selected?selected->level_id:0;
}

int main( int argc, char** argv )
{
	/* Information about the current video settings. */
	const SDL_VideoInfo* info = NULL;
	/* Color depth in bits of our window. */
	Uint8 fullscreen;
	unsigned int bpp;
	Uint32 i,flags;
	level_desc *level_read;
	int fd;
	DIR * mydir;
	struct dirent * direntry;

	/* defaults args */
	fullscreen = show_FPS = bpp = 0;
	snprintf(world_dir_name,sizeof(world_dir_name),"%s","lvl/default/");

	/* on se place dans le repertoire des datas */
	if(chdir(DATADIR))
		chdir("../");

	for(i=1;i<argc;i++)
	{	/* fullscreen */
		if(strcmp(argv[i],"-f")==0)
		{	fullscreen=1;
		}
		else /* FPS */
		if(strcmp(argv[i],"-fps")==0)
		{	show_FPS=1;
		}
		else /* help */
		if(strcmp(argv[i],"-h")==0)
		{	how_to_use(0);
		}
		else /* bpp */
		if(strncmp(argv[i],"-bpp=",5)==0)
		{	sscanf((char*)(argv[i]+5),"%d",&bpp);
			if(bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
				how_to_use(0);
		}
		else /* filename */
		{	snprintf(world_dir_name,sizeof(world_dir_name),"%s",argv[i]);
			printf("world_dir_name=>%s\n",world_dir_name);
		}
	}

	/* try to open worldfile in RW (created if non existant) */
	snprintf(world_file_name,sizeof(world_file_name),"%s/world.wld",world_dir_name);
	fd=open(world_file_name,O_WRONLY | O_CREAT,0666);
	if(fd<0)
	{	printf("Cannot write open %s : %s\n",world_file_name,strerror(errno));
		quit( 1 );
	}
	close(fd);
	
	/* init alea */
	srand(getpid());

	/* First, initialize SDL's video subsystem. */
	if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER) < 0 ) 
	{	fprintf( stderr, "Video initialization failed: %s\n", SDL_GetError( ) );
		quit( 1 );
	}

	/* Let's get some video information. */
	info = SDL_GetVideoInfo( );
	if( !info ) 
	{	fprintf( stderr, "Video query failed: %s\n", SDL_GetError( ) );
		quit( 1 );
	}
	
	if(!bpp)
		bpp=info->vfmt->BitsPerPixel;

	flags=SDL_DOUBLEBUF | SDL_HWSURFACE;
	if(fullscreen)
		flags|= SDL_FULLSCREEN ;
	g_SDL_screen = SDL_SetVideoMode( 800, 600, bpp, flags);
	if( g_SDL_screen == 0 )
	{	fprintf( stderr, "Video mode set failed: %s\n", SDL_GetError( ) );
		quit( 1 );
	}
	else
		printf("Video mode set to %ux%u at %u bpp\n",800, 600, bpp);
		
	/* titre */
	SDL_WM_SetCaption ("Mole Invasion - World editor", NULL);

	/* lecture du fichier de worldmap */
	if(load_worldfile(world_file_name,&all_level_desc,&world_infos) == -1)
	{	printf("Error on load_worldfile !\n");
		quit(1);
	}
	
	/* init des dessins */
	draw_foregrnd(DO_INIT,world_infos);

	/* we've got all levels described in world file
	let's add all levels in the directory */
	if(!(mydir=opendir(world_dir_name)))
	{	perror(world_dir_name);
		quit(1);
	}

	while((direntry=readdir(mydir)))
	{	char level_file_name[512];
		char * pos=direntry->d_name+strlen(direntry->d_name)-strlen(LEVEL_EXTENSION);
		level_desc local_level_read;
		level_info level_infos;
		int alreadypresent=0;
		
		/*printf("%s(%s)\n",direntry->d_name,pos);*/
		if(strcmp(pos,LEVEL_EXTENSION))
			continue;
		for(i=0;i<all_level_desc->size;i++)
		{	level_read=GetPosList(all_level_desc,i);
			/*printf("%d:%s<=>%s\n",i,level_read->fic_name,direntry->d_name);*/
			if(!strcmp(level_read->fic_name,direntry->d_name))
			{	alreadypresent=1;
				break;
			}
		}
		if(alreadypresent)
			continue;
	
		snprintf(level_file_name,sizeof(level_file_name),"%s/%s",world_dir_name,direntry->d_name);
		if(load_levelinfos(level_file_name,&level_infos) != -1)
		{	memset(&local_level_read,0,sizeof(local_level_read));
			snprintf(local_level_read.level_name,sizeof(local_level_read.level_name),"%s",level_infos.level_name);
			snprintf(local_level_read.fic_name,sizeof(local_level_read.fic_name),"%s",direntry->d_name);
			AddToList(all_level_desc,&local_level_read,sizeof(level_desc));
			printf("Add %s (%s) not yet in world.wld\n",local_level_read.level_name,direntry->d_name);
		}
	}
	closedir(mydir);

	/* open all levels (and push if out of bounds) */
	for(i=0;i<all_level_desc->size;i++)
	{	level_read=GetPosList(all_level_desc,i);
		level_read->level_status=OPEN;
		if(level_read->posX<20)
			level_read->posX=20;
		if(level_read->posX>750)
			level_read->posX=750;
		if(level_read->posY<20)
			level_read->posY=20;
		if(level_read->posY>650)
			level_read->posY=650;
		/* level_id correct ? */
		if(level_read->level_id<1)
		{	static unsigned int level_id_test=1;
			while(GetPosListById(all_level_desc,level_id_test))
				level_id_test++;
			level_read->level_id=level_id_test;
			level_id_test++;
		}
		/* display */
		printf("Init %.3u [%.3u %.3u] {id=%.3u} '%s' '%s'\n",
			i,level_read->posX,level_read->posY,level_read->level_id,
			level_read->fic_name,level_read->level_name);
	}

	/* font initialisation */
	{SDL_Color myText_bg={255,255,255};
	SDL_Color myText_fg={255,20,20};
	font_select(FONT_NAME,25,myText_fg,myText_bg,180);
	}

	while(1)
	{	/* world en cours */
		int current_level_id=0;
		
		/* init des dessins */
		draw_world(DO_INIT,world_infos,all_level_desc);

		/* ré-init des évènements */
		events_init();

		needreload=0;
		while(!needreload)
		{	/* dessin du niveau */
			draw_world(DO_DRAW,world_infos,all_level_desc);
			draw_foregrnd(DO_DRAW,world_infos);
			if(current_level_id>0)
				draw_level_name(current_level_id,all_level_desc);
			
			/* envoi au hard */
			My_Flip();

			/* on bloque à 30 FPS */
			coef_frame_rate(show_FPS);

			/* déplacements de player + espace */
			current_level_id=process_events();
			/*printf("current=%d\n",current_level_id);*/
		}

		/* free de dessin du niveau */
		draw_world(DO_FREE,world_infos,all_level_desc);
	}
	/* free de dessin du niveau */
	draw_foregrnd(DO_FREE,world_infos);

	FreeList(all_level_desc);
	return 0;
}
