/*
===========================================================================

Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").

Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/
#ifndef __GAME_SSD_WINDOW_H__
#define __GAME_SSD_WINDOW_H__

#include "ui/Window.h"

class idGameSSDWindow;

class SSDCrossHair {

public:
	enum {
		CROSSHAIR_STANDARD = 0,
		CROSSHAIR_SUPER,
		CROSSHAIR_COUNT
	};
	const idMaterial*	crosshairMaterial[CROSSHAIR_COUNT];
	int					currentCrosshair;
	float				crosshairWidth, crosshairHeight;

public:
				SSDCrossHair();
				~SSDCrossHair();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile );

	void		InitCrosshairs();
	void		Draw(idDeviceContext *dc, const idVec2& cursor);
};

enum {
	SSD_ENTITY_BASE = 0,
	SSD_ENTITY_ASTEROID,
	SSD_ENTITY_ASTRONAUT,
	SSD_ENTITY_EXPLOSION,
	SSD_ENTITY_POINTS,
	SSD_ENTITY_PROJECTILE,
	SSD_ENTITY_POWERUP
};

class SSDEntity  {

public:
	//SSDEntity Information
	int					type;
	int					id;
	idStr				materialName;
	const idMaterial*	material;
	idVec3				position;
	idVec2				size;
	float				radius;
	float				hitRadius;
	float				rotation;

	idVec4				matColor;

	idStr				text;
	float				textScale;
	idVec4				foreColor;

	idGameSSDWindow*	game;
	int					currentTime;
	int					lastUpdate;
	int					elapsed;

	bool				destroyed;
	bool				noHit;
	bool				noPlayerDamage;

	bool				inUse;


public:
						SSDEntity();
	virtual				~SSDEntity();

	virtual void		WriteToSaveGame( idFile *savefile );
	virtual void		ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game );

	void				EntityInit();

	void				SetGame(idGameSSDWindow* _game);
	void				SetMaterial(const char* _name);
	void				SetPosition(const idVec3& _position);
	void				SetSize(const idVec2& _size);
	void				SetRadius(float _radius, float _hitFactor = 1.0f);
	void				SetRotation(float _rotation);

	void				Update();
	bool				HitTest(const idVec2& pt);


	virtual void		EntityUpdate() {};
	virtual void		Draw(idDeviceContext *dc);
	virtual void		DestroyEntity();

	virtual void		OnHit(int key) {};
	virtual void		OnStrikePlayer() {};

	idBounds			WorldToScreen(const idBounds worldBounds);
	idVec3				WorldToScreen(const idVec3& worldPos);

	idVec3				ScreenToWorld(const idVec3& screenPos);

};

/*
*****************************************************************************
* SSDMover
****************************************************************************
*/

class SSDMover : public SSDEntity {

public:
	idVec3				speed;
	float				rotationSpeed;

public:
						SSDMover();
	virtual				~SSDMover();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	void				MoverInit(const idVec3& _speed, float _rotationSpeed);

	virtual void		EntityUpdate();


};

/*
*****************************************************************************
* SSDAsteroid
****************************************************************************
*/

#define MAX_ASTEROIDS 64

class SSDAsteroid : public SSDMover {

public:

	int					health;

public:
						SSDAsteroid();
						~SSDAsteroid();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	void				Init(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health);

	virtual void		EntityUpdate();
	static SSDAsteroid*	GetNewAsteroid(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health);
	static SSDAsteroid*	GetSpecificAsteroid(int id);
	static void			WriteAsteroids(idFile* savefile);
	static void			ReadAsteroids(idFile* savefile, idGameSSDWindow* _game);



protected:
	static SSDAsteroid	asteroidPool[MAX_ASTEROIDS];

};

/*
*****************************************************************************
* SSDAstronaut
****************************************************************************
*/
#define MAX_ASTRONAUT 8

class SSDAstronaut : public SSDMover {

public:

	int					health;

public:
							SSDAstronaut();
							~SSDAstronaut();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	void					Init(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health);

	static SSDAstronaut*	GetNewAstronaut(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health);
	static SSDAstronaut*	GetSpecificAstronaut(int id);
	static void				WriteAstronauts(idFile* savefile);
	static void				ReadAstronauts(idFile* savefile, idGameSSDWindow* _game);

protected:
	static SSDAstronaut	astronautPool[MAX_ASTRONAUT];

};

/*
*****************************************************************************
* SSDExplosion
****************************************************************************
*/
#define MAX_EXPLOSIONS 64

class SSDExplosion : public SSDEntity {

public:
	idVec2	finalSize;
	int		length;
	int		beginTime;
	int		endTime;
	int		explosionType;

	//The entity that is exploding
	SSDEntity*			buddy;
	bool				killBuddy;
	bool				followBuddy;

	enum {
		EXPLOSION_NORMAL = 0,
		EXPLOSION_TELEPORT = 1
	};

public:
	SSDExplosion();
	~SSDExplosion();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	void				Init(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy = true, bool _followBuddy = true);

	virtual void		EntityUpdate();
	static SSDExplosion*	GetNewExplosion(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy = true, bool _followBuddy = true);
	static SSDExplosion*	GetSpecificExplosion(int id);
	static void				WriteExplosions(idFile* savefile);
	static void				ReadExplosions(idFile* savefile, idGameSSDWindow* _game);

protected:
	static SSDExplosion	explosionPool[MAX_EXPLOSIONS];
};

#define MAX_POINTS 16

class SSDPoints : public SSDEntity {

	int		length;
	int		distance;
	int		beginTime;
	int		endTime;

	idVec3	beginPosition;
	idVec3	endPosition;

	idVec4	beginColor;
	idVec4	endColor;


public:
	SSDPoints();
	~SSDPoints();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	void				Init(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color);
	virtual void		EntityUpdate();

	static SSDPoints*	GetNewPoints(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color);
	static SSDPoints*	GetSpecificPoints(int id);
	static void			WritePoints(idFile* savefile);
	static void			ReadPoints(idFile* savefile, idGameSSDWindow* _game);

protected:
	static SSDPoints	pointsPool[MAX_POINTS];
};

#define MAX_PROJECTILES 64

class SSDProjectile : public SSDEntity {

	idVec3	dir;
	idVec3	speed;
	int		beginTime;
	int		endTime;

	idVec3	endPosition;

public:
	SSDProjectile();
	~SSDProjectile();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	void				Init(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size);
	virtual void		EntityUpdate();

	static SSDProjectile* GetNewProjectile(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size);
	static SSDProjectile* GetSpecificProjectile(int id);
	static void				WriteProjectiles(idFile* savefile);
	static void				ReadProjectiles(idFile* savefile, idGameSSDWindow* _game);

protected:
	static SSDProjectile	projectilePool[MAX_PROJECTILES];
};


#define MAX_POWERUPS 64

/**
* Powerups work in two phases:
*	1.) Closed container hurls at you
*		If you shoot the container it open
*	3.) If an opened powerup hits the player he aquires the powerup
* Powerup Types:
*	Health - Give a specific amount of health
*	Super Blaster - Increases the power of the blaster (lasts a specific amount of time)
*	Asteroid Nuke - Destroys all asteroids on screen as soon as it is aquired
*	Rescue Powerup - Rescues all astronauts as soon as it is acquited
*	Bonus Points - Gives some bonus points when acquired
*/
class SSDPowerup : public SSDMover {

	enum {
		POWERUP_STATE_CLOSED = 0,
		POWERUP_STATE_OPEN
	};

	enum {
		POWERUP_TYPE_HEALTH = 0,
		POWERUP_TYPE_SUPER_BLASTER,
		POWERUP_TYPE_ASTEROID_NUKE,
		POWERUP_TYPE_RESCUE_ALL,
		POWERUP_TYPE_BONUS_POINTS,
		POWERUP_TYPE_DAMAGE,
		POWERUP_TYPE_MAX
	};

	int powerupState;
	int powerupType;


public:


public:
	SSDPowerup();
	virtual ~SSDPowerup();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile,  idGameSSDWindow* _game  );

	virtual void		OnHit(int key);
	virtual void		OnStrikePlayer();

	void	OnOpenPowerup();
	void	OnActivatePowerup();



	void	Init(idGameSSDWindow* _game, float _speed, float _rotation);

	static SSDPowerup* GetNewPowerup(idGameSSDWindow* _game, float _speed, float _rotation);
	static SSDPowerup* GetSpecificPowerup(int id);
	static void			WritePowerups(idFile* savefile);
	static void			ReadPowerups(idFile* savefile, idGameSSDWindow* _game);

protected:
	static SSDPowerup	powerupPool[MAX_POWERUPS];

};


typedef struct {
	float	spawnBuffer;
	int		needToWin;
} SSDLevelData_t;

typedef struct {
	float	speedMin, speedMax;
	float	sizeMin, sizeMax;
	float	rotateMin, rotateMax;
	int		spawnMin, spawnMax;
	int		asteroidHealth;
	int		asteroidPoints;
	int		asteroidDamage;
} SSDAsteroidData_t;

typedef struct {
	float	speedMin, speedMax;
	float	rotateMin, rotateMax;
	int		spawnMin, spawnMax;
	int		health;
	int		points;
	int		penalty;
} SSDAstronautData_t;

typedef struct {
	float	speedMin, speedMax;
	float	rotateMin, rotateMax;
	int		spawnMin, spawnMax;
} SSDPowerupData_t;

typedef struct {
	float	speed;
	int		damage;
	int		size;
} SSDWeaponData_t;

/**
* SSDLevelStats_t
*	Data that is used for each level. This data is reset
*	each new level.
*/
typedef struct {
	int					shotCount;
	int					hitCount;
	int					destroyedAsteroids;
	int					nextAsteroidSpawnTime;

	int					killedAstronauts;
	int					savedAstronauts;

	//Astronaut Level Data
	int					nextAstronautSpawnTime;

	//Powerup Level Data
	int					nextPowerupSpawnTime;

	SSDEntity*			targetEnt;
} SSDLevelStats_t;

/**
* SSDGameStats_t
*	Data that is used for the game that is currently running. Memset this
*	to completely reset the game
*/
typedef struct {
	bool				gameRunning;

	int					score;
	int					prebonusscore;

	int					health;

	int					currentWeapon;
	int					currentLevel;
	int					nextLevel;

	SSDLevelStats_t		levelStats;
} SSDGameStats_t;


class idGameSSDWindow : public idWindow {
public:
	idGameSSDWindow(idUserInterfaceLocal *gui);
	idGameSSDWindow(idDeviceContext *d, idUserInterfaceLocal *gui);
	~idGameSSDWindow();

	virtual void	WriteToSaveGame( idFile *savefile );
	virtual void	ReadFromSaveGame( idFile *savefile );

	virtual const char*	HandleEvent(const sysEvent_t *event, bool *updateVisuals);
	virtual idWinVar*	GetWinVarByName	(const char *_name, bool winLookup = false, drawWin_t** owner = NULL);


	virtual void		Draw(int time, float x, float y);

	void				AddHealth(int health);
	void				AddScore(SSDEntity* ent, int points);
	void				AddDamage(int damage);

	void				OnNuke();
	void				OnRescueAll();
	void				OnSuperBlaster();

	SSDEntity*			GetSpecificEntity(int type, int id);

	void				PlaySound(const char* sound);




	static idRandom		random;
	int					ssdTime;

private:

	//Initialization
	virtual bool		ParseInternalVar(const char *name, idParser *src);
	void				ParseLevelData(int level, const idStr& levelDataString);
	void				ParseAsteroidData(int level, const idStr& asteroidDataString);
	void				ParseWeaponData(int weapon, const idStr& weaponDataString);
	void				ParseAstronautData(int level, const idStr& astronautDataString);
	void				ParsePowerupData(int level, const idStr& powerupDataString);

	void				CommonInit();
	void				ResetGameStats();
	void				ResetLevelStats();
	void				ResetEntities();

	//Game Running Methods
	void				StartGame();
	void				StopGame();
	void				GameOver();

	//Starting the Game
	void				BeginLevel(int level);
	void				ContinueGame();

	//Stopping the Game
	void				LevelComplete();
	void				GameComplete();



	void				UpdateGame();
	void				CheckForHits();
	void				ZOrderEntities();

	void				SpawnAsteroid();

	void				FireWeapon(int key);
	SSDEntity*			EntityHitTest(const idVec2& pt);

	void				HitAsteroid(SSDAsteroid* asteroid, int key);
	void				AsteroidStruckPlayer(SSDAsteroid* asteroid);





	void				RefreshGuiData();

	idVec2				GetCursorWorld();

	//Astronaut Methods
	void				SpawnAstronaut();
	void				HitAstronaut(SSDAstronaut* astronaut, int key);
	void				AstronautStruckPlayer(SSDAstronaut* astronaut);

	//Powerup Methods
	void				SpawnPowerup();


	void				StartSuperBlaster();
	void				StopSuperBlaster();

	//void				FreeSoundEmitter( bool immediate );




public:

	//WinVars used to call functions from the guis
	idWinBool					beginLevel;
	idWinBool					resetGame;
	idWinBool					continueGame;
	idWinBool					refreshGuiData;

	SSDCrossHair				crosshair;
	idBounds					screenBounds;

	//Level Data
	int							levelCount;
	idList<SSDLevelData_t>		levelData;
	idList<SSDAsteroidData_t>	asteroidData;
	idList<SSDAstronautData_t>	astronautData;
	idList<SSDPowerupData_t>	powerupData;


	//Weapon Data
	int							weaponCount;
	idList<SSDWeaponData_t>		weaponData;

	int							superBlasterTimeout;

	//All current game data is stored in this structure (except the entity list)
	SSDGameStats_t				gameStats;
	idList<SSDEntity*>			entities;

	int							currentSound;

};

#endif //__GAME_SSD_WINDOW_H__