////////////////////////////////////////////////////////////////////////////////
// Class VehicleAI and subclasses
// Classes that control vehicle movement, including physics
// Copyright Bjoern Ganster
// Developed since 2010
////////////////////////////////////////////////////////////////////////////////

#ifndef VehicleAI__h
#define VehicleAI__h

#include "BipedMech.h"
#include "BoundingBox.h"
#include "GameObject.h"
#include "Mesh.h"
#include "MissionGoals.h"
#include "Vehicles.h"

#include <vector>

////////////////////////////////////////////////////////////////////////////////
// Constants

const double jjStrength = 20.0;
const double jjUseRate = 2.0;
//static const double maxTurnPerSecond = 90.0;

#define MAX_COLLISION_RESOLVE_LOOPS 5

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

struct AIGoal {
	SubObjectiveType type;
	Point3D coords;
	int duration; // for wait actions
	BGCPString target, trigger;
};

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

class AbstractVehicleAI: public VirtualClass {
public:
	bool groupFire;
	double mTriggerSpeed, mAimingAccuracy;

	// Constructor
	AbstractVehicleAI(const char* className, int classId, Vehicle* vehicle);

	// Destructor
	~AbstractVehicleAI() OVERRIDE;

	Point3D getFront() const;

	double getSpeed() const;

	// Get vehicle controlled by this AI
	Vehicle* getVehicle();
	const Vehicle* getVehicle() const;

	virtual void setAim(double dx, double dy) = 0;

	virtual int getPerspective() const;

	virtual bool weaponActive(int i, bool groupFire) const = 0;

	virtual void planMovement(DWORD now) = 0;

	virtual void setTarget(GameObject* gameObject);

	// Find out what the AI is currently targeting
	GameObject* getTarget() const;

	// Notify AI of an event, like a destroyed object
	virtual void updateObjectStatus(const BGCPString& id, SubObjectiveType newStatus) = 0;

	// Set range where AI triggers
	virtual void setTriggerRange(double newVal) = 0;

	// Add single goal to attack (possibly after sleep goal)
	virtual void addAttackGoal(const BGCPString& target) = 0;

	// Add goals for AI
	virtual void addGoals(const std::vector<AIGoal>& goals, bool clearExisting) = 0;

	// Set skills (will be reflected by other variables));
	virtual void setPiloting(int newVal);
	virtual void setGunnery(int newVal);
protected:
	// The vehicle controlled by the AI
	Vehicle* mVehicle;

	// The target currently fought by the AI
	GameObject* mTarget;
};

// Get list of polygons colliding with this bounding box
void findColliders(const BoundingBox& bb, RenderableObject* scene, const Vehicle* vehicle, std::vector<RenderableObject*>& colliders);

void resolveObjectCollision(Vehicle* oneVehicle, Vehicle* otherVehicle);

// Resolve collisions with unmoveable object
void resolveGroundCollision(Vehicle* vehicle, RenderableObject* collider, const BoundingBox& vehicleBB, 
	Point3D& movement, bool& movementChanged);

////////////////////////////////////////////////////////////////////////////////
// Abstract base class for vehicles and Mechs that are controlled by players

class PlayerVehicleAI: public AbstractVehicleAI {
public:
	// Constructor
	PlayerVehicleAI(const char* className, int classID, Vehicle* vehicle)
	: AbstractVehicleAI(className, classID, vehicle),
	  mPerspective(0)
	{
	}

	// Destructor
	~PlayerVehicleAI() OVERRIDE
	{
	}

	// Keyboard event handlers
	virtual void keypressed(BGKey key, bool shiftHeld, bool controlHeld, bool down, bool repeat) = 0;

	// Button state changed over a window: returns child that was clicked
	virtual void buttonStateChanged(int button, bool down, int /*x*/, int /*y*/) = 0;

	virtual void mouseMoved(int /*x*/, int /*y*/) = 0;

	int getPerspective() const OVERRIDE;

	// Ignored for player vehicles
	void setTriggerRange(double newVal) OVERRIDE;
	void addAttackGoal(const BGCPString& target) OVERRIDE;
	void addGoals(const std::vector<AIGoal>& goals, bool clearExisting) OVERRIDE;
protected:
	int mPerspective;
};

#endif