#ifdef PRECOMPILEDHEADERS
	#include "JA2 All.h"
	#include "Loading Screen.h"
	#include "INIReader.h"
#else
	#include "vsurface.h"
	#include "mapscreen.h"
	#include "Loading Screen.h"
	#include "Campaign Types.h"
	#include "Game Clock.h"
	#include "GameSettings.h"
	#include "Random.h"
	#include "Debug.h"
	#include "local.h"
	#include "Font Control.h"
	#include "font.h"
	#include "render dirty.h"
#endif
#include "Strategic Movement.h"
#include "UndergroundInit.h"
#include <string>
#include "strategicmap.h"

extern HVSURFACE ghFrameBuffer;
extern BOOLEAN gfSchedulesHosed;

#ifdef JA2UB
	#include "Ja25_Tactical.h"
	#include "Ja25 Strategic Ai.h"
#endif
UINT8 gubLastLoadingScreenID = LOADINGSCREEN_NOTHING;
//BOOLEAN bShowSmallImage = FALSE;
SECTOR_LOADSCREENS gSectorLoadscreens[MAX_SECTOR_LOADSCREENS];

static INT16 requestedX, requestedY, requestedZ;
static STR8 szSector;
static STR8 szSectorMap[MAP_WORLD_Y][MAP_WORLD_X] =	{
	{"N",	"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" , "N" , "N" , "N" , "N" , "N" , "N" , "N"	,"N"},

	{"N",	"A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16"	,"N"},
	{"N",	"B1","B2","B3","B4","B5","B6","B7","B8","B9","B10","B11","B12","B13","B14","B15","B16"	,"N"},
	{"N",	"C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13","C14","C15","C16"	,"N"},
	{"N",	"D1","D2","D3","D4","D5","D6","D7","D8","D9","D10","D11","D12","D13","D14","D15","D16"	,"N"},
	{"N",	"E1","E2","E3","E4","E5","E6","E7","E8","E9","E10","E11","E12","E13","E14","E15","E16"	,"N"},
	{"N",	"F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","F13","F14","F15","F16"	,"N"},
	{"N",	"G1","G2","G3","G4","G5","G6","G7","G8","G9","G10","G11","G12","G13","G14","G15","G16"	,"N"},
	{"N",	"H1","H2","H3","H4","H5","H6","H7","H8","H9","H10","H11","H12","H13","H14","H15","H16"	,"N"},
	{"N",	"I1","I2","I3","I4","I5","I6","I7","I8","I9","I10","I11","I12","I13","I14","I15","I16"	,"N"},
	{"N",	"J1","J2","J3","J4","J5","J6","J7","J8","J9","J10","J11","J12","J13","J14","J15","J16"	,"N"},
	{"N",	"K1","K2","K3","K4","K5","K6","K7","K8","K9","K10","K11","K12","K13","K14","K15","K16"	,"N"},
	{"N",	"L1","L2","L3","L4","L5","L6","L7","L8","L9","L10","L11","L12","L13","L14","L15","L16"	,"N"},
	{"N",	"M1","M2","M3","M4","M5","M6","M7","M8","M9","M10","M11","M12","M13","M14","M15","M16"	,"N"},
	{"N",	"N1","N2","N3","N4","N5","N6","N7","N8","N9","N10","N11","N12","N13","N14","N15","N16"	,"N"},
	{"N",	"O1","O2","O3","O4","O5","O6","O7","O8","O9","O10","O11","O12","O13","O14","O15","O16"	,"N"},
	{"N",	"P1","P2","P3","P4","P5","P6","P7","P8","P9","P10","P11","P12","P13","P14","P15","P16"	,"N"},

	{"N",	"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" , "N" , "N" , "N" , "N" , "N" , "N" , "N"	,"N"},
};

// Map LOADINGSCREEN_NOTHING, ..., LOADINGSCREEN_NIGHTBALIME (see enum in header file)
// to some strings which will be used to create the actual filename
// (by appending e.g. "_800x600.sti" or something).
// This is only used when NOT loading them from SectorLoadscreens.xml.
static STR8 LoadScreenNames[LOADINGSCREEN_NIGHTBALIME+1] =
{
	"LS_Heli",
	"LS_DayGeneric",
	"LS_DayTown1",
	"LS_DayTown2",
	"LS_DayWild",
	"LS_DayTropical",
	"LS_DayForest",
	"LS_DayDesert",
	"LS_DayPalace",
	"LS_NightGeneric",
	"LS_NightWild",
	"LS_NightTown1",
	"LS_NightTown2",
	"LS_NightForest",
	"LS_NightTropical",
	"LS_NightDesert",
	"LS_NightPalace",
	"LS_Heli",
	"LS_Basement",
	"LS_Mine",
	"LS_Cave",
	"LS_DayPine",
	"LS_NightPine",
	"LS_DayMilitary",
	"LS_NightMilitary",
	"LS_DaySAM",
	"LS_NightSAM",
	"LS_DayPrison",
	"LS_NightPrison",
	"LS_DayHospital",
	"LS_NightHospital",
	"LS_DayAirport",
	"LS_NightAirport",
	"LS_DayLab",
	"LS_NightLab",
	"LS_DayOmerta",
	"LS_NightOmerta",
	"LS_DayChitzena",
	"LS_NightChitzena",
	"LS_DayMine",
	"LS_NightMine",
	"LS_DayBalime",
	"LS_NightBalime",
};

//returns the UINT8 ID for the specified sector.
// Which for sectors above ground is one of { HELI, DAY, NIGHT }
// if gGameExternalOptions.gfUseExternalLoadscreens.
// Otherwise and for underground sectors this is the actual loadsceen ID.
UINT8 GetLoadScreenID(INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ)
{
	const UINT8 ubSectorID = SECTOR( sSectorX, sSectorY );
	const BOOLEAN fNight = NightTime(); //before 5AM or after 9PM

	requestedX = sSectorX; requestedY = sSectorY; requestedZ = bSectorZ;

	/* User made system - BEGIN */
	if (gGameExternalOptions.gfUseExternalLoadscreens)
	{
		szSector = szSectorMap [sSectorY][sSectorX];
		if (DidGameJustStart())
			return DidGameJustStart() ? HELI : (fNight ? NIGHT : DAY);

		else if (bSectorZ != 0)
			return UNDERGROUND;

		else
			return fNight ? NIGHT : DAY;
		
	} /* WANNE: User made System - END */

	/* WANNE: Sir-Tech System - BEGIN */
	else
	{
		// Which map layer? (ground, basement 1-3)?
		switch( bSectorZ )
		{
			// Ground
			case 0:
			{
				switch( ubSectorID )
				{
					case SEC_A2:
					case SEC_B2:
						return fNight ? LOADINGSCREEN_NIGHTCHITZENA : LOADINGSCREEN_DAYCHITZENA;
					case SEC_A9:
							return DidGameJustStart() ? LOADINGSCREEN_HELI :
								(fNight ? LOADINGSCREEN_NIGHTOMERTA : LOADINGSCREEN_DAYOMERTA);
					case SEC_A10:
						return fNight ? LOADINGSCREEN_NIGHTOMERTA : LOADINGSCREEN_DAYOMERTA;
					case SEC_P3:
						return fNight ? LOADINGSCREEN_NIGHTPALACE : LOADINGSCREEN_DAYPALACE;
					case SEC_H13:
					case SEC_H14: //military installations
					case SEC_I13:
					case SEC_N7:
						return fNight ? LOADINGSCREEN_NIGHTMILITARY : LOADINGSCREEN_DAYMILITARY;
					case SEC_K4:
						return fNight ? LOADINGSCREEN_NIGHTLAB : LOADINGSCREEN_DAYLAB;
					case SEC_J9:
						return fNight ? LOADINGSCREEN_NIGHTPRISON : LOADINGSCREEN_DAYPRISON;
					case SEC_D2:
					case SEC_D15:
					case SEC_I8:
					case SEC_N4:
						return fNight ? LOADINGSCREEN_NIGHTSAM : LOADINGSCREEN_DAYSAM;
					case SEC_F8:
						return fNight ? LOADINGSCREEN_NIGHTHOSPITAL : LOADINGSCREEN_DAYHOSPITAL;
					case SEC_B13:
					case SEC_N3:
						return fNight ? LOADINGSCREEN_NIGHTAIRPORT : LOADINGSCREEN_DAYAIRPORT;
					case SEC_L11:
					case SEC_L12:
						return fNight ? LOADINGSCREEN_NIGHTBALIME : LOADINGSCREEN_DAYBALIME;
					case SEC_H3:
					case SEC_H8:
					case SEC_D4:
						return fNight ? LOADINGSCREEN_NIGHTMINE : LOADINGSCREEN_DAYMINE;
				}

				SECTORINFO *pSector = &SectorInfo[ ubSectorID ];
				switch( pSector->ubTraversability[ THROUGH_STRATEGIC_MOVE ] )
				{
					case TOWN:
						return Random(2) > 0 ?
							(fNight ? LOADINGSCREEN_NIGHTTOWN2 : LOADINGSCREEN_DAYTOWN2) :
							(fNight ? LOADINGSCREEN_NIGHTTOWN1 : LOADINGSCREEN_DAYTOWN1);
					case SAND:
					case SAND_ROAD:
						return fNight ? LOADINGSCREEN_NIGHTDESERT : LOADINGSCREEN_DAYDESERT;
					case FARMLAND:
					case FARMLAND_ROAD:
					case ROAD:
						return fNight ? LOADINGSCREEN_NIGHTGENERIC : LOADINGSCREEN_DAYGENERIC;
					case PLAINS:
					case SPARSE:
					case HILLS:
					case PLAINS_ROAD:
					case SPARSE_ROAD:
					case HILLS_ROAD:
						return fNight ? LOADINGSCREEN_NIGHTWILD : LOADINGSCREEN_DAYWILD;
					case DENSE:
					case SWAMP:
					case SWAMP_ROAD:
					case DENSE_ROAD:
						return fNight ? LOADINGSCREEN_NIGHTFOREST : LOADINGSCREEN_DAYFOREST;
					case TROPICS:
					case TROPICS_ROAD:
					case WATER:
					case NS_RIVER:
					case EW_RIVER:
					case COASTAL:
					case COASTAL_ROAD:
						return fNight ? LOADINGSCREEN_NIGHTTROPICAL : LOADINGSCREEN_DAYTROPICAL;
					default:
						Assert( 0 );
						return fNight ? LOADINGSCREEN_NIGHTGENERIC : LOADINGSCREEN_DAYGENERIC;
				}
			/* WANNE: Sir-Tech System */
		}
#ifdef JA2UB

		case 1:
		{
			switch( ubSectorID )
			{
				case SEC_I13:
				case SEC_J13:
					return fNight ? LOADINGSCREEN_MINE : LOADINGSCREEN_MINE;
				//tunnels
				case SEC_J14:
				case SEC_K14:
					return LOADINGSCREEN_TUNNELS;
				case SEC_K15:
				{
					if( gJa25SaveStruct.ubLoadScreenStairTraversal == LS__GOING_UP_STAIRS )
						return  LOADINGSCREEN_UP_STAIRS;
					else if( gJa25SaveStruct.ubLoadScreenStairTraversal == LS__GOING_DOWN_STAIRS )
						return LOADINGSCREEN_DOWN_STAIRS;
					else
						return LOADINGSCREEN_COMPLEX_BASEMENT_GENERIC;
				}
				default:
					return LOADINGSCREEN_BASEMENT;
			}
		}
		case 2:
		{
			switch( ubSectorID )
			{
				case SEC_K15:
				{	
					//if we are going up stairs, else traversing at same level
					if( gJa25SaveStruct.ubLoadScreenStairTraversal == LS__GOING_UP_STAIRS )
						return LOADINGSCREEN_UP_STAIRS;
					else if( gJa25SaveStruct.ubLoadScreenStairTraversal == LS__GOING_DOWN_STAIRS )
						return LOADINGSCREEN_DOWN_STAIRS;
					else
						return LOADINGSCREEN_COMPLEX_BASEMENT;
				}
				case SEC_L15:
				{
					//if we are going up stairs, else traversing at same level
					if( gJa25SaveStruct.ubLoadScreenStairTraversal == LS__GOING_UP_STAIRS )
						return LOADINGSCREEN_UP_STAIRS;
					else
						return LOADINGSCREEN_COMPLEX_BASEMENT;
				}
				default:
					return LOADINGSCREEN_BASEMENT;
			}
		}
		case 3:
		{
			switch( ubSectorID )
			{
				case SEC_L15:
				{
					//if we are going up stairs, else traversing at same level
					if( gJa25SaveStruct.ubLoadScreenStairTraversal == LS__GOING_DOWN_STAIRS )
						return LOADINGSCREEN_DOWN_STAIRS;
					else
						return LOADINGSCREEN_COMPLEX_BASEMENT_GENERIC;
				}
				default:
					return LOADINGSCREEN_CAVE;
			}
		}
		break;
			return LOADINGSCREEN_CAVE;
		default:

    /*
    case 1:
    case 2:
    case 3:
         return LOADINGSCREEN_CAVE;
    break;
	return LOADINGSCREEN_CAVE;
   default:
   */
#else
			// Basement Level 1
			case 1:
				switch( ubSectorID )
				{
					case SEC_A10:	//Miguel's basement
					case SEC_I13:	//Alma prison dungeon
					case SEC_J9:	//Tixa prison dungeon
					case SEC_K4:	//Orta weapons plant
					case SEC_O3:	//Meduna
					case SEC_P3:	//Meduna
						return LOADINGSCREEN_BASEMENT;
					default:		//rest are mines
						return LOADINGSCREEN_MINE;
				}
			// Basement Level 2 and 3
			case 2:
			case 3:
				//all level 2 and 3 maps are caves!
				return LOADINGSCREEN_CAVE;
			default:
#endif
				// shouldn't ever happen
				Assert( FALSE );
				return fNight ? LOADINGSCREEN_NIGHTGENERIC : LOADINGSCREEN_DAYGENERIC;
		}
	
	} /* WANNE: Sir-Tech System - END */
}

static void BuildLoadscreenFilename(std::string& dst, const char* path, int resolution, const char* ext)
{
	if (path)
		dst.append(path);

	if (ext)
	{
		dst.append(".");
		dst.append(ext);
	}
	else
		// This might suck later on. If it does, remove it.
		dst.append(".sti");
}

//sets up the loadscreen with specified ID, and draws it to the FRAME_BUFFER,
//and refreshing the screen with it.
void DisplayLoadScreenWithID( UINT8 ubLoadScreenID )
{
	VSURFACE_DESC		vs_desc = {};
	HVSURFACE			hVSurface;
	UINT32				uiLoadScreen;

	vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE | VSURFACE_CREATE_FROMPNG_FALLBACK;

	szSector = szSectorMap [gWorldSectorY][gWorldSectorX];
	const BOOLEAN fExternalLS = (szSector != NULL && strcmp(szSector, "N") != 0) && ((DAY <= ubLoadScreenID && ubLoadScreenID <= NIGHT_ALT) || (ubLoadScreenID == UNDERGROUND));
	
	if (fExternalLS)
	{
		// Get the image path
		std::string imagePath;
		std::string imageFormat;

		// Start screen
		if (ubLoadScreenID == HELI)
		{
			imagePath = gSectorLoadscreens[0].szDay;
			imageFormat = gSectorLoadscreens[0].szImageFormat;
		}
		else if (ubLoadScreenID == UNDERGROUND)
		{
			g_luaUnderground.GetLoadscreen(requestedX, requestedY, requestedZ, imagePath, imageFormat);
		}
		else
		{
			for (int i = 1; i < MAX_SECTOR_LOADSCREENS; i++)
			{
				// We found the sector
				if (strcmp(gSectorLoadscreens[i].szLocation, szSector) == 0)
				{
					imageFormat = gSectorLoadscreens[i].szImageFormat;

					BOOLEAN fAlternate = gSectorLoadscreens[i].RandomAltSector;

					if (fAlternate && (Random(2) > 0))
					{
						if (strlen(gSectorLoadscreens[i].szImageFormatAlt) > 0)
							imageFormat = gSectorLoadscreens[i].szImageFormatAlt;
						switch (ubLoadScreenID)
						{
							case DAY:
								ubLoadScreenID = DAY_ALT;
								break;
							case NIGHT:
								ubLoadScreenID = NIGHT_ALT;
								break;
							default:
								break;
						}
					}

					switch (ubLoadScreenID)
					{
						case DAY:
							imagePath = gSectorLoadscreens[i].szDay;
							break;
						case DAY_ALT:
							imagePath = gSectorLoadscreens[i].szDayAlt;
							break;
						case NIGHT:
							imagePath = gSectorLoadscreens[i].szNight;
							break;
						case NIGHT_ALT:
							imagePath = gSectorLoadscreens[i].szNight;
							break;
					}
					break;
				}
			}
		}

		std::string strImage;

		BuildLoadscreenFilename(strImage, imagePath.c_str(), 0, imageFormat.c_str());
		strImage.copy(vs_desc.ImageFile, sizeof(vs_desc.ImageFile)-1);
		
		
		if ( !FileExists(vs_desc.ImageFile) )
		{
			std::string strImage;
			BuildLoadscreenFilename(strImage, imagePath.c_str(), 0, "png");
			strImage.copy(vs_desc.ImageFile, sizeof(vs_desc.ImageFile) - 1);

			if (!FileExists(vs_desc.ImageFile))
			{
				std::string strImage("LOADSCREENS\\");

				BuildLoadscreenFilename(strImage, LoadScreenNames[1], 0, imageFormat.c_str());

				strImage.copy(vs_desc.ImageFile, sizeof(vs_desc.ImageFile) - 1);
			}
		}
	}
	else
	{
		std::string strImage("LOADSCREENS\\");

		if (LOADINGSCREEN_NOTHING <= ubLoadScreenID && ubLoadScreenID <= LOADINGSCREEN_NIGHTBALIME)
		{
			BuildLoadscreenFilename(strImage, LoadScreenNames[ubLoadScreenID], 0, "sti");
		}
		else
		{
			// for some reason the heli screen is the default
			BuildLoadscreenFilename(strImage, LoadScreenNames[0], 0, "sti");
		}
		strImage.copy(vs_desc.ImageFile, sizeof(vs_desc.ImageFile)-1);
	}


	if( gfSchedulesHosed )
	{
		SetFont( FONT10ARIAL );
		SetFontForeground( FONT_YELLOW );
		SetFontShadow( FONT_NEARBLACK );
		ColorFillVideoSurfaceArea( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 );
		mprintf( 5, 5, L"Error loading save, attempting to patch save to version 1.02...", vs_desc.ImageFile );
	}
	else
	{
		if (FileExists(vs_desc.ImageFile) && AddVideoSurface(&vs_desc, &uiLoadScreen))
		{
			SGPRect SrcRect, DstRect;
									
			//Blit the background image
			GetVideoSurface(&hVSurface, uiLoadScreen);
			
			// Stretch the background image
			SrcRect.iLeft = 0;
			SrcRect.iTop = 0;
			SrcRect.iRight = hVSurface->usWidth;
			SrcRect.iBottom = hVSurface->usHeight;
			
			DstRect.iLeft = 0;
			DstRect.iTop = 0;
			DstRect.iRight = SCREEN_WIDTH;
			DstRect.iBottom = SCREEN_HEIGHT;
			
			BltStretchVideoSurface( FRAME_BUFFER, uiLoadScreen, 0, 0, 0, &SrcRect, &DstRect );
						
			DeleteVideoSurfaceFromIndex( uiLoadScreen );			
		}
		else
		{
			 //Failed to load the file, so use a black screen and print out message.
			SetFont( FONT10ARIAL );
			SetFontForeground( FONT_YELLOW );
			SetFontShadow( FONT_NEARBLACK );
			ColorFillVideoSurfaceArea( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 );
			mprintf( 5, 5, L"%S loadscreen data file not found...", vs_desc.ImageFile );
		}
	}

	gubLastLoadingScreenID = ubLoadScreenID;
	InvalidateScreen( );
	ExecuteBaseDirtyRectQueue();
	EndFrameBufferRender();
	RefreshScreen( NULL );
}
