////////////////////////////////////////////////////////////////////////////////
// AeroTech.h
// Declaration of a vehicle class for Aerospace fighters
// Copyright Bjoern Ganster
// Developed since 2021
////////////////////////////////////////////////////////////////////////////////

#ifndef AeroTech__h
#define AeroTech__h

#include "BGCPString.h"
#include "RenderableObject.h"
#include "Vehicles.h"

#include <vector>

////////////////////////////////////////////////////////////////////////////////

#define AeroTechMaxSections 4

class AeroTech FINAL: public Vehicle {
public:
	ENUM_CLASS Aerotech_Subtype {
		aerotech,
		spherical,
		aerodyne
	};

	// Rolling: turning around the length axis, p_front
	double mLastRoll, mCurrRoll, mNextRoll;

	// Pitching: turning around p_left
	double mLastPitch, mCurrPitch, mNextPitch;

	// Number of critical hits taken to avionics
	int mDamagedAvionics;

	// Current thrust setting (0..1)
	double mThrust;

	// Current movement vector (valid for movement in space and planetary environments)
	Point3D mMovementVector;

	// Constructor
	AeroTech(Aerotech_Subtype aSubType);

	// Destructor
	~AeroTech() OVERRIDE;

	// Read tags and attributes that are specific to an AeroTech from XML
	void readSpecialAttributesFromRoot(XMLTreeConstIterator& iter) OVERRIDE;
	void readSpecialAttributes(XMLTreeConstIterator& iter, 
		const std::vector<RenderableObject*>& geometries, const PathChar* mechDir) OVERRIDE;

	// Help function for parsing that translates a section name to a number
	int getSectionByName(const BGCPString& str) OVERRIDE;

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

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

	// Get special texture used by the cockpit (used for rendering the instruments)
	Mesh* getCockpitMesh() OVERRIDE;

	// Create a suitable AI for the vehicle
	AbstractVehicleAI* createAI(bool isPlayer, int environment) OVERRIDE;

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

	// After loading a config, use this function to set min/max speeds using vehicle-type-specific rules
	void setMinMaxSpeed() OVERRIDE;

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

	// 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);

	// Jet cockpits do not have a reticle that moves horizontally
	bool reticleMovesHorizontally() const OVERRIDE;

	// Get/set armor values
	DWORD getArmor(int section, int ArmorType) const OVERRIDE;
	bool setArmor(int section, DWORD newVal, int ArmorType) OVERRIDE;

	// Querying this for an aircraft will give its structural integrity instead
	DWORD getInternalStructure(int section) const OVERRIDE;

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

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

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

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

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

	// Change vehicle status
	void setStatus(VehicleStatus newStatus) OVERRIDE;

	double getPitchRate(int env) const;
	double getRollRate() const;

	// Set thrust while considering minimum thrust required by the environment
	void setThrust(double newVal, int env);

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

	// Compute additional values after loading a config (like heat sinks)
	void postLoadConfig() OVERRIDE;
private:
	Aerotech_Subtype mSubType;

	// Armor is tracked by location. It would be possible to differentiate between hits to the top/bottom of an aircraft.
	int mArmor[AeroTechMaxSections];

	// Damage sustained by section
	double mSectionDamage[AeroTechMaxSections];

	// Structural integrity acts similar to internal structure in Mechs, but is not tracked by location.
	// Hits reduce structural integrity, and when structural integrity is reduced to 0, the aircraft is destroyed.
	double mStructuralIntegrity;
	double mOriginalStructuralIntegrity; // the original value before any damage, for reference

	// Damage to structural integrity
	double mStructuralIntegrityDamage;

	// Aerospace fighters suffer from heat effects
	double mCurrentHeat;

	// Track destroyed criticals
	std::vector <std::vector <bool>> mCriticalDamaged;

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

	bool mGearDestroyed;
	int mFuel;

	int mSafeThrust;

	// Track movement of an aerospace fighter after its destruction
	Point3D mDestroyedFighterMovement;
};

#endif

