////////////////////////////////////////////////////////////////////////////////
// BipedMech.h
// BipedMech inplementation
// Copyright Bjoern Ganster
// Developed since 2007
////////////////////////////////////////////////////////////////////////////////

#ifndef BipedMech__h
#define BipedMech__h

#include "GameObject.h"
#include "Vehicles.h"
#include "XMLTree.h"

#include <vector>

struct MechAnimation {
	std::vector<double> data;
	double animDuration;
	double metersPerSecond;
};

////////////////////////////////////////////////////////////////////////////////
// Mech section identifiers
// todo: sections should be called locations ...

const int Biped_Mech_Section_Head = 0;
const int Biped_Mech_Section_Center_Torso = 1;
const int Biped_Mech_Section_Left_Torso = 2;
const int Biped_Mech_Section_Right_Torso = 3;
const int Biped_Mech_Section_Left_Arm = 4;
const int Biped_Mech_Section_Right_Arm = 5;
const int Biped_Mech_Section_Left_Leg = 6;
const int Biped_Mech_Section_Right_Leg = 7;

const int Biped_Mech_Sections = 8;
const int MaxBipedCriticalsPerSection = 12;

////////////////////////////////////////////////////////////////////////////////
// Mech mesh identifiers

const int Biped_Mech_Part_Hip = 0;
const int Biped_Mech_Part_Torso = 1;
const int Biped_Mech_Part_LeftArm = 2;
const int Biped_Mech_Part_RightArm = 3;
const int Biped_Mech_Part_LeftUpperLeg = 4;
const int Biped_Mech_Part_LeftLowerLeg = 5;
const int Biped_Mech_Part_LeftFoot = 6;
const int Biped_Mech_Part_RightUpperLeg = 7;
const int Biped_Mech_Part_RightLowerLeg = 8;
const int Biped_Mech_Part_RightFoot = 9;
const int Biped_Mech_Part_Windshield = 10;
const int Biped_Mech_Part_LeftLowerArm = 11;
const int Biped_Mech_Part_RightLowerArm = 12;
const int Biped_Mech_Part_Cockpit = 13;

const size_t Biped_Mech_MAX_PARTS = 14;

////////////////////////////////////////////////////////////////////////////////
// State for a bipedal mech

class BipedMech FINAL: public Vehicle
{
public:
	double torsoTilt;
	double torsoTwist;
	double torsoTwistLimit;
	double torsoTiltLimit;
	double armTwist;
	double armTwistLimit;

	// Constructor
	BipedMech();

	// Destructor
	~BipedMech() OVERRIDE;

	// Load entire mech
	virtual void readSpecialAttributesFromRoot(XMLTreeConstIterator& iter);
	virtual void readSpecialAttributes(XMLTreeConstIterator& iter, 
		const std::vector<RenderableObject*>& geometries, const PathChar* mechDir);

	// Add anim parameters
	void addAnim(XMLTreeConstIterator& iter);

	// Get maximum weight mech chassis can carry
	virtual int getMaxWeight() const;

	// Calculate actual mech weight
	virtual double calcRealWeight();
	virtual double getWeight() const;
	virtual int countArmorPoints() const;
	virtual double calcInternalStructureWeight() const;
	double calcJJWeight();

	virtual DWORD getArmor(int section, int ArmorType) const;
	virtual bool setArmor(int section, DWORD newVal, int ArmorType);
	virtual DWORD getInternalStructure(int section) const;

	// Add weapon to mech section
	virtual bool addWeapon(int currSection, WeaponType weaponNo);

	// Remove weapon from mech section
	virtual int removeWeapon(int currSection, int critNo, WeaponType weaponNo, int critCount = -1);

	// Check - and try to correct - config problems 
	// Returns true on success, false otherwise, and sets an error description on failure
	bool check(BGCPString& errors) OVERRIDE;

	// Set current animation matrices
	void setMatrices(double speed, DWORD missionTime) OVERRIDE;

	virtual void setInternalStructure(int section, DWORD newVal);

	// Transform all vertices using m
	void applyMatrix(const Matrix& m) OVERRIDE;

	void setAim(double turn, double tilt) OVERRIDE;

	// Return the section corresponding to a limb
	int limb2section(int limb) OVERRIDE;

	// Query damage to armor and internal structure
	double getArmorDamage(int section, int type) const OVERRIDE;
	double getInternalDamage(int section) const OVERRIDE;

	// Function to notify vehicle that it is taking damage
	void receiveDamage(RenderableObject* limb, double damage, GameObject* sender, const Point3D& pointOfImpact) OVERRIDE;

	// Check if the critical in section is damaged
	bool criticalDamaged(int section, int critical) const OVERRIDE;

	// Mark all criticals in one section as destroyed and check for additional effects
	void destroyLimb(int section);

	// Get maximum speed in meters per second currently supported by the vehicle
	double getMaxSpeed() const OVERRIDE;

	// Check if this vehicle differentiates between front and armor for a section
	bool separateFrontAndRearArmor(int section) const OVERRIDE;

	// Show or hide the vehicle's windshiled (cockpit view may require it to be hidden)
	void windshieldVisible(bool newVal) OVERRIDE;

	// Get tilt and turn for current aim direction
	double getAimTilt() const OVERRIDE;
	double getAimTurn() const OVERRIDE;

	// Move aim towards given angles by at most delta
	void adjustAim(double desiredTorsoTwist, double desiredTorsoTilt, double delta) OVERRIDE;

	// Get max armor allowed for a section
	int getMaxArmor(int section) OVERRIDE;

	// Get mesh used for the cockpit
	Mesh* getCockpitMesh() OVERRIDE;

	// Check for a collision with a polygon and handle it
	void checkCollision(const MeshPolygon* poly, Point3D& movement) OVERRIDE;

	// Set colors for wireframe rendering
	void setWireframeColors() OVERRIDE;

	// Based on the vehicle, connect the vehicle to a suitable AI
	AbstractVehicleAI* createAI(bool isPlayer, int environment);

	// Calculate heat for next frame
	void calcNextFrameHeat(DWORD now, double deltaT);

	// Get current heat value for this Mech
	double getHeat() const NOEXCEPT OVERRIDE;

	// Calculate movement for next frame
	void calcNextFrameMovement(double deltaT, RenderableObject* scene, DWORD now, double gravity) OVERRIDE;

	// The point to attack may differ per vehicle class, the center of the volume isn't necessarily a good spot to attack
	Point3D getAttackSpot(bool onGround) const OVERRIDE;

	// Get sensor damage - 0 equals no damage, 1 equals sensors completely destroyed
	double getSensorDamage() OVERRIDE;
private:
	double speed;
	bool legsParallelToGround;
	std::vector <MechAnimation> allAnimations;
	std::vector <double> mArmorDamageFront, mArmorDamageRear, mInternalDamage;
	std::vector <std::vector <bool>> mCriticalDamaged;

	// Basic mech data
	double realWeight;

	// Armor and internal structure
	int mFrontArmor[Biped_Mech_Sections];
	int mRearArmor[Biped_Mech_Sections];
	int mInternalStructure[Biped_Mech_Sections];

	// Current heat
	double mCurrentHeat;

	// Number of gyro hits the mech has received
	int mGyroHits;

	int mSensorDamage;

	bool mLifeSupportDestroyed;

	int mJumpJetHits;

	// Hide torso in cockpit view: useful for Mechs where torso polygons intersect the cockpit. Currently used for Orion.
	bool hideTorsoInCockpitView;

	int checkAndFixEngineCrits(int section);

	double animate(int part, double phase, double speed, double phaseShift);

	// Return the number of the part corresponding to a section
	// used by updateLoadoutGeometry() to find the mesh corresponding to the mech section
	int section2part(int section, bool allowLowerArms) OVERRIDE;

	// Check for items that the user may not add
	bool userMayAddDirectly(int section, WeaponType weaponNo) OVERRIDE;

	// Check if a critical may be removed by the user
	bool userMayRemoveDirectly (WeaponType weaponNo) OVERRIDE;

	// Check if the vehicle's cockpit has a reticle that moves horizontally
	bool reticleMovesHorizontally() const OVERRIDE;

	// Update mobility for a mech and send the "x disabled" event i mobility is reduced to zero
	void setMobility(double newVal);

	// Check if a section may mount jump jets
	bool mayMountJJs(int section) OVERRIDE;

	// Check for for critical damage, e.g. if a weapon is destroyed by a critical hit
	void checkCriticalDamage(int section, int criticalToDestroy);
};

double animate_old(int part, const MechAnimation& animationData, double phase);

#endif