#pragma once

#include "dllinterface.h"
#include "..\Utilities\list.h"
#include "..\Utilities\XString.h"
#include "DXMatrix.h"
#include "DXVector3.h"
#include "PhysicsCore.h"

#include <NxPhysics.h>

enum SHAPETYPE
{
	SHAPE_NONE = 0,
	SHAPE_BOX,
	SHAPE_SPHERE,
	SHAPE_CAPSULE,
	SHAPE_MESH
};

struct BoxShapeDesc;
struct SphereShapeDesc;
struct CapsuleShapeDesc;
struct MeshShapeDesc;

struct DXFUNCTIONS_API ShapeDesc
{
	SHAPETYPE Type;

	float Mass;
	DXMatrix LocalPose;

	ShapeDesc(SHAPETYPE type) { Mass = 0; LocalPose.SetIdentity(); Type = type; }

	BoxShapeDesc* IsBox(void) { if(Type == SHAPE_BOX) return (BoxShapeDesc*)this; else return NULL; }
	SphereShapeDesc* IsSphere(void) { if(Type == SHAPE_SPHERE) return (SphereShapeDesc*)this; else return NULL; }
	CapsuleShapeDesc* IsCapsule(void) { if(Type == SHAPE_CAPSULE) return (CapsuleShapeDesc*)this; else return NULL; }
	MeshShapeDesc* IsMesh(void) { if(Type == SHAPE_MESH) return (MeshShapeDesc*)this; else return NULL; }
};

//AllocateShape methode required to avoid garbage collector

struct DXFUNCTIONS_API BoxShapeDesc : ShapeDesc
{
	DXVector3 Dimensions;

	BoxShapeDesc(void) : ShapeDesc(SHAPE_BOX) { Dimensions = DXVector3(1, 1, 1); }

	static BoxShapeDesc* AllocateShape(void) { return new BoxShapeDesc(); }
};

struct DXFUNCTIONS_API SphereShapeDesc : ShapeDesc
{
	float Radius;

	SphereShapeDesc(void) : ShapeDesc(SHAPE_SPHERE) { Radius = 1; }

	static SphereShapeDesc* AllocateShape(void) { return new SphereShapeDesc(); }
};

struct DXFUNCTIONS_API CapsuleShapeDesc : ShapeDesc
{
	float Radius;
	float Height;

	CapsuleShapeDesc(void) : ShapeDesc(SHAPE_CAPSULE) { Radius = 1; Height = 1; }

	static CapsuleShapeDesc* AllocateShape(void) { return new CapsuleShapeDesc(); }
};

struct DXFUNCTIONS_API MeshShapeDesc : ShapeDesc
{
	XString Filename;
	float Scale;

	MeshShapeDesc(void) : ShapeDesc(SHAPE_MESH) { Scale = 0; }

	static MeshShapeDesc* AllocateShape(void) { return new MeshShapeDesc(); }
};

class DXFUNCTIONS_API CollisionShape
{
	//list of shapes
	LList<ShapeDesc> m_Shapes;
	//LList<NxShapeDesc> m_NxShapes;

public:
	CollisionShape(void);
	~CollisionShape(void);

	//if mass == 0 it will be taken from its shapes, if mass < 0 then static actor
	NxActor* BuildActor(PhysicsScene* const scene, const float scale, const float mass);

	LList<ShapeDesc>* GetShapes(void) { return &m_Shapes; }
	void AddShape(ShapeDesc* const shape) { m_Shapes.AddTail(shape, 0); }
	void DeleteShape(ShapeDesc* const shape) { ListElement<ShapeDesc>* e = m_Shapes.GetElement(shape); if(e) e->Delete(); }

	void Read(FILE* const f);
	void Write(FILE* const f) const;
};
