#pragma once
#include "MobileMicrobe.h"
#include "Touchable.h"
#include "Damageable.h"
#include "Actors\ParticleActor.h"

class Macrophage;
class CellWarsMTManager;
class MultiSelectionCircle;
class SelectionCircle;
class SelectionButton;

const int BACTERIUM_VELOCITY_BUFFER_SIZE = 3;

class Bacterium : public MobileMicrobe, public Touchable, public Damageable
{
public:
	Bacterium(Vector2 spawnPos, CellWarsMTManager *useThisMultiTouchManager);
	virtual ~Bacterium();
	virtual void PreDestroy();

	virtual void die();

	virtual void setUpgradeLevel(int newLevel);
	virtual void upgrade();
	virtual Bacterium* replicate(); // returns the pointer to the copy, or if not enough resources a NULL pointer

	virtual void Update(float dt);
	virtual void Render();
	
	virtual void ReceiveMessage(Message *m);
	
	virtual void fingerDown(Vector2 posDownInAngelCoords);
	virtual void fingerMove(Vector2 moveToInAngelCoords);
	virtual void fingerUp(Vector2 lastPosInAngelCoords);
	
	virtual void devour(Macrophage *devourByThis){devourByThisMacrophage = devourByThis;}
	virtual void spitOut(){devourByThisMacrophage = NULL;}
	virtual bool isDevoured(){return (devourByThisMacrophage != NULL);}
	
	void isNowSelected(MultiSelectionCircle *selectedByThis){selectedByThisCircle = selectedByThis;}
	void isNowDeselected(){selectedByThisCircle = NULL;}
	bool isCurrentlySelected(){return (selectedByThisCircle != NULL);}

	void skipMissingFingerUpEventsFromMSCircle(int numEvents){numFingersOnThis -= numEvents;}
	
	bool hasFullResources(){return resources >= getCurrentMaxResForLevel() * FLOAT_CHECK_ACCURACY_FACTOR;}
	bool hasFullLife(){return getLifePoints() >= getCurrentHPForLevel() * FLOAT_CHECK_ACCURACY_FACTOR;}

protected:
	static const float STANDARD_SIZE;
	static const float STANDARD_HEALTH_POINTS;
	static const float STANDARD_DAMAGE;
	static const float STANDARD_ATTACK_DISTANCE;
	static const float STANDARD_MAX_RESOURCES;
	static const float STAT_INCREASE_PER_LEVEL_FACTOR;
	static const float STANDARD_SENSOR_DISTANCE;
	static const float STANDARD_OWN_MOVEMENT_SPEED;

	int upgradeLevel;
	float resources;
	
	float getCurrentSizeForLevel(){return STANDARD_SIZE * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	float getCurrentHPForLevel(){return STANDARD_HEALTH_POINTS * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	float getCurrentDamageForLevel(){return STANDARD_DAMAGE * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	float getCurrentAttackDistForLevel(){return STANDARD_ATTACK_DISTANCE * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	float getCurrentMaxResForLevel(){return STANDARD_MAX_RESOURCES * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	float getCurrentSensorDistForLevel(){return STANDARD_SENSOR_DISTANCE + getCurrentSizeForLevel();}
	float getCurrentOwnMovementForLevel(){return STANDARD_OWN_MOVEMENT_SPEED * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	float getCurrentDriftAwayDistForLevel(){return DRIFT_AWAY_DISTANCE * (1 + STAT_INCREASE_PER_LEVEL_FACTOR * upgradeLevel);}
	
	Actor* healthBar;
	Actor* resourceBar;

	SelectionCircle *selectionCircle;
	std::vector<SelectionButton*> *buttons;
	
	AngelSoundHandle attackSound;
	AngelSoundHandle moveSound;

	float staggerPhase;
	float staggerDir;

private:
	static const float FLOAT_CHECK_ACCURACY_FACTOR;
	static const float DRIFT_AWAY_DISTANCE;
	static const float MAX_TIME_SINCE_LAST_MOVE;
	static const float STAGGER_VELOCITY;
	static const float STAGGER_PHASE_VELOCITY_FACTOR;

	void driftAway();
	void moveToNextTarget(float dt);
	void attackNextTarget(float dt);
	void stagger(float dt);

	void updatePositionVelocityHistory();
	void resetPositionVelocityHistory(Vector2 resetPos);

	Vector2 lastPositions[BACTERIUM_VELOCITY_BUFFER_SIZE];
	float lastTimes[BACTERIUM_VELOCITY_BUFFER_SIZE];
	Vector2 lastVelocities[BACTERIUM_VELOCITY_BUFFER_SIZE];
	Vector2 avgVelocity;
	int bufferCycleVar;
	
	void updateHealthBar();
	void updateResourceBar();

	Macrophage *devourByThisMacrophage;
	CellWarsMTManager *useThisMTManager;

	MultiSelectionCircle *selectedByThisCircle;

	ParticleActor *movementParticles;

	bool isAttackingThisFrame;
	float lastFrameVelocitySoundFactor;
};