/*
   Copyright (C) 2004 by James Gregory
   Part of the GalaxyHack project
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.
 
   See the COPYING file for more details.
*/

#include "Stuff.h"
#include "Globals.h"
#include "Group.h"
#include "Logging.h"
#include "Menu_Base.h"

#include <fstream>
#include <sstream>
#include <boost/filesystem/operations.hpp>

using std::fstream;
using std::stringstream;
using std::getline;
using std::ifstream;

void FontStruct::Init(int iWidth, int iHeight, int iLetterJump, int iLineJump) {
	width = iWidth;
	height = iHeight;
	letterJump = iLetterJump;
	lineJump = iLineJump;

	//set up font look-up table
	SDL_Rect tempRect = {2, 2, width, height};
	fontLookup['A'] = tempRect;

	NextLetter(tempRect);
	fontLookup['B'] = tempRect;

	NextLetter(tempRect);
	fontLookup['C'] = tempRect;

	NextLetter(tempRect);
	fontLookup['D'] = tempRect;

	NextLetter(tempRect);
	fontLookup['E'] = tempRect;

	NextLetter(tempRect);
	fontLookup['F'] = tempRect;

	NextLetter(tempRect);
	fontLookup['G'] = tempRect;

	NextLetter(tempRect);
	fontLookup['H'] = tempRect;

	NextLetter(tempRect);
	fontLookup['I'] = tempRect;

	NextLetter(tempRect);
	fontLookup['J'] = tempRect;

	NextLetter(tempRect);
	fontLookup['K'] = tempRect;

	NextLetter(tempRect);
	fontLookup['L'] = tempRect;

	NextLetter(tempRect);
	fontLookup['M'] = tempRect;

	NextLine(tempRect);
	fontLookup['N'] = tempRect;

	NextLetter(tempRect);
	fontLookup['O'] = tempRect;

	NextLetter(tempRect);
	fontLookup['P'] = tempRect;

	NextLetter(tempRect);
	fontLookup['Q'] = tempRect;

	NextLetter(tempRect);
	fontLookup['R'] = tempRect;

	NextLetter(tempRect);
	fontLookup['S'] = tempRect;

	NextLetter(tempRect);
	fontLookup['T'] = tempRect;

	NextLetter(tempRect);
	fontLookup['U'] = tempRect;

	NextLetter(tempRect);
	fontLookup['V'] = tempRect;

	NextLetter(tempRect);
	fontLookup['W'] = tempRect;

	NextLetter(tempRect);
	fontLookup['X'] = tempRect;

	NextLetter(tempRect);
	fontLookup['Y'] = tempRect;

	NextLetter(tempRect);
	fontLookup['Z'] = tempRect;

	NextLine(tempRect);
	fontLookup['a'] = tempRect;

	NextLetter(tempRect);
	fontLookup['b'] = tempRect;

	NextLetter(tempRect);
	fontLookup['c'] = tempRect;

	NextLetter(tempRect);
	fontLookup['d'] = tempRect;

	NextLetter(tempRect);
	fontLookup['e'] = tempRect;

	NextLetter(tempRect);
	fontLookup['f'] = tempRect;

	NextLetter(tempRect);
	fontLookup['g'] = tempRect;

	NextLetter(tempRect);
	fontLookup['h'] = tempRect;

	NextLetter(tempRect);
	fontLookup['i'] = tempRect;

	NextLetter(tempRect);
	fontLookup['j'] = tempRect;

	NextLetter(tempRect);
	fontLookup['k'] = tempRect;

	NextLetter(tempRect);
	fontLookup['l'] = tempRect;

	NextLetter(tempRect);
	fontLookup['m'] = tempRect;

	NextLine(tempRect);
	fontLookup['n'] = tempRect;

	NextLetter(tempRect);
	fontLookup['o'] = tempRect;

	NextLetter(tempRect);
	fontLookup['p'] = tempRect;

	NextLetter(tempRect);
	fontLookup['q'] = tempRect;

	NextLetter(tempRect);
	fontLookup['r'] = tempRect;

	NextLetter(tempRect);
	fontLookup['s'] = tempRect;

	NextLetter(tempRect);
	fontLookup['t'] = tempRect;

	NextLetter(tempRect);
	fontLookup['u'] = tempRect;

	NextLetter(tempRect);
	fontLookup['v'] = tempRect;

	NextLetter(tempRect);
	fontLookup['w'] = tempRect;

	NextLetter(tempRect);
	fontLookup['x'] = tempRect;

	NextLetter(tempRect);
	fontLookup['y'] = tempRect;

	NextLetter(tempRect);
	fontLookup['z'] = tempRect;

	NextLine(tempRect);
	fontLookup['1'] = tempRect;

	NextLetter(tempRect);
	fontLookup['2'] = tempRect;

	NextLetter(tempRect);
	fontLookup['3'] = tempRect;

	NextLetter(tempRect);
	fontLookup['4'] = tempRect;

	NextLetter(tempRect);
	fontLookup['5'] = tempRect;

	NextLetter(tempRect);
	fontLookup['6'] = tempRect;

	NextLetter(tempRect);
	fontLookup['7'] = tempRect;

	NextLetter(tempRect);
	fontLookup['8'] = tempRect;

	NextLetter(tempRect);
	fontLookup['9'] = tempRect;

	NextLetter(tempRect);
	fontLookup['0'] = tempRect;

	NextLetter(tempRect);
	fontLookup['!'] = tempRect;

	NextLetter(tempRect);
	fontLookup['"'] = tempRect;

	NextLetter(tempRect);
	fontLookup['£'] = tempRect;

	NextLine(tempRect);
	fontLookup['$'] = tempRect;

	NextLetter(tempRect);
	fontLookup['%'] = tempRect;

	NextLetter(tempRect);
	fontLookup['^'] = tempRect;

	NextLetter(tempRect);
	fontLookup['&'] = tempRect;

	NextLetter(tempRect);
	fontLookup['*'] = tempRect;

	NextLetter(tempRect);
	fontLookup['('] = tempRect;

	NextLetter(tempRect);
	fontLookup[')'] = tempRect;

	NextLetter(tempRect);
	fontLookup['-'] = tempRect;

	NextLetter(tempRect);
	fontLookup['_'] = tempRect;

	NextLetter(tempRect);
	fontLookup['+'] = tempRect;

	NextLetter(tempRect);
	fontLookup['='] = tempRect;

	NextLetter(tempRect);
	fontLookup['`'] = tempRect;

	NextLetter(tempRect);
	fontLookup[','] = tempRect;

	NextLine(tempRect);
	fontLookup['.'] = tempRect;

	NextLetter(tempRect);

	fontLookup['/'] = tempRect;

	NextLetter(tempRect);
	fontLookup['<'] = tempRect;

	NextLetter(tempRect);
	fontLookup['>'] = tempRect;

	NextLetter(tempRect);
	fontLookup['?'] = tempRect;

	NextLetter(tempRect);
	fontLookup[';'] = tempRect;

	//apostrophe
	NextLetter(tempRect);
	fontLookup[39] = tempRect;

	NextLetter(tempRect);
	fontLookup['#'] = tempRect;

	NextLetter(tempRect);
	fontLookup[':'] = tempRect;

	NextLetter(tempRect);
	fontLookup['@'] = tempRect;

	NextLetter(tempRect);
	fontLookup['~'] = tempRect;

	//backslash
	NextLetter(tempRect);
	fontLookup[92] = tempRect;

	NextLetter(tempRect);
	fontLookup['|'] = tempRect;
}

void FontStruct::NextLetter(SDL_Rect& theRect) {
	theRect.x += letterJump;
}

void FontStruct::NextLine(SDL_Rect& theRect) {
	theRect.x = 2;
	theRect.y += lineJump;
}

void FontStruct::AddFont(SDL_Surface* newPic) {
	pics.push_back(newPic);
}

void FontStruct::BlitString(int x, int y, int nFont, const string& output) {
	SDL_Rect destRect = {x, y, width, height};

	for (int i = 0; i != output.size(); ++i) {
		if (output[i] == '\n') {
			destRect.x = x;
			destRect.y+= lineGap;
			continue;
		}

		if (output[i] != ' ')
			JSDL.BltPart(pics[nFont], fontLookup[output[i]], destRect);

		destRect.x+= width;
	}
}

void FontStruct::Shutdown() {
	for (int i = 0; i != pics.size(); ++i)
		SDL_FreeSurface(pics[i]);

	pics.clear();
}

int GetMoveProps(float& propx, float& propy, float dx, float dy) {
	propx = 0;
	propy = 0;

	float adx = fabs(dx);
	float ady = fabs(dy);

	//don't divide by 0!
	if (adx + ady) {
		if (dx < 0)
			propx = -(adx / (adx + ady));
		else
			propx = adx / (adx + ady);

		if (dy < 0)
			propy = -(ady / (adx + ady));
		else
			propy = ady / (adx + ady);

		return 1;
	}
	else
		return 0;
}

int TestOverlap(const SDL_Rect& rectOne, const SDL_Rect& rectTwo) {
	int oneRight = rectOne.x + rectOne.w - 1;
	int oneBottom = rectOne.y + rectOne.h - 1;

	int twoRight = rectTwo.x + rectTwo.w - 1;
	int twoBottom = rectTwo.y + rectTwo.h - 1;

	//one inside two
	if (rectTwo.x <= rectOne.x && rectOne.x <= twoRight
	        && rectTwo.y <= rectOne.y && rectOne.y <= twoBottom)
		return 1;

	if (rectTwo.x <= oneRight && oneRight <= twoRight
	        && rectTwo.y <= rectOne.y && rectOne.y <= twoBottom)
		return 1;

	if (rectTwo.x <= rectOne.x && rectOne.x <= twoRight
	        && rectTwo.y <= oneBottom && oneBottom <= twoBottom)
		return 1;

	if (rectTwo.x <= oneRight && oneRight <= twoRight
	        && rectTwo.y <= oneBottom && oneBottom <= twoBottom)
		return 1;

	//two inside one
	if (rectOne.x <= rectTwo.x && rectTwo.x <= oneRight
	        && rectOne.y <= rectTwo.y && rectTwo.y <= oneBottom)
		return 1;

	if (rectOne.x <= twoRight && twoRight <= oneRight
	        && rectOne.y <= rectTwo.y && rectTwo.y <= oneBottom)
		return 1;

	if (rectOne.x <= rectTwo.x && rectTwo.x <= oneRight
	        && rectOne.y <= twoBottom && twoBottom <= oneBottom)
		return 1;

	if (rectOne.x <= twoRight && twoRight <= oneRight
	        && rectOne.y <= twoBottom && twoBottom <= oneBottom)
		return 1;

	//rect one left side runs across rect two (think of a cross)
	if (rectTwo.x <= rectOne.x && rectOne.x <= twoRight
	        && rectTwo.y >= rectOne.y && oneBottom >= twoBottom)
		return 1;

	//rect two left side runs across rect one (think of a cross)
	if (rectOne.x <= rectTwo.x && rectTwo.x <= oneRight
	        && rectOne.y >= rectTwo.y && twoBottom >= oneBottom)
		return 1;

	return 0;
}

void CheckFileExists(const string& filename) {
	if (!DoesFileExist(filename)) {
		string error = "File doesn't exist: ";
		error+= filename;
		throw runtime_error(error.c_str());
	}
}

bool DoesFileExist(const string& filename) {
	namespace fs = boost::filesystem;
	fs::path tempPath(filename);

	if (fs::exists(tempPath))
		return true;
	else
		return false;
}

bool CheckNameValid(const string& theName, bool createInfo) {
	string errorStr = "\n";
	bool isValid = true;
	int alpha = 0;

	if (theName.size() < 3) {
		errorStr += "Names must be at least 3 letters long";
		isValid = false;
		goto endLabel;
	}

	if (theName.size() > 20) {
		errorStr += "Names must be no longer than 20 letters";
		isValid = false;
		goto endLabel;
	}

	for (int i = 0; i != theName.size(); ++i) {
		if (normalFonts.fontLookup.find(theName[i]) == normalFonts.fontLookup.end() && theName[i] != ' ') {
			errorStr += "Unrecognised character";
			isValid = false;
			goto endLabel;
		}
	}

	for (int i = 0; i != theName.size(); ++i) {
		if (isalnum(theName[i]))
			++alpha;
	}

	if (alpha < 3) {
		errorStr += "Names must contain at least 3 alphanumeric characters";
		isValid = false;
		goto endLabel;
	}

endLabel:

	if (!isValid && createInfo)
		CreateInfoString(errorStr);

	return isValid;
}

void DrawRectBorder(SDL_Rect& theRect, Uint16 color) {
	static SDL_Rect tempRect;

	//left
	tempRect.x = theRect.x - 1;
	tempRect.y = theRect.y - 1;
	tempRect.w = 1;
	tempRect.h = theRect.h + 1;
	JSDL.BltFill(tempRect, color);

	//top
	tempRect.x = theRect.x;
	tempRect.y = theRect.y - 1;
	tempRect.w = theRect.w;
	tempRect.h = 1;
	JSDL.BltFill(tempRect, color);

	//right
	tempRect.x = theRect.x + theRect.w;
	tempRect.y = theRect.y - 1;
	tempRect.w = 1;
	tempRect.h = theRect.h + 1;
	JSDL.BltFill(tempRect, color);

	//bottom
	tempRect.x = theRect.x;
	tempRect.y = theRect.y + theRect.h;
	tempRect.w = theRect.w;
	tempRect.h = 1;
	JSDL.BltFill(tempRect, color);
}

void FileToString(const string& fileName, string& theString) {
	const char* cStrName = fileName.c_str();

	CheckFileExists(cStrName);
	ifstream fStream(cStrName);

	string tempStr;

	while (getline(fStream, tempStr))
		theString += tempStr + '\n';

	NewlineConvert(theString);
}

void ReportOnMinorError(const char* error, bool force) {
	if (!anInfoString || force) {
		WriteLog(error);
		CreateInfoString(error, force);
	}
}

void ErrorBackToMM(const string& error) {
	WriteLog(error);
	globalErrorString = error;
	gsTo = GST_MainMenu;
}

string MakePicDirString(int nSide, const string& endOfDir, bool standard) {
	string ret;
	if (standard)
		ret = globalSettings.bdp + "standardpictures/";	
	else
		ret = GetFleetDir(nSide) + "unitpictures/";

	if (sides[nSide].color == sideRed)
		ret += "red/";
	else if (sides[nSide].color == sideGreen)
		ret += "green/";
	else if (sides[nSide].color == sideBlue)
		ret += "blue/";
	else if (sides[nSide].color == sideYellow)
		ret += "yellow/";

	ret += endOfDir;

	return ret;
}

//game always uses Linux newlines, whatever system it is running on
void NewlineConvert(string& theString) {
	char c, prevCh;
	string newStr;

	prevCh = EOF;

	for (int i = 0; i != theString.size(); ++i) {
		c = theString[i];

		/* basically we withhold emitting any '\r' until we */
		/* are sure that the next character is not a '\n'. */
		/* If it is not, we emit the '\r', if it is, we */
		/* only emit the '\n'. */

		if (prevCh == '\r') {
			/* '\r' is a special case because we don't */
			/* emit a '\r' until the next character */
			/* has been read */
			if (c == '\n') {
				/* a "\r\n" pair */
				/* discard previous '\r' and */
				/* just put the '\n' */
				newStr += c;
			} else {	/* prevch was a standalone '\r' */
				/* emit the standalone '\r' */
				newStr += '\r';
				/* emit the current character if it is not a '\r' */

				if (c != '\r')
					newStr += c;
			}
		} else { /* prevch was not '\r' */
			/* emit current character if it is not */
			/* a '\r' */
			if (c != '\r')
				newStr += c;
		}

		prevCh = c;
	}

	theString = newStr;
}

void FollowViewCenter() {
	//scrolling via following a group
	//must be done at the end of each frame,
	//because we don't want it to constantly flicker
	//due to being a frame out of date
	if (viewSide != -1) {
		CoordsInt center = sides[viewSide].groups[viewGroup].GetCenter();

		viewx = center.x - (globalSettings.screenWidth / 2);
		viewy = center.y - (globalSettings.screenHeight / 2);
	}
}

void CycleGroupInfoType() {
	if (SidePU::infoType == SIT_Points)
		SidePU::infoType = SIT_Number;
	else
		SidePU::infoType = static_cast<SideInfoType>(SidePU::infoType + 1);
}


string GetFleetDir(int whichSide) {
    return globalSettings.bdp + "fleets/" + sides[whichSide].name + "/";
}

bool CheckFleetExists(const string& fleetName) {
	if (!CheckNameValid(fleetName, false))
		return false;

	string filename = globalSettings.bdp + "fleets/" + fleetName + "/" + fleetName + ".dat";

	if (DoesFileExist(filename))
		return true;
	else
		return false;
}

void RemoveDirectory(const string& path) {
	namespace fs = boost::filesystem;
	fs::path tempPath(path);
			
	fs::directory_iterator directoryEnd; // default construction yields past-the-end
	for (fs::directory_iterator iter(tempPath); iter != directoryEnd; ++iter) {
		if (fs::is_directory(*iter) && !fs::is_empty(*iter))
			RemoveDirectory(iter->string());
		else
			fs::remove(*iter);
	}

	fs::remove(tempPath);
}

ustring strToUstr(const string& str) {
	ustring ret;
	string::const_iterator lIter = str.begin();
	string::const_iterator lEnd =  str.end();
	
	while (lIter != lEnd) {
		ret.push_back(*lIter);
		++lIter;
	}
	
	return ret;
}

string ustrToStr(const ustring& ustr) {
	string ret;
	ustring::const_iterator lIter = ustr.begin();
	ustring::const_iterator lEnd =  ustr.end();
	
	while (lIter != lEnd) {
		ret.push_back(*lIter);
		++lIter;
	}
	
	return ret;
}

void LoadStandardGraphics() {
	//fonts
	normalFonts.Init(normalLetterWidth, 13, 16, 15);
	boldFonts.Init(boldLetterWidth, 13, 18, 15);

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/normalfont.png");
	JSDL.BitmapColorConvert(white);
	normalFonts.AddFont(JSDL.BitmapFiletoSurface(0, 0, 256, 128, lightBlue));
	JSDL.BitmapCloseFile();
	
	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/normalfont.png");
	JSDL.BitmapColorConvert(greyText);
	normalFonts.AddFont(JSDL.BitmapFiletoSurface(0, 0, 256, 128, lightBlue));
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/boldfont.png");
	JSDL.BitmapColorConvert(white);
	boldFonts.AddFont(JSDL.BitmapFiletoSurface(0, 0, 256, 128, lightBlue));
	JSDL.BitmapCloseFile();


	//general pictures
	genPictures[GENPIC_CURSOR] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/cursor1.png", 0, 0, 16, 16, lightBlue);
	genPictures[GENPIC_CLOSEBOX] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/windowclose.png", 0, 0, 12, 12, lightBlue);

	genPictures[GENPIC_SMSHEXLODE1] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/ssexplode3.png", 0, 0, 8, 8);
	genPictures[GENPIC_SMSHEXLODE2] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/ssexplode4.png", 0, 0, 8, 8);
	genPictures[GENPIC_SMSHEXLODE3] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/ssexplode5.png", 0, 0, 8, 8);
	genPictures[GENPIC_SMSHEXLODE4] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/ssexplode6.png", 0, 0, 8, 8);
	genPictures[GENPIC_SMSHEXLODE5] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/ssexplode7.png", 0, 0, 8, 8);
	genPictures[GENPIC_SMSHEXLODE6] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/ssexplode8.png", 0, 0, 8, 8);

	genPictures[GENPIC_FREXLODE1] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode2.png", 0, 0, 84, 44);
	genPictures[GENPIC_FREXLODE2] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode3.png", 0, 0, 84, 44);
	genPictures[GENPIC_FREXLODE3] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode4.png", 0, 0, 84, 44);
	genPictures[GENPIC_FREXLODE4] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode5.png", 0, 0, 84, 44);
	genPictures[GENPIC_FREXLODE5] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode6.png", 0, 0, 84, 44);
	genPictures[GENPIC_FREXLODE6] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode7.png", 0, 0, 84, 44);
	genPictures[GENPIC_FREXLODE7] = JSDL.BitmapHDtoSurface(globalSettings.bdp + "graphics/frexplode8.png", 0, 0, 84, 44);

	///

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode2.png");
	genPictures[GENPIC_HCSEXLODE1] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE1] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE1] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode3.png");
	genPictures[GENPIC_HCSEXLODE2] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE2] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE2] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode4.png");
	genPictures[GENPIC_HCSEXLODE3] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE3] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE3] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode5.png");
	genPictures[GENPIC_HCSEXLODE4] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE4] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE4] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode6.png");
	genPictures[GENPIC_HCSEXLODE5] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE5] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE5] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode7.png");
	genPictures[GENPIC_HCSEXLODE6] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE6] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE6] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode8.png");
	genPictures[GENPIC_HCSEXLODE7] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE7] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE7] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode9.png");
	genPictures[GENPIC_HCSEXLODE8] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE8] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE8] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();

	JSDL.BitmapHDtoFile(globalSettings.bdp + "graphics/csexplode10.png");
	genPictures[GENPIC_HCSEXLODE9] = JSDL.BitmapFiletoSurface(0, 0, 768, 168);
	genPictures[GENPIC_MCSEXLODE9] = JSDL.BitmapFiletoSurface(0, 0, 512, 112);
	genPictures[GENPIC_LCSEXLODE9] = JSDL.BitmapFiletoSurface(0, 0, 328, 72);
	JSDL.BitmapCloseFile();
}

void ClearStandardGraphics() {
	normalFonts.Shutdown();
	boldFonts.Shutdown();

	for (int i = 0; i != nGenPictures; ++i) {
		if (genPictures[i]) {
			SDL_FreeSurface(genPictures[i]);
			genPictures[i] = 0;
		}
	}
}

void ResetGraphics() {
	ClearStandardGraphics();
	JSDL.ResetVideo();
	LoadStandardGraphics();
}

void SelectGroup(int side, int group, WindowChoice infoType) {
	for (int i = 0; i != sides.size(); ++i) {
		for (int j = 0; j != sides[i].groups.size(); ++j)
			sides[i].groups[j].Unselect();
	}

	sides[side].groups[group].Select(infoType);
}

