//
// License: GPL
// Date: 25.02.2006
// Author: André Schnabel (thefrogs@web.de)
// http://www.masterspace.biz/andreschnabel/
//

// Framework.h

#ifndef FRAMEWORK_H
#define FRAMEWORK_H

#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <list>
#include <map>
using namespace std;

#ifdef _WIN32

// Only working with MSVC++

//#pragma warning(disable : 4018)
//#pragma warning(disable : 4244)
#pragma warning(disable : 4715) // not all paths return a value...

#pragma comment(lib, "SDL.lib")
#pragma comment(lib, "SDLmain.lib")
#pragma comment(lib, "SDL_mixer.lib")
#pragma comment(lib, "SDL_image.lib")
#pragma comment(lib, "SDL_ttf.lib")

#include <windows.h>

#endif

#ifdef __GNUC__

#define sprintf_s	sprintf
#define strcpy_s	strcpy

#endif

const int MAX_STR_LENGTH = 256;
const long double PI = 3.1415926535897932;

// Default settings
namespace Default
{
	const string CAPTION		= "Framework";
	const int SCR_W				= 640;
	const int SCR_H				= 480;
	const int SCR_BPP			= 32;
	const bool DOUBLEBUF		= true;
	const bool FULLSCREEN		= true;
	const int AUDIO_FREQUENCY	= 44100;
	const Uint16 AUDIO_FORMAT	= AUDIO_S16SYS;
	const int AUDIO_CHANNELS	= 2;
	const int AUDIO_CHUNK_SIZE	= 2048;
	const bool AUDIO_DISABLED	= false;
	const string VERSION		= "1.0";
}

namespace Color
{
	const SDL_Color black	= { 0x00, 0x00, 0x00 };
	const SDL_Color white	= { 0xFF, 0xFF, 0xFF };

	const SDL_Color red		= { 0xFF, 0x00, 0x00 };
	const SDL_Color green	= { 0x00, 0xFF, 0x00 };
	const SDL_Color blue	= { 0x00, 0x00, 0xFF };

	const SDL_Color yellow	= { 0xFF, 0xFF, 0x00 };
	const SDL_Color magenta = { 0xFF, 0x00, 0xFF };
	const SDL_Color cyan	= { 0x00, 0xFF, 0xFF };
}

struct FrameworkSettings
{
	string caption;
	int scrW, scrH, scrBpp;
	bool doubleBuffering;
	bool fullscreen;
	int audioFrequency;
	Uint16 audioFormat;
	int audioChannels;
	int audioChunkSize;
	bool audioDisabled;
	string version;

	FrameworkSettings()
	{
		caption = Default::CAPTION;
		scrW = Default::SCR_W;
		scrH = Default::SCR_H;
		scrBpp = Default::SCR_BPP;
		doubleBuffering = Default::DOUBLEBUF;
		fullscreen = Default::FULLSCREEN;
		audioFrequency = Default::AUDIO_FREQUENCY;
		audioFormat = Default::AUDIO_FORMAT;
		audioChannels = Default::AUDIO_CHANNELS;
		audioChunkSize = Default::AUDIO_CHUNK_SIZE;
		audioDisabled = Default::AUDIO_DISABLED;
		version = Default::VERSION;
	}
};

class State;

class Framework
{
public:
	Framework(FrameworkSettings *settings = NULL);
	~Framework();

	void Output(string msg) const;
	void Error(string msg);
	void AddState(State *state);
	bool ProcessEvents() const;
	void Run();

	SDL_Surface *LoadImage(string filename, bool useAlpha = false);	
	Mix_Chunk *LoadSound(string filename);	
	Mix_Music *LoadMusic(string filename);
	TTF_Font *LoadFont(string filename, int ptSize = 10);

	void FreeImage(SDL_Surface *image) const;
	void FreeSound(Mix_Chunk *sound) const;
	void FreeMusic(Mix_Music *music) const;
	void FreeFont(TTF_Font *font) const;

	void SetAlpha(SDL_Surface *image, Uint8 alpha) const;

	void Draw(SDL_Surface *img, int x = 0, int y = 0);
	void Draw(SDL_Surface *img, SDL_Rect *destRect);
	void Draw(SDL_Surface *img, SDL_Rect *srcRect, SDL_Rect *destRect);

	void FillRect(SDL_Rect *rect = NULL, SDL_Color color = Color::black);
	void Flip();

	void DrawText(string text, int x, int y, TTF_Font *font, SDL_Color color = Color::black, bool blended = false);
	void DrawShadowedText(string text, int x, int y, TTF_Font *font, SDL_Color color = Color::white, bool blended = false);

	void PlaySound(Mix_Chunk *snd) const;
	void PlayMusic(Mix_Music *music, bool loop = true) const;
	void HaltMusic() const;

	Uint32 GetTicks() const;
	int GetMaxFps() const;

	SDL_Surface *GetScreen();
	int GetScreenW() const;
	int GetScreenH() const;

	void SetCaption(string caption) const;

	bool KeyIsPressed(int keyNum, bool wasReleased = true) const;
	int GetNumKeys() const;
	void RelativeMouseState(int *x, int *y) const;

	bool Coll(SDL_Rect *rect1, SDL_Rect *rect2) const;

	template<class Type>
	Type Cos(Type alpha) const;

	template<class Type>
	Type Sin(Type alpha) const;

	string GetVersion() const;

	void MakeScreenshot(string prefix = "screenshot") const;
	bool FileExists(string filename) const;

	void SetDrawFps(bool value, TTF_Font *font = NULL);
	void DrawFPS();

	bool IsFullscreen() const;
	void SetFullscreen(bool value);
	void ToggleFullscreen();

	void VidRestart();

	void Delay(Uint32 length = 1000) const;
	void SetGamma(float red = 1.0f, float green = 1.0f, float blue = 1.0f);
	void IncGamma(float value = 1.0f);
	void DecGamma(float value = 1.0f);
	void ShowDisplayModes() const;

	bool GetAudioDisabled() const;
	void SetAudioDisabled(bool value);
	void ToggleAudioDisabled();

	template<class Type>
	Type Pow(Type num, int exponent) const;

	template<class Type>
	Type Sqrt(Type num) const;

	int Rand(int min, int max);

	void SetNoRedraw(bool value);

	void LockScreen();
	void UnlockScreen();

	Uint32 GetPixelColor(int x, int y);
	void SetPixelColor(int x, int y, Uint32 color);

	Uint32 SDLColToUint32Col(SDL_Color color) const;

	int CountLinesInFile(string filename, bool noEmptyLines = true);

private:
	static const int MAX_SCRSHOTS	= 100;

	FrameworkSettings settings;

	SDL_Surface *screen;
	Uint8 *keys, *oldKeys;
	int numKeys;

	bool audioDisabled, audioInitialized;

	unsigned int maxFps;
	int fps, curFps;
	bool drawFps;
	TTF_Font *fpsFont;

	bool noRedraw;

	list<State *> states;

	struct GammaValues
	{
		float red, green, blue;

		GammaValues()
		{
			red = green = blue = 1.0f;
		}

		void Inc(float value)
		{
			red += value;
			green += value;
			blue += value;

			if(red > 10.0f || green > 10.0f || blue > 10.0f)
				red = green = blue = 10.0f;
		}

		void Dec(float value)
		{
			red -= value;
			green -= value;
			blue -= value;

			if(red < 0.1f || green < 0.1f || blue < 0.1f)
				red = green = blue = 0.1f;
		}

		void Set(float red, float green, float blue)
		{
			this->red = red;
			this->green = green;
			this->blue = blue;
		}
	};

	GammaValues curGamma;
};

extern Framework *framework;

#endif

