#pragma once
#include "BaseGameState.h"
#include "SkyController.h"
#include "ReflectionController.h"
#include "GroundController.h"
#include "GameObject.h"
#include "TextManager.h"
#include "TextPrinter.h"

class MechanicComponent;

/*
	The name is bad, but I can't think of a better one.
	This class displays story-related messages at the
	bottom of the screen.
*/
class PlayByPlay
{
	  // Class for drawing text in area
	TextPrinter m_textPrinter;

	  // Bitmap on which PBB message is composed before drawing it on screen
	ImageHandle m_image;
	  // Icon of current speaker
	ImageHandle m_currentActor;
	  // Timer used for various things
	float m_timer;

	  // Index of current PBP message in level's array
	int m_pbpIndex;
	  // True when m_pbpIndex changes
	bool m_pbpUpdated;
	  // If true, m_timer is treated as a pause after all message is show and before it disappears
	bool m_pauseAfter;

public:
	PlayByPlay()
	{
		Reset();
	}

	void UpdatePBPIndex( int index );
	void Update( IGameContext & context, float dt );
	void Render( IRender & render );
	void Reset()
	{
		m_image = ImageHandle();
		m_currentActor = ImageHandle();

		m_timer = 0;
		m_pbpIndex = -1;
		m_pbpUpdated = false;
		m_pauseAfter = false;
	}
};

/*
	This state describes main game screen, where you play the game.

	Screen logic:
	* Fade in from black
	* Draw objects, process controls and messages
	* Show PBP messages when necessary
	* If player loses all lives or is out of time - go to game over screen
	* If enough of target is destroye - go to win screen
*/
class GameStateLevel : public BaseGameState
{
	  // Class responsible for drawing sky
	SkyController m_skyController;
	  // Class responsible for drawing reflection in water
	ReflectionController m_refController;
	  // Class responsible for drawing ground in levels where there is no water
	GroundController m_groundController;
	  // Graphic component IDs for render procedures, the only objects other than GameObjects to use Component system
	GraphicCompID m_beforeComp;
	GraphicCompID m_afterComp;
	GraphicCompID m_groundCompFg;
	GraphicCompID m_groundCompMg;
	GraphicCompID m_groundCompBg;	 
	  // Class for displaying and tracking story messages
	PlayByPlay m_pbp;

	  // User input flags
	bool m_exitGame;
	bool m_pauseGame;
	int m_controls;

	  // Specially remembered ID of player's object (plane)
	GameObjectID m_playerObjectID;
	RequestID m_playerObjectRequestID;

	  // Used to notice when options version change (see g_options_version)
	int m_optionsVersion;

	  // Gameplay flags
	bool m_aimAidEnabled;
	bool m_turboFireEnabled;

	enum EGameOverType
	{
		GAMEOVER_TYPE_NONE	= 0,
		GAMEOVER_TYPE_LIVES = 1,
		GAMEOVER_TYPE_TIME	= 2,
	};

	  // Timer for pause before going to game over screen
	float m_gameOverTimer;
	EGameOverType m_gameOverType;

	  // If true, draw fade effect
	bool m_fade;
	float m_fadeTimer;

	  // How long this level played in seconds
	float m_levelTimer;

	bool ExitGame( const InputEvent & e);
	bool PauseGame( const InputEvent & e);

	bool TurnUp( const InputEvent & e);
	bool TurnDown( const InputEvent & e);
	bool SpeedUp( const InputEvent & e);
	bool FireGun( const InputEvent & e);
	bool FireBomb( const InputEvent & e);

	  // Applies player and AI input to physic (movement)
	void ControlsToPhysics( GameObject *pObject,IGameContext & context, float dt );
	  // Applies player and AI input to mechanic (weapons etc.)
	void ControlsToMechanic( GameObject *pObject,IGameContext & context, float dt );
	  // Applies changes in Physic components to Graphic components (copies position etc.)
	void PhysicsToGraphics( GameObject *pObject,IGameContext & context, float dt );
	  // Applies changes in Physic components to Sound components (copies angle to calculate engine pitch etc.)
	void PhysicsToSound( GameObject *pObject,IGameContext & context, float dt );
	  // Copies necessary data from Physic components to AI
	void PhysicsToAI( GameObject *pObject,IGameContext & context, float dt );
	  // Provides sound event from animation changes
	void GraphicsToSound( GameObject *pObject,IGameContext & context, float dt );

	  // Processes all collisions supplied by PhysicProcessor
	void ProcessCollisions( IGameContext & context );
	  // Processes single collision between two objects
	void ProcessSingleCollision( const MechanicComponent *pMe, const MechanicComponent *pOther, IGameContext & context );
	  
	  // Fires a weapon (for player or AI)
	void FireWeapon( int weaponIndex, const PhysicComponent *pPhComp, const ControlComponent *pCnComp, const GraphicComponent *pGrComp, MechanicComponent *pMechComp, SoundComponent *pSnComp, IGameContext & context, const std::string & soundEvent );

public:
	GameStateLevel();

	void OnPush( IGameContext & context );
	void OnRemove( IGameContext & context );

	void RenderBefore( IRender & render, const IGameContext & context );
	void RenderAfter( IRender & render, const IGameContext & context );
	void Update( float dt, IGameContext & context );
};
