//	GamePlayState.h - The main gameplay state.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	This program 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.
//
//	This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef GAMEPLAYSTATE_H_
#define GAMEPLAYSTATE_H_

#include "drawing/TextLayout.h"
#include "ParticleGenerator.h"
#include "PickupAnnouncer.h"
#include "BulletCreator.h"
#include "Snowflakes.h"
#include "c0xHeaders.h"
#include "GameState.h"
#include "Tweener.h"

#include <sstream>
#include <vector>

class PuddleCollisionCreatorBase;
class GenericFileSounder;
class TankYouGlobalData;
class PickupGenerator;
class ShockwaveEntity;
class MineTrigger;
class Collidable;
class MADButton;
class Puddle;
class Bullet;
class Pickup;
class Tank;
class Wall;
class Mine;
class NPC;

///	The main gameplay state.
class GamePlayState : public GameState
{
  public:
	///	Constructor.
	GamePlayState(Application& app, SounderPtr& sound);
	///	Destructor.
	~GamePlayState();

	///	Called frequently to update the state.
	void update();
	///	Called to draw the state.
	void draw(DrawerPtr& d, float timestepInterp);

	///	Called when a key down event is received.
	void keyDown(const std::wstring& action,
				 const std::wstring& keyPressed,
				 int keyModifier);
	///	Called when a key up event is received.
	void keyUp(const std::wstring& action,
			   const std::wstring& keyPressed,
			   int keyModifier);

	///	Called when a joystick axis changes.
	/*!
		\param action The name of the action mapped to this joystick axis.
		\param value The value of this axis (0->1).
		\param joystick The index of the joystick which sent this message.
		\param axis The index of the axis which changed (0 = up, 1 = right,
		2 = down, 3 = left, 4 = trigger1, 5 = trigger2, 6 = up2, 7 = right2,
		8 = down2, 9 = left2).
	 */
	void joyMove(const std::wstring& action,
				 float value,
				 int joystick,
				 int axis);

	///	Helper method. Fires a primary shot from the passed-in tank.
	void firePrimary(const TwoFloats& pos,
					 const TwoFloats& dir,
					 const ThreeFloats& col,
					 const std::wstring& parent);
	///	Helper method. Fires a secondary shot from the passed-in tank.
	void fireSecondary(const Tank& tank);
	///	Adds a Bullet with no modifiers to the game.
	void firePlainBullet(const TwoFloats& pos,
						 const TwoFloats& dir,
						 const ThreeFloats& col,
						 const std::wstring& parent);
	///	Adds a mine to the game.
	void addMine(const TwoFloats& pos,
				 const std::wstring& owner,
				 const ThreeFloats& colour);
	///	Adds a bee to the game.
	void addBee(const TwoFloats& pos, const ThreeFloats& col);
	///	Adds a zombie to the game.
	void addZombie(const TwoFloats& pos, const ThreeFloats& col);
	///	Adds a turret to the game.
	void addTurret(const TwoFloats& pos, const ThreeFloats& col);
	///	Adds an npc to the game.
	void addNpc(shared_ptr<NPC>& npc);
	///	Turns recursive shot properties on.
	void setRecursiveShotProperties();
	///	Turns bullet collection of pickups on.
	void setBulletPickupCollection();
	///	Turns bullet->mine triggering on.
	void setBulletsTriggerMines();
	///	Turns on turn-based mode.
	void setTurnBasedMode();
	///	Makes mines camouflaged.
	void setCamouflageMines();

	///	Returns the number of tanks in the game.
	int getNumTanks() const {return tanks.size();};
	///	Returns the indexed tank.
	shared_ptr<Tank>& getTank(int index) {return tanks[index];};

	///	Returns the number of npcs in the game.
	int getNumNpcs() const {return npcs.size();};
	///	Returns the indexed npc.
	shared_ptr<NPC>& getNpc(int index) {return npcs[index];};

	///	Sets the death message for the indexed tank.
	void setDeathMessage(int index,
						 const std::wstring& message,
						 const ThreeFloats& colour);

	///	Places the named pickup away from any other Collidables.
	void addPickup(const std::wstring& pickupType);
	///	Adds a MADButton to the centre of the arena.
	void addMADButton();
	///	Adds a wall to the arena at the specified position.
	void addWall(const TwoFloats& pos);

	///	Adds a shockwave at the passed-in position.
	void addShockwave(const TwoFloats& pos, const ThreeFloats& col);

	///	Returns the number of pickups on screen.
	int getNumPickups() const {return pickups.size();};

	///	Returns the game's BulletCreator.
	BulletCreator& getBulletCreator() {return bulletCreator;};
	///	Used to register a MineTrigger.
	void registerMineTrigger(shared_ptr<MineTrigger> trigger);
	///	Used to register a PuddleCollisionModifier.
	void registerPuddleCollisionMod(PuddleCollisionCreatorBase *mod);

	///	Returns the left border line colour.
	const ThreeFloats& getLeftBorderColour() const {return lineLeft;};
	///	Returns the right border line colour.
	const ThreeFloats& getRightBorderColour() const {return lineRight;};

	///	Returns the name of this state.
	const std::wstring getName() const {return L"GamePlayState";};
	///	Used to construct instances of this state.
	static GameStateCreator<GamePlayState> creator;
  private:
	///	Helper method. Handles all the collision detection.
	void collisionDetection();
	///	Helper method. Tests if a Collidable is colliding with an arena wall.
	/*!
		Calls the Collidable's collide() method of it is colliding.
	 */
	void arenaWallCheck(shared_ptr<Collidable>& collidable);
	///	Helper method. Triggers background flash, screen shake etc.
	/*!
		\param pos The position of the collision.
	 */
	void triggerCollisionEffects(const TwoFloats& pos);
	///	Helper method. Called when a mine is triggered.
	void mineTriggered(const shared_ptr<Mine>& mine);
	///	Helper method. Chooses a random midi note.
	int getRandomMIDINote();

	///	Struct holding all the relevant information to display a death message.
	struct DeathMessage
	{
		///	Constructor.
		DeathMessage(const TwoFloats& pos):
		position(pos)
		{

		};

		///	The message.
		std::wstring message;
		///	The TextLayout to draw it.
		TextLayout layout;
		///	The position to draw it at.
		TwoFloats position;
		///	The colour to draw it with.
		ThreeFloats colour;
	};

	///	Any constants we use.
	enum
	{
		TurnCounterMax = 45,
		PauseCounterMax = 15
	};

	///	The current background colour.
	ThreeFloats backgroundColour;
	///	Tweener for the background colour.
	STweener<ThreeFloats> backgroundTweener;
	///	The current border colour.
	ThreeFloats borderColour;
	///	Tweener for the border colour.
	STweener<ThreeFloats> borderTweener;
	///	Used to shake the screen.
	float shake;
	///	Used to shake the screen.
	float shakeIndex;

	///	The line left colour.
	ThreeFloats lineLeft;
	///	Tweener for the line left colour.
	STweener<ThreeFloats> lineLeftTweener;
	///	The line right colour.
	ThreeFloats lineRight;
	///	Tweener for the line right colour.
	STweener<ThreeFloats> lineRightTweener;
	///	The top and bottom lines.
	std::vector<TwoFloats> linePos[2];
	///	The top and bottom lines.
	std::vector<float> lineSize;
	///	The top and bottom lines.
	std::vector<ThreeFloats> lineCol;
	///	The top and bottom lines.
	std::vector<float> lineAlpha;

	///	All the collidable objects currently in the game.
	std::vector<weak_ptr<Collidable> > collidables;
	///	The tanks currently in the game.
	std::vector<shared_ptr<Tank> > tanks;
	///	The bullets currently in the game.
	std::vector<shared_ptr<Bullet> > bullets;
	///	The walls in the game.
	std::vector<shared_ptr<Wall> > walls;
	///	The pickups in the game.
	std::vector<shared_ptr<Pickup> > pickups;
	///	The shockwaves in the game.
	std::vector<shared_ptr<ShockwaveEntity> > shockwaves;
	///	The mines in the game.
	std::vector<shared_ptr<Mine> > mines;
	///	The puddles in the game.
	std::vector<shared_ptr<Puddle> > puddles;
	///	Any npcs in the game.
	std::vector<shared_ptr<NPC> > npcs;
	///	The MADButton if it exists.
	shared_ptr<MADButton> madButton;

	///	Any active MineTriggers.
	std::vector<shared_ptr<MineTrigger> > mineTriggers;
	///	Used to store any PuddleCollisionModifiers.
	std::vector<PuddleCollisionCreatorBase *> puddleCollisionModifiers;

	///	Collidable used to represent the arena walls in collisionDetection().
	shared_ptr<Wall> arenaWall;

	///	Death messages for the 4 tanks.
	std::vector<DeathMessage> deathMessages;

	///	Used to create Bullets.
	BulletCreator bulletCreator;
	///	If true, all Bullets are normal Bullets.
	bool recursiveShotProperties;
	///	Used to limit the number of Bullets that are created in a single frame.
	int bulletLimit;
	///	True if Bullets can collect Pickups.
	bool bulletPickupCollection;
	///	True if Bullets can trigger Mines.
	bool bulletsTriggerMines;
	///	True if mines are camouflaged.
	bool camouflageMines;

	///	Used to limit the number of Shockwaves which are created in a single frame.
	int shockwaveLimit;

	///	True if we're in turn-based mode.
	bool turnBasedMode;
	///	The counter during which to allow player input in turn-based mode.
	int turnCounter;
	///	The counter used to pause between turns in turn-based mode.
	int turnPauseCounter;
	///	The current tank in turn-based mode.
	int turnTank;
	///	Used to bounce the turn marker.
	float turnBounce;

	///	Used to generate Pickups.
	shared_ptr<PickupGenerator> pickupGenerator;

	///	The particles from collisions.
	ParticleGenerator particles;
	///	Used to limit the number of times the background colour can be incremented during a frame.
	int backgroundColLimit;

	///	Used to announce which pickups have been collected.
	PickupAnnouncer announcer;

	///	True if the game is over.
	bool gameOver;
	///	The game over text.
	std::wstring gameOverText;
	///	Text layout for gameOverText.
	TextLayout gameOverLayout;
	///	Colour for the game over text.
	ThreeFloats gameOverColour;
	///	Used to bounce the game over text down from the top of the screen.
	TwoFloats gameOverPos;
	///	Used to bounce the game over text down from the top of the screen.
	STweener<TwoFloats> gameOverTweener;

	///	If true, the player's got the console open.
	bool console;
	///	The current contents of the console.
	std::wstringstream consoleText;
	///	Used to ensure we don't get multiple console key presses via the KeyManager.
	bool consoleReady;

	///	Used to draw snowflakes in December.
	Snowflakes snowflakes;

	///	Our sounder.
	shared_ptr<GenericFileSounder> sounder;
	///	Our global data.
	shared_ptr<TankYouGlobalData> globalData;
};

#endif
