#include<sys/stat.h>
#include<sys/unistd.h>

#include "game.h"

static unsigned int eventColor=0x80<<24;

int selectIntroItem()
{
	switch(game.menuitem) {
	case 0: setMode(GAME_PLAY); break;
	case 1: setMode(GAME_EDITOR); break;
	case 2: setMode(GAME_HIGHSCORE); break;
	case 3: setMode(GAME_EXTRAS); break;
	case 4: setMode(GAME_RULES); break;
	case 5: setMode(GAME_QUIT); return 1;
	}
	return 0;
}

int selectExtrasItem()
{
	switch(game.menuitem) {
	case 0: setMode(GAME_CREDITS); break;
	case 1: setMode(GAME_PLAYINTRO); break;
	case 2: setMode(GAME_SUBWAY); break;
	case 3: setMode(GAME_INTRO); break;
	}
	return 0;
}

int selectEditorItem()
{
	int x,y;
	
	switch(game.menuitem) {
	case 0:
		// new level
		if(game.map) free(game.map);
		game.map=0;
		game.mapWidth=40;
		game.mapHeight=40;
		game.map=calloc(sizeof(struct Map),128*128);
		for(y=0;y<128;y++) {
			for(x=0;x<128;x++) {
				game.map[x+128*y].tile=&tileset[1];
			}
		}
printf("game first character is %08x\n",(int)game.firstCharacter);
		setMode(GAME_EDITOR_PLACE);
		break;
	case 1:
		// load level -- need to select the name
		setMode(GAME_EDITOR_LOAD);
		break;
	case 2:
		// save level -- need to select the name
		setMode(GAME_EDITOR_SAVE);
		break;
	case 3:
		setMode(GAME_INTRO);
		break;
	}
	return 0;
}

int selectPauseItem()
{
	switch(game.menuitem) {
	case 0:
		game.mode=GAME_PLAY;
		break;
	case 1:
		setMode(GAME_RULESPAUSE);
		break;
	case 2:
		setMode(GAME_INTRO);
		break;
	}
	return 0;
}

int selectEditorPlaceItem()
{
	int x=game.player->x/TILE_WIDTH;
	int y=game.player->y/TILE_HEIGHT;
	if(x<0 || y<0 || x>=game.mapWidth || y>=game.mapHeight) {
		printf("Bad select tile location (%dx%d).\n",x,y);
		return 0;
	}
	if(game.menuitem<0 || game.menuitem+1>=tilesetCount) {
		printf("Bad select tile to be changing to (%d).\n",game.menuitem);
		return 0;
	}
	printf("Placing tile %d at %d,%d\n",game.menuitem,x,y);
	game.map[x+game.mapWidth*y].tile=&tileset[game.menuitem+1];
	return 0;
}

void selectEditorSave()
{
	char oldbuf[256];
	char buf[256];
#ifndef WIN32
	mkdir("map",0777);
#else
	mkdir("map");
#endif
	sprintf(oldbuf,"map/level%03d.old",game.level);
	unlink(oldbuf);
	sprintf(buf,"map/level%03d.lvl",game.level);
	rename(buf,oldbuf);
	FILE *file=fopen(buf,"w");
	if(file) {
		int x,y;
		fprintf(file,"# Created with the built in level editor\n"
		"w=%d\nh=%d\n",game.mapWidth,game.mapHeight);

		for(y=0;y<game.mapHeight;y++) {
			for(x=0;x<game.mapWidth;x++) {
				fprintf(file,"%d%s",game.map[x+y*game.mapWidth].tile->id,
				x<game.mapWidth-1?",":",\n");
			}
		}
		fprintf(file,"\n");
		fclose(file);
	}
	setMode(GAME_EDITOR_PLACE);
}

void selectEditorLoad()
{
	loadLevel(game.level);
	setMode(GAME_EDITOR_PLACE);
}

int handleKey(int key,int up)
{
	if( key==27) return handleJoy(BT_START,up);
	if( key==7) return handleJoy(BT_TRIANGLE,up);
	if( key=='z') return handleJoy(BT_TRIANGLE,up);
	if( key==' ') return handleJoy(BT_SQUARE,up);
	if( key==13) return handleJoy(BT_CROSS,up);
	if( key==8) return handleJoy(BT_CIRCLE,up);
	if( key=='h' || key==276) return handleJoy(BT_LEFT,up);
	if( key=='j' || key==274) return handleJoy(BT_DOWN,up);
	if( key=='k' || key==273) return handleJoy(BT_UP,up);
	if( key=='l' || key==275) return handleJoy(BT_RIGHT,up);
	if( key=='o') return handleJoy(BT_LTRIGGER,up);
	if( key=='p') return handleJoy(BT_RTRIGGER,up);
	return 0;
}

int updown[16]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};

extern int dir_x[9];
extern int dir_y[9];

struct Map *nearbyPlayer(int i,enum TileType type,int *x,int *y)
{
	struct Map *map;

	if(!game.player) return 0;	
	
	*x=game.player->x+game.player->tile->w/2;
	*y=game.player->y+game.player->tile->h-1;
	(*x)/=TILE_WIDTH;
	(*y)/=TILE_HEIGHT;
	*x+=dir_x[i];
	*y+=dir_y[i];
	// Now look in that direction:
	if(*x<0 || *x>=game.mapWidth || *y<0 || *y>=game.mapHeight) {
		return NULL;
	}
	map=game.map+ *x + game.mapWidth*(*y);
	if(map->tile->type==type) {
		return map;
	}
	
	return NULL;
}

struct Character *nearbyPlayerNPC()
{
	struct Character *c;
	
	for(c=game.firstCharacter;c;c=c->next) {
		if(c->type==CHAR_NPC) {
			int dx=c->x-game.player->x;
			int dy=c->y-game.player->y;
			if(dx<0) dx=-dx;
			if(dy<0) dy=-dy;
			if(dx*dx+dy*dy<4*TILE_WIDTH*TILE_HEIGHT) {
				return c;
			}
		}
	}
	
	return 0;
}

char *dirname[]={"North","East","South","West"};

const char *playerExitDir()
{
	return dirname[rand()%4];
}

void showPoints(int points,int x,int y)
{
	if(points) {
		int amount=1;
		if(points>100) amount=0;
		if(points<100) amount=2;
		if(points<50) amount=3;
		if(points>500) amount=4;
		struct Character *pt=newCharacter(CHAR_POINTS,pointtile+amount,x,y);
		pt->next=game.player->next;
		game.player->next=pt;
		game.characterCount++;
		pt->tx=pt->x;
		pt->ty=pt->y-TILE_HEIGHT*3;
		pt->dx=0;
		pt->dy=-MAXDELTA/2;
	}
}

const char *playerComment(struct Character *c)
{
	const char *comment=c->comment;
	int commentPoints=c->commentPoints;
	static int newgame_commentId=0;
	
	if(newgame_commentId<newgame_commentCount) {
		// Do it all from the new game comments.
		game.score+=newgame_comment[newgame_commentId].points;
		game.newScoreTimer=NEWSCOREDUR;
		showPoints(newgame_comment[newgame_commentId].points,c->x,c->y);
		return newgame_comment[newgame_commentId++].comment;
	}
	
	game.score+=commentPoints;
	game.newScoreTimer=NEWSCOREDUR;
	if(commentPoints!=0) c->comment="Shouldn't you be finding the exit?";
	c->commentPoints=0;
	showPoints(commentPoints,c->x,c->y);
	return comment;
}

int handleJoy(int button,int up)
{
/*	if( button==BT_START) {
		setMode(GAME_QUIT);
		return 1;	// quit please.
	}*/
	if(game.mode==GAME_SUBWAY) return;
	
	updown[button]=up;
	if(game.mode==GAME_PLAY && up) {
		int x,y;
		int i;
		struct Map *map;
		for(i=0;i<9;i++) {
			if(button==BT_TRIANGLE) {	// Open door
				// Find a door if any.
				map=nearbyPlayer(i,MAP_DOOR,&x,&y);
				if(map && game.keys>0) {
					game.keys--;
					game.map[x+y*game.mapWidth].tile=&tileset[20];
					playSfx(S_DOOROPENS);
					insertMessage("The door opens, passkey used.",avatar+4,(0x80<<24)+(0x80<<8),2000);
				} else if(map) {
					playSfx(S_DOORLOCKED);
					insertMessage("You don't have that passkey!",avatar+4,(0x80<<24)+(0x80<<16),2000);
				}
				map=nearbyPlayer(i,MAP_EXIT,&x,&y);
				if(map) {
					insertMessage("You left that floor.  Congrats.",avatar+4,(0x80<<24)+(0x80<<8),2000);
					playSfx(S_LEVELCOMPLETE);
					loadLevel(game.level+1);
					//setMode(GAME_SUMMARY);
				}
			} else if(button==BT_CROSS) {	// Search desk
				map=nearbyPlayer(i,MAP_DESK,&x,&y);
				if(map) {
					int count=0;
					if(map->flags&MAPF_KEY) {
						game.keys++;
						playSfx(S_POWERUP);
						map->flags^=MAPF_KEY;
						insertMessage("You got a passkey",avatar+4,eventColor,2000);
						count++;
					}
					if(map->flags&MAPF_CANDY) {
						playSfx(S_POWERUP);
						map->flags^=MAPF_CANDY;
						insertMessage("Snack-o-ramma",avatar+6,eventColor,2000);
						game.score+=175;
						game.newScoreTimer=NEWSCOREDUR;
						showPoints(175,x*TILE_WIDTH,y*TILE_HEIGHT);
						count++;
					}
					if(map->flags&MAPF_BOTTLE) {
						playSfx(S_POWERUP);
						map->flags^=MAPF_BOTTLE;
						insertMessage("A refreshing drink",avatar+5,eventColor,2000);
						game.health-=25;
						game.newHealthTimer=NEWHEALTHDUR;
						if(game.health<0) game.health=0;
						count++;
					}
					if(count==0) {
						insertMessage("Desk empty",map->tile,eventColor,500);
					}
				}
			} else if(button==BT_CIRCLE) {	// Search plant, water, etc.
				map=nearbyPlayer(i,MAP_ITEM,&x,&y);
				if(map) {
					int count=0;
					if(map->flags&MAPF_CANDY) {
						playSfx(S_POWERUP);
						map->flags^=MAPF_CANDY;
						insertMessage("Snack-o-ramma",avatar+6,eventColor,2000);
						game.score+=175;
						game.newScoreTimer=NEWSCOREDUR;
						showPoints(175,x*TILE_WIDTH,y*TILE_HEIGHT);
						count++;
					}
					if(map->flags&MAPF_BOTTLE) {
						playSfx(S_POWERUP);
						map->flags^=MAPF_BOTTLE;
						insertMessage("A refreshing drink",avatar+5,eventColor,2000);
						game.health-=25;
						game.newHealthTimer=NEWHEALTHDUR;
						if(game.health<0) game.health=0;
						count++;
					}
					if(map->flags&MAPF_SPECIAL) {
						static char specialMsg[80];
						const char *specialFmt[]={
							"%s that goes Bing!",
							"%s of Protection",
							"Mystic %s",
							"Legendary %s",
							"%s of Doom",
							"Invisible %s",
							"%s of Wonder",
							"Doppelganger %s",
							"%s of Drinking"};
						playSfx(S_SPECIAL);
						map->flags^=MAPF_SPECIAL;
						sprintf(specialMsg,specialFmt[game.level%9],avatar[7+(game.level%4)].name);
						insertMessage(specialMsg,avatar+7+(game.level%4),0x80800000,4000);
						game.score+=1000*game.level;
						game.newScoreTimer=NEWSCOREDUR;
						int i;
						for(i=0;i<game.level;i++)
							showPoints(1000,x*TILE_WIDTH,y*TILE_HEIGHT-i*16);
						count++;
					}
					if(count==0 && map->tile->id!=3) {
						insertMessage("Nothing here",map->tile,eventColor,2000);
					}
				}
			}
		}
		// Near by NPC, talk to them
		if(button==BT_SQUARE) {
			struct Character *c=nearbyPlayerNPC();
			if(c) {
				char buf[256];
				int id=(-c->tile->id-1)/4;
				if(id<0 || id>3) id=0;
				sprintf(buf,"%s: %s",c->name,playerComment(c));
				insertMessage(buf,c->tile,eventColor,1000);
			}
		}
		// Clear dialog clutter.
		if(button==BT_RTRIGGER) {
			struct Message *m;
			for(m=game.firstMessage;m;m=m->next) {
				m->teletypeDelay=10;
				m->timeToLiveTimer=10*(strlen(m->message)-m->teletypePos)+1;
			}
		}
	}
	if(game.mode==GAME_PLAY || game.mode==GAME_EDITOR_PLACE) {
		if( button==BT_LEFT) {
			game.player->dx=up?0:-MAXDELTA;
			game.player->dy=0;
			game.player->tile=&playerTileDir[TLEFT];
		} else if( button==BT_RIGHT) {
			game.player->dx=up?0:MAXDELTA;
			game.player->dy=0;
			game.player->tile=&playerTileDir[TRIGHT];
		} else if( button==BT_UP) {
			game.player->dx=0;
			game.player->dy=up?0:-MAXDELTA;
			game.player->tile=&playerTileDir[TUP];
		} else if( button==BT_DOWN) {
			game.player->dx=0;
			game.player->dy=up?0:MAXDELTA;
			game.player->tile=&playerTileDir[TDOWN];
		}
		if(game.mode==GAME_EDITOR_PLACE && up==0) {
			if(button==BT_LTRIGGER) {
				if(game.menuitem>0) {
					game.menuitem--;
					playSfx(S_DOOROPENS);
				} else {
					playSfx(S_DOORLOCKED);
				}
			}
			if(button==BT_RTRIGGER) {
				if(game.menuitem+1<game.menuitemCount) {
					game.menuitem++;
					playSfx(S_DOOROPENS);
				} else {
					playSfx(S_DOORLOCKED);
				}
			}
			if(button==BT_CROSS) {
				return selectEditorPlaceItem();
			}
			if(button==BT_START) {
				if(game.player) {
					game.player->dx=0;
					game.player->dy=0;
				}
				setMode(GAME_EDITOR);
			}
		}
		if(button==BT_START && up) {
			if(game.player) {
				game.player->dx=0;
				game.player->dy=0;
			}
			setMode(GAME_PAUSE);	// temporary, for level editors
		}
	} else if(game.mode==GAME_EDITOR_LOAD || game.mode==GAME_EDITOR_SAVE) {
		if(up==0) {
			if(button==BT_CROSS || button==BT_RIGHT) {
				if(game.mode==GAME_EDITOR_LOAD)
					selectEditorLoad();
				else
					selectEditorSave();
				return 0;
			}
			if(button==BT_UP) game.level++;
			if(button==BT_DOWN) game.level--;
			if(game.level<1) game.level=1;
		}
	} else if(game.mode==GAME_NEWHIGH) {
		if(button==BT_UP && up==1) {
			if(game.menuitem-12>=0) {
				game.menuitem-=12;
				playSfx(S_DOOROPENS);
			} else {
				playSfx(S_DOORLOCKED);
			}				
		} else if(button==BT_DOWN && up==1) {
			if(game.menuitem+12<game.menuitemCount) {
				game.menuitem+=12;
				playSfx(S_DOOROPENS);
			} else {
				playSfx(S_DOORLOCKED);
			}
		} else if(button==BT_LEFT && up==1) {
			if(game.menuitem>0) {
				game.menuitem--;
				playSfx(S_DOOROPENS);
			} else {
				playSfx(S_DOORLOCKED);
			}				
		} else if(button==BT_RIGHT && up==1) {
			if(game.menuitem+1<game.menuitemCount) {
				game.menuitem++;
				playSfx(S_DOOROPENS);
			} else {
				playSfx(S_DOORLOCKED);
			}
		} else if(button==BT_CROSS && up==1) {
			if(strlen(game.name)<15) {
				game.name[strlen(game.name)+1]=0;
				game.name[strlen(game.name)]=alphabet[game.menuitem];
				playSfx(S_POWERUP);
			} else {
				playSfx(S_DOORLOCKED);
			}
		} else if(button==BT_SQUARE && up==1) {
			if(strlen(game.name)>0) {
				game.name[strlen(game.name)-1]=0;
				playSfx(S_POWERUP);
			} else {
				playSfx(S_DOORLOCKED);
			}
		} else if(button==BT_TRIANGLE && up==1) {
			playSfx(S_LEVELCOMPLETE);
			saveHighScore();
			setMode(GAME_INTRO);
		}
	} else {
		if(button==BT_UP && up==1) {
			if(game.menuitem>0) {
				game.menuitem--;
				playSfx(S_DOOROPENS);
			} else {
				playSfx(S_DOORLOCKED);
			}				
		} else if(button==BT_DOWN && up==1) {
			if(game.menuitem+1<game.menuitemCount) {
				game.menuitem++;
				playSfx(S_DOOROPENS);
			} else {
				playSfx(S_DOORLOCKED);
			}
		} else if(button==BT_CROSS && up==1) {
			if(game.mode==GAME_INTRO) return selectIntroItem();
			if(game.mode==GAME_EXTRAS) return selectExtrasItem();
			if(game.mode==GAME_EDITOR) return selectEditorItem();
			if(game.mode==GAME_PAUSE) return selectPauseItem();
			if(game.mode==GAME_HIGHSCORE) setMode(GAME_INTRO);
		}
		if(game.mode==GAME_PLAYINTRO && up==1) setMode(GAME_INTRO);
	}
	return 0;
}

static int ax,ay;

int handleAnalog(int axis,int value)
{
	if(game.mode==GAME_SUBWAY) return 0;
	
	if(axis==0) {
		ax=value;
		// Implement a dead zone.
		if(ax>100 && ax<156) ax=100;
		else if(ax>156) ax-=56;
		ax-=100;
	}
	if(axis==1) {
		ay=value;
		// Implement a dead zone.
		if(ay>100 && ay<156) ay=100;
		else if(ay>156) ay-=56;
		ay-=100;
	}
//return 0;	// disabled for now.
	//printf("Lx: %d, Ly: %d; ",ax,ay);
	if(updown[BT_UP]==0 || updown[BT_LEFT]==0 || updown[BT_DOWN]==0 || updown[BT_RIGHT]==0) {
		// analog is lower priority.
		return 0;
	}
	
	if(game.mode==GAME_PLAY || game.mode==GAME_EDITOR_PLACE) {
		game.player->dx=(ax)*MAXDELTA/100;
		game.player->dy=(ay)*MAXDELTA/100;
		
		//printf("ax,y=%d,%d; dx,dy=%d,%d\n",ax,ay,game.player->dx,game.player->dy);
		updateFacing(game.player);
	}
	return 0;
}
