/*********************************************************************//**
*	\brief Deklarace zbrani a prostredky pro jejich vytvoreni
*	Databaze zbrani spolecne s definicemi jednotlivych zbrani.
*	Kazda zbran obsahuje sadu funkci, ktere se volaji pri urcite udalosti:
*		- strelba, stav klidu, nabijeni apod.
*	Vsechny zbrane obsahuji nekolik zakladnich promennych, ktere indikuji
*	napriklad aktualni identifikacni cislo animace, model zbrane, potrebu
*	naboju, pocet naboju, maximalni pocet naboju, jmeno zbrane, moznost
*	pouzivani zbane (jeji vlastneni) atd..Tyto atributy jsou definovany
*	ve spolecne nadtride BasicWeapon.
*
*	\author Michal Jirous
*	\date 27.11.2008
*	\file weapons.h
**********************************************************************/

#ifndef __WEAPONS_H__
#define __WEAPONS_H__

class WarStorage;	//predeclaration

#include "ammo_def.h"
#include "modelslib.h"
#include "attack_info.h"

/** @brief Poradi a identifikacni cisla zbrani. */
enum weapons
{
	NO_WEAPON = 0,	/*!< @brief Zadna zbran. */
	WPN_KNIFE,		/*!< @brief Nuz. */
	PISTOL_9MM,		/*!< @brief Pistole. */
	WPN_MP5,		/*!< @brief MP5. */


	WEAPONS_COUNT	/*!< @brief Celkovy pocet zbrani. */
};

class BasicWeapon;

typedef BasicWeapon* (*weapon_creator_t)( );			/*!< @brief Typ ukazatel na funkci, ktera tvori novou zbran. */

unsigned int getWeaponId( std::string weapon_name );	/*!< @brief Zjisti identifikacni cislo dle nazvu zbrane. */
void registerWeaponName( const char*  weapon_name, unsigned int weapon_type );	/*!< @brief Funkce propoji nazev zbrane s jejim identifikacnim cislem. */

BasicWeapon* createWeapon( std::string weapon_name  );	/*!< @brief Funkce vytvori objekt zbrane dle nazvu. */
BasicWeapon* createWeapon( unsigned int weapon_type  );	/*!< @brief Funkce vytvori objekt zbrane dle identifikacniho cisla. */

void addNewWeaponCreator( unsigned int weapon_type, weapon_creator_t fnc );	/*!< @brief Propoji identifikacni cislo zbrane s funkci, ktera vytvori jeji objekt. */

/** @brief Objekt, ktery propojuje identifikacni cislo zbrane, funkci na vytvoreni jejiho objektu a jmeno zbrane. 
*
*	Pri vytvoreni tohoto objektu s pouzitim definovaneho konstruktoru se vlozi do databaze zaznam, kde se propoji
*	identifikacni cislo zbrane s funkci, ktera vytvori novy objekt zbrane. Navic se zaregistruje a propoji
*	jmeno zbrane s jejim identifikacnim cislem.
*/
struct WeaponCreatingFunctionMaker
{
	/** @brief Konstruktor, ktery propojovani provadi. */
	WeaponCreatingFunctionMaker( unsigned int weapon_type, weapon_creator_t fnc, const char*  name )
	{
		addNewWeaponCreator( weapon_type, fnc );
		registerWeaponName( name, weapon_type );
	}
};

/*!< @brief Sablona pro vytvareni objektu zbrane. */
template <typename T>
BasicWeapon *getWeaponNewObject(  )
{
	return new T(  );
}

/*!< @brief Zjednoduseni registrace nove zbrane se jmenem a identifikacnim cislem. */
#define LINK_WEAPONTYPE_TO_CLASS( type, weaponclass, name ) const WeaponCreatingFunctionMaker weap_creator_for_##weaponclass( type, getWeaponNewObject<weaponclass>, name )

/** @brief Vycet typu zamku pri animacich. */
enum anim_lock_types
{
	UNLOCKED = 0,	/*!< @brief Bez uzamceni. */
	NORMAL_LOCK,	/*!< @brief Standardni zamek. */
	GRAB_OR_HOLSTER_LOCK	/*!< @brief Zamek pri vytahovani ci zatahovani zbrane. */
};

/** @brief Typ ukazatele na clenskou funkci tridy BasicWeapon a vsech jejich potomku. */
typedef void (BasicWeapon::*WpnFunc)();





/** @brief Predpis zakladni abstraktni tridy zbrani. */
class BasicWeapon
{

	void baseInit();
	std::string m_sModelFilename;
	unsigned int m_uiAnimationEndTime;
	unsigned int m_uiCurrentAnimation;
	int m_iLockedType;
	WpnFunc anim_end_func;	//ukazatel na funkci, ktera se ma zavolat podokonceni aktualni animace
	BasicWeapon *m_pTargetWeapon;
	bool m_bWeaponInHands;
	bool m_bAnimationRepeated;
	bool basic_grab();
	bool basic_attack( bool pulse );
	bool basic_holster();
	bool basic_reload( bool pulse );
	
protected:
	modelLib::ModelElement *m_pModel;	/*!< @brief Model zbrane k vykreslovani. */
	bool m_bIsOwned;		/*!< @brief Indikuje, zda lze zbran pouzivat. */
	bool m_bNeedAmmo;		/*!< @brief Indikuje, zda zbran potrebuje naboje. */
	int m_iAmmoType;		/*!< @brief Identifikacni cislo typu naboje. */
	int m_iAmmoAmount;		/*!< @brief Pocet naboju v zbrani. */
	int m_iMaxAmmoAmount;	/*!< @brief Maximalni pocet naboju ve zbrani. */
	int m_iCrosshair;	

	/** @brief Funkce pro standardni strelbu. */
	bool basic_fight( int damage, AttackInfo &target, float distance = INFINITE_DISTANCE, int damage_type = dmg::GENERIC, float dispersion = ZERO_DEGREES );

	/** @brief Nastavi model zbrane dle souboru. */
	void setModel( std::string filename );

	/** @brief Spusti animaci, pokud je to mozne. */
	bool playAnimation( int id, int length, bool repeat = false, int lock_type = NORMAL_LOCK, WpnFunc function = NULL, BasicWeapon *pWeapon = NULL );


	virtual void primaryAttack( bool pulse ) = 0;	/*!< @brief Predpis funkce primarniho utoku. */
	virtual void secondaryAttack( bool pulse ) = 0;	/*!< @brief Predpis funkce sekundarniho utoku. */
	virtual void reload( bool pulse )				/*!< @brief Predpis funkce nabijeni. */ {}
	virtual void holster()							/*!< @brief Funkce zastrceni zbrane. */	{}
	virtual void idle() = 0;						/*!< @brief Prepis funkce klidoveho stavu. */
	virtual void grab() = 0;						/*!< @brief Predpis funkce vytazeni zbrane. */

public:
	BasicWeapon();		/*!< @brief Konstruktor, ktery nastavuje vsechny parametry zbrane. */
	virtual ~BasicWeapon();	/*!< @brief Destruktor, ktery dealokuje alokovana data. */
	int getLockType()	/*!< @brief Zjistuje aktualni zamek animace. */		{ return m_iLockedType; }
	bool isOwned()		/*!< @brief Zjistuje, zda lze zbran pouzit. */		{ return m_bIsOwned; }	
	virtual void setOwned( bool owned ); /*!< @brief Nastavuje moznost pouziti zbrane. */
	int getAmmo()		/*!< @brief Zjistuje pocet naboju ve zbrani. */		{ return m_iAmmoAmount; }
	bool needAmmo()		/*!< @brief Zjistuje, zda zbran potrebuje naboje. */{ return m_bNeedAmmo; }
	unsigned int getTotalAmmo();	/*!< @brief Zjistuje celkovy pocet naboju typu, ktery zbran pouziva. */

	void weapon_grab();								/*!< @brief Hlavni funkce vytazeni zbrane. */
	void weapon_primaryAttack( bool pulse );		/*!< @brief Hlavni funkce primarniho utoku. */
	void weapon_secondaryAttack( bool pulse );		/*!< @brief Hlavni funkce sekundarniho utoku. */
	void weapon_holster();							/*!< @brief Hlavni funkce zastrceni zbrane. */
	void weapon_reload( bool pulse );				/*!< @brief Hlavni funkce nabijeni. */
	
	virtual void run();								/*!< @brief Funkce zakladni aktualizace. */
	virtual void draw();							/*!< @brief Funkce zakladniho vykreslovani. */

	int getCrosshairType()	{ return m_iCrosshair; }

};


/** @brief Zakladni typ zbrane, coz je "Zadna zbran" a hrac ji ma od zacatku. 
*
*	Zbran prakticky nevykonava zadnou cinnost, ale umoznuje hraci nemit vytazenou zadnou zbran.
*/
class NoWeapon : public BasicWeapon
{
	virtual void primaryAttack( bool pulse )	/*!< @brief Bez funkce. */ {}
	virtual void secondaryAttack( bool pulse )	/*!< @brief Bez funkce. */ {}
	virtual void reload( bool pulse )			/*!< @brief Bez funkce. */ {}
	virtual void idle()							/*!< @brief Bez funkce. */ {}
	virtual void grab()							/*!< @brief Bez funkce. */ {}
public:
	NoWeapon( );								/*!< @brief Definice promennych zbrane. */
	virtual void draw()							/*!< @brief Bez funkce. */ {}
	virtual void run()							/*!< @brief Bez funkce. */ {}
};

LINK_WEAPONTYPE_TO_CLASS( NO_WEAPON, NoWeapon, "weapon_none");	//nalinkujeme zbran (ID, trida, jmeno)


#endif

