//mapselection.cpp
//let the user select a map

#include <stdio.h>
#include <string.h>
#include "gamemem.h"
#include "fileio.h"
#include "gameinitexit.h"
#include "parser.h"
#include "config.h"
#include "environment.h"
#include "interfaceutil.h"
#include "mapselection.h"
#include "reg_tool_3.h"
#include "controls.h"

#define kMaxMaps 1024
#define kMaxEnvironments 64

char *StripName(char *aName)
{
	while(*aName==' '||*aName=='\t')aName++;
	while(*aName=='\255')
	{
		aName++;
		while(*aName!='\255'&&*aName!=0)
			aName++;
		if(*aName=='\255')
			aName++;
		while(*aName==' '||*aName=='\t')aName++;	
	}	
	return aName;
}

int CompareMaps(const void *a,const void *b)
{
	tMapInfo *mapa=(tMapInfo*)FileGetParsedDataPtr(*(tFileRef*)a,kParserTypeMapInfoDesc,sizeof(tMapInfo));
	tMapInfo *mapb=(tMapInfo*)FileGetParsedDataPtr(*(tFileRef*)b,kParserTypeMapInfoDesc,sizeof(tMapInfo));
	return _stricmp(StripName(mapa->name),StripName(mapb->name));
}

//get a list of available map files
void GetAvailableMaps(int *availableMaps,int *mapCount,int demoOnly)
{
	*mapCount=0;
	for(int i=0;i<gFileTableSize;i++)
		if(*mapCount<kMaxMaps)
			if(char *extension=FileGetExtension(i))
				if(!_stricmp(extension,kFileTypeMapDefinition))
				{
					tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(i,kParserTypeMapInfoDesc,sizeof(tMapInfo));
					int demook=false;
					if(i==FileGetReference("city2.mapinfo"))demook=true;
					if(i==FileGetReference("highspeed.mapinfo"))demook=true;
					if(!mapInfo->hideMap&&(demook||!demoOnly))
						availableMaps[(*mapCount)++]=i;
				}
	qsort(availableMaps,*mapCount,sizeof(tFileRef),CompareMaps);
}

//get a list of available environment files
void GetAvailableEnvironments(int *availableEnvironments,int *environmentCount,int timeTrial)
{
	*environmentCount=0;
	for(int i=0;i<gFileTableSize;i++)
		if(*environmentCount<kMaxEnvironments)
			if(char *extension=FileGetExtension(i))
				if(!_stricmp(extension,kFileTypeEnvironmentDefinition))
				{
					int ok=false;
					if(i==FileGetReference("daylight.env"))ok=true;
					if(i==FileGetReference("night.env"))ok=true;
					if(i==FileGetReference("rain.env"))ok=true;
					if(i==FileGetReference("snow.senv"))ok=true;
					if(i==FileGetReference("sunset.env"))ok=true;
					if(!timeTrial||ok)
						availableEnvironments[(*environmentCount)++]=i;
				}
}

void SelectNextMap(tFileRef *map)
{
	int availableMaps[kMaxMaps];
	int mapCount;
	int selection=0;
	
	GetAvailableMaps(availableMaps,&mapCount,!RT3_IsRegistered());
	for(int i=0;i<mapCount;i++)
		if(*map==availableMaps[i])
			selection=i;
	
	selection=(selection+1)%mapCount;
		
	*map=availableMaps[selection];
	gConfig->lastRoad=*map;
}

void SelectPrevMap(tFileRef *map)
{
	int availableMaps[kMaxMaps];
	int mapCount;
	int selection=0;
	
	GetAvailableMaps(availableMaps,&mapCount,!RT3_IsRegistered());
	for(int i=0;i<mapCount;i++)
		if(*map==availableMaps[i])
			selection=i;
	
	selection--;
	if(selection<0)
		selection+=mapCount;

	*map=availableMaps[selection];
	gConfig->lastRoad=*map;
}

int SelectMapByChar(char ch)
{
	tFileRef availableMaps[kMaxMaps];
	int mapCount;
	GetAvailableMaps(availableMaps,&mapCount,false);

	for(int i=0;i<mapCount;i++)
	{
		tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[i],kParserTypeMapInfoDesc,sizeof(tMapInfo));
		if(toupper(StripName(mapInfo->name)[0])>=ch)
			return i;
	}
	return mapCount-1;
}

typedef struct{
	float t;
	int *mapSelection;
	int (*Callback)(void*);
	void *userData;	
} tMapSelectionCallbackUserData;


enum{
	kMapSelectionMap,
	kMapSelectionReverse,
	kMapSelectionLaps,
	kMapSelectionEnvironment,
//	kMapSelectionMode,
	kMapSelectionAccept,
	kMapSelectionExit,
	kNumMapSelectionItems
};

int MapSelectionCallback(void *ud)
{
	char ch=toupper(PeekKeyInput(NULL));
	if(ch>='A'&&ch<='Z')
	{
		*((tMapSelectionCallbackUserData*)ud)->mapSelection=SelectMapByChar(ch);
		GetKeyInput(NULL);
		return kNumMapSelectionItems;
	}
	if(((tMapSelectionCallbackUserData*)ud)->Callback)
		return ((tMapSelectionCallbackUserData*)ud)->Callback(((tMapSelectionCallbackUserData*)ud)->userData);
	return -1;
}

int InterfaceMapSelection(tGameInfo *gInfo,int (*Callback)(void*),void *userData,int timeTrial)
{
	tFileRef availableMaps[kMaxMaps];
	int availableEnvironments[kMaxEnvironments];
	int mapSelection=0;
	int environmentSelection=0;
	int mapCount,environmentCount;
	int lapCount=gConfig->lastLaps;
	int reverse=gConfig->reverse;
	
	tMapSelectionCallbackUserData ud;
	ud.t=INFINITY;
	ud.mapSelection = &mapSelection;
	ud.Callback=Callback;
	ud.userData=userData;
	
	GetAvailableMaps(availableMaps,&mapCount,false);
	for(int i=0;i<mapCount;i++)
		if(gConfig->lastRoad==availableMaps[i])
			mapSelection=i;
	GetAvailableEnvironments(availableEnvironments,&environmentCount,timeTrial);
	for(int i=0;i<environmentCount;i++)
		if(gConfig->lastEnv==availableEnvironments[i])
			environmentSelection=i;

	tInterfaceMenuDescribtion menu;
	InterfaceInitMenu(&menu,kNumMapSelectionItems,"Select Map");
	menu.RenderCallback=InterfaceRenderReplay;
	InterfaceMenuZoomAnimation(&menu,-1,true);

	menu.items[kMapSelectionReverse-1].lineSpacing*=1.5;
	menu.items[kMapSelectionAccept-1].lineSpacing*=4.25;
	strcpy(menu.items[kMapSelectionExit].label,"Cancel");
	menu.imageXScale=kMapImageXStretch;
	menu.imageYScale=kMapImageYStretch;	
	menu.imageXPos+=0.1;
	menu.imageYPos-=0.03;
	menu.TimerCallback=MapSelectionCallback;
	menu.userData=&ud;
	menu.returnOnSpace=true;
	
	for(int i=0;i<=kMapSelectionEnvironment;i++)
		menu.items[i].flags|=kInterfaceMenuItemArrowInput;

	for(int i=kMapSelectionReverse;i<=kMapSelectionEnvironment;i++)
	{
		menu.items[i].size*=0.8;
		menu.items[i].lineSpacing*=0.8;
	}
		
	int exit=false;
	int sel;
		
	do{
		tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[mapSelection],kParserTypeMapInfoDesc,sizeof(tMapInfo));
		tEnvironment *environment=(tEnvironment*)FileGetParsedDataPtr(availableEnvironments[environmentSelection],kParserTypeEnvironmentDesc,sizeof(tEnvironment));
		int demook=false;
		if(availableMaps[mapSelection]==FileGetReference("city2.mapinfo"))demook=true;
		if(availableMaps[mapSelection]==FileGetReference("highspeed.mapinfo"))demook=true;
		menu.image=mapInfo->image;
		
		if(demook||RT3_IsRegistered())
		{
			menu.imageAlpha=1.0;
			strcpy(menu.items[kMapSelectionAccept].label,"Accept");
			menu.items[kMapSelectionAccept].flags=0;
			if((!mapInfo->loop)||gInfo->numLaps==-1)
				menu.items[kMapSelectionLaps].flags|=kInterfaceMenuItemDisabled;
			else
				menu.items[kMapSelectionLaps].flags&=~kInterfaceMenuItemDisabled;
			menu.items[kMapSelectionEnvironment].flags&=~kInterfaceMenuItemDisabled;
			menu.items[kMapSelectionReverse].flags&=~kInterfaceMenuItemDisabled;
		}
		else
		{
			menu.imageAlpha=0.5;
			strcpy(menu.items[kMapSelectionAccept].label,"\255demo.png\255 Not available in demo!!");
			menu.items[kMapSelectionAccept].flags|=kInterfaceMenuItemDisabled;
			menu.items[kMapSelectionLaps].flags|=kInterfaceMenuItemDisabled;
			menu.items[kMapSelectionEnvironment].flags|=kInterfaceMenuItemDisabled;
			menu.items[kMapSelectionReverse].flags|=kInterfaceMenuItemDisabled;
		}
			
		sprintf(menu.items[kMapSelectionMap].label,"Selected Map: \255#a\255%s",mapInfo->name);
		sprintf(menu.items[kMapSelectionReverse].label,"Direction: \255#a\255%s",reverse?"Reverse":"Normal");
		if(gInfo->numLaps!=-1)
			if(!mapInfo->loop)
				sprintf(menu.items[kMapSelectionLaps].label,"Number of Laps: \255#a\255Not Looped");
			else
				sprintf(menu.items[kMapSelectionLaps].label,"Number of Laps: \255#a\255%d",lapCount);
		else
			sprintf(menu.items[kMapSelectionLaps].label,"Number of Laps: \255#a\255Unlimited");
		if(mapInfo->useAltEnv&&environment->hasAltEnv)
			environment=(tEnvironment*)FileGetParsedDataPtr(environment->altEnv,kParserTypeEnvironmentDesc,sizeof(tEnvironment));
		sprintf(menu.items[kMapSelectionEnvironment].label,"Weather: \255#a\255%s",environment->name);

		sel=InterfaceGetUserMenuSelection(&menu);
		if(sel==kNumMapSelectionItems)
			menu.initialSelection=0;
		else
			switch(menu.initialSelection=(sel&kInterfaceMenuItemMask))
			{
				case kMapSelectionMap:
					if(sel&kInterfaceMenuLeftArrow)
						do{
							mapSelection--;
							if(mapSelection<0)mapSelection=mapCount-1;
							mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[mapSelection],kParserTypeMapInfoDesc,sizeof(tMapInfo));
						}while(gInfo->numLaps==-1&&!mapInfo->loop);
					else if(sel&kInterfaceMenuRightArrow)
						do{
							mapSelection=(mapSelection+1)%mapCount;
							mapInfo=(tMapInfo*)FileGetParsedDataPtr(availableMaps[mapSelection],kParserTypeMapInfoDesc,sizeof(tMapInfo));
						}while(gInfo->numLaps==-1&&!mapInfo->loop);
					else if(mapInfo->demoAvailable||RT3_IsRegistered())
						exit=true;
					break;
					
				case kMapSelectionReverse:
					if(sel&(kInterfaceMenuRightArrow|kInterfaceMenuLeftArrow))
						reverse=!reverse;
					else if(mapInfo->demoAvailable||RT3_IsRegistered())
						exit=true;
					break;
					
				case kMapSelectionLaps:
					if(sel&kInterfaceMenuLeftArrow){
						lapCount--;
						if(lapCount<1)lapCount=kMaxLaps;
					}
					else if(sel&kInterfaceMenuRightArrow){
						lapCount++;
						if(lapCount>kMaxLaps)lapCount=1;					
					}
					else if(mapInfo->demoAvailable||RT3_IsRegistered())
						exit=true;
					break;
					
				case kMapSelectionEnvironment:
					if(sel&kInterfaceMenuLeftArrow){
						environmentSelection--;
						if(environmentSelection<0)environmentSelection=environmentCount-1;
					}
					else if(sel&kInterfaceMenuRightArrow)
						environmentSelection=(environmentSelection+1)%environmentCount;
					else if(mapInfo->demoAvailable||RT3_IsRegistered())
						exit=true;
					break;
				
	/*			case kMapSelectionMode:
					if(sel&kInterfaceMenuLeftArrow){
						gInfo->arcade--;
						if(gInfo->arcade<0)
							gInfo->arcade=(sel&kInterfaceMenuEasterEgg?2:1);
					}
					else if(sel&kInterfaceMenuRightArrow)
						gInfo->arcade=(gInfo->arcade+1)%(sel&kInterfaceMenuEasterEgg?3:2);
					else exit=true;
					break;
	*/				
				case kInterfaceMenuOK:
				case kMapSelectionAccept:
					if(mapInfo->demoAvailable||RT3_IsRegistered())
						exit=true;
					break;
					
				case kInterfaceMenuEsc:
				case kMapSelectionExit:
					exit=true;
					break;
			}
	}while(!exit);

	InterfaceDisposeMenu(&menu);
	
	sel&=kInterfaceMenuItemMask;
	if(sel!=kInterfaceMenuEsc&&sel!=kMapSelectionExit)
	{
		gInfo->reverse=reverse;
		if(gInfo->numLaps!=-1)
			gInfo->numLaps=lapCount;
		gInfo->map=availableMaps[mapSelection];
		tMapInfo *mapInfo=(tMapInfo*)FileGetParsedDataPtr(gInfo->map,kParserTypeMapInfoDesc,sizeof(tMapInfo));
		if(!mapInfo->loop)
		{
			gInfo->numLaps=1;
		}
		gInfo->environment=availableEnvironments[environmentSelection];
		
		gConfig->lastRoad=availableMaps[mapSelection];
		gConfig->reverse=reverse;
		gConfig->lastLaps=lapCount;
		gConfig->lastEnv=availableEnvironments[environmentSelection];
//		gConfig->arcade=gInfo->arcade;
		return true;
	}
	return false;
}