#ifndef WSMOBJECT_H
#define WSMOBJECT_H

#include "PajaTypes.h"
#include "ColorC.h"
#include "ImportableI.h"
#include "FileIO.h"
#include "ScenegraphItemI.h"
#include "QuatC.h"
#include "Vector2C.h"
#include "Vector3C.h"
#include "ContVector3C.h"
#include "ContQuatC.h"
#include "ContFloatC.h"
#include "ControllerC.h"
#include "MaterialC.h"


const PajaTypes::int32	CGITEM_WSMOBJECT = 0x5000;


enum WSMTypeE {
	WSM_WIND = 1,
	WSM_GRAVITY,
	WSM_DEFLECTOR,
};

enum ForceTypeE {
	FORCE_PLANAR = 0,
	FORCE_SPHERICAL = 1,
};



// Forward declaration
class WSMObjectC;


class ForceFieldI
{
public:
	ForceFieldI( WSMObjectC* pObj )
	{
		m_pObject = pObj;
	}

	virtual void				eval_state( PajaTypes::int32 i32Time ) = 0;

	virtual PajaTypes::Vector3C force( PajaTypes::int32 i32T, PajaTypes::float32* pPos, PajaTypes::float32* pVel, PajaTypes::int32 i32Index ) = 0;
	virtual PajaTypes::uint32	get_type() = 0;

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave ) = 0;
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad ) = 0;

protected:
	WSMObjectC*	m_pObject;
};

class CollisionObjectI
{
public:
	CollisionObjectI( WSMObjectC* pObj )
	{
		m_pObject = pObj;
	}

	virtual void				eval_state( PajaTypes::int32 i32Time ) = 0;

	virtual bool	check_collision( PajaTypes::int32 i32T, PajaTypes::float32* pPos, PajaTypes::float32* pVel, PajaTypes::float32 f32DT, PajaTypes::int32 i32Index, PajaTypes::float32 *pColTime = 0, bool bUpdatePastCollide = true ) = 0;
	virtual PajaTypes::uint32	get_type() = 0;

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave ) = 0;
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad ) = 0;

protected:
	WSMObjectC*	m_pObject;
};

//
// Wind
//

class WindC : public ForceFieldI
{
public:
	WindC( WSMObjectC* pObj );
	virtual ~WindC();

	virtual void				eval_state( PajaTypes::int32 i32Time );

	virtual PajaTypes::Vector3C force( PajaTypes::int32 i32T, PajaTypes::float32* pPos, PajaTypes::float32* pVel, PajaTypes::int32 i32Index );
	virtual PajaTypes::uint32	get_type();

	virtual void				set_strength( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_strength() const;

	virtual void				set_decay( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_decay() const;

	virtual void				set_size( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_size() const;

	virtual void				set_turbulence( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_turbulence() const;

	virtual void				set_frequency( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_frequency() const;

	virtual void				set_scale( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_scale() const;

	virtual void				set_wind_type( PajaTypes::uint32 ui32Val );
	virtual PajaTypes::uint32	get_wind_type() const;

	virtual void				set_strength_cont( ContFloatC* pCont );
	virtual void				set_decay_cont( ContFloatC* pCont );
	virtual void				set_turbulence_cont( ContFloatC* pCont );
	virtual void				set_frequency_cont( ContFloatC* pCont );
	virtual void				set_scale_cont( ContFloatC* pCont );

	virtual PajaTypes::uint32	save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32	load( FileIO::LoadC* pLoad );

protected:
	PajaTypes::float32		m_f32Strength;
	PajaTypes::float32		m_f32Decay;
	PajaTypes::uint32		m_ui32Type;
	PajaTypes::float32		m_f32Size;
	PajaTypes::float32		m_f32Turbulence;
	PajaTypes::float32		m_f32Frequency;
	PajaTypes::float32		m_f32Scale;

	ContFloatC*				m_pStrengthCont;
	ContFloatC*				m_pDecayCont;
	ContFloatC*				m_pTurbulenceCont;
	ContFloatC*				m_pFrequencyCont;
	ContFloatC*				m_pScaleCont;
};


//
// Gravity
//

class GravityC : public ForceFieldI
{
public:
	GravityC( WSMObjectC* pObj );
	virtual ~GravityC();

	virtual void				eval_state( PajaTypes::int32 i32Time );

	virtual PajaTypes::Vector3C force( PajaTypes::int32 i32T, PajaTypes::float32* pPos, PajaTypes::float32* pVel, PajaTypes::int32 i32Index );
	virtual PajaTypes::uint32	get_type();

	virtual void				set_strength( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_strength() const;

	virtual void				set_decay( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_decay() const;

	virtual void				set_size( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_size() const;

	virtual void				set_gravity_type( PajaTypes::uint32 ui32Val );
	virtual PajaTypes::uint32	get_gravity_type() const;

	virtual void				set_strength_cont( ContFloatC* pCont );
	virtual void				set_decay_cont( ContFloatC* pCont );

	virtual PajaTypes::uint32	save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32	load( FileIO::LoadC* pLoad );

protected:
	PajaTypes::float32		m_f32Strength;
	PajaTypes::float32		m_f32Decay;
	PajaTypes::float32		m_f32Size;
	PajaTypes::uint32		m_ui32Type;

	ContFloatC*				m_pStrengthCont;
	ContFloatC*				m_pDecayCont;
};


//
// Deflector
//

#define		RANDOM_FLOAT_COUNT	512
#define		RANDOM_FLOAT_MASK	(RANDOM_FLOAT_COUNT - 1)

class DeflectorC : public CollisionObjectI
{
public:
	DeflectorC( WSMObjectC* pObj );
	virtual ~DeflectorC();

	virtual void				eval_state( PajaTypes::int32 i32Time );

	virtual bool				check_collision( PajaTypes::int32 i32T, PajaTypes::float32* pPos, PajaTypes::float32* pVel, PajaTypes::float32 f32DT, PajaTypes::int32 i32Index, PajaTypes::float32 *pColTime = 0, bool bUpdatePastCollide = true );
	virtual PajaTypes::uint32	get_type();

	virtual void				set_bounce( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_bounce() const;

	virtual void				set_width( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_width() const;

	virtual void				set_height( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_height() const;

	virtual void				set_variation( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_variation() const;

	virtual void				set_chaos( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_chaos() const;

	virtual void				set_friction( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_friction() const;

	virtual void				set_inherit_velocity( PajaTypes::float32 f32Val );
	virtual PajaTypes::float32	get_inherit_velocity() const;

	virtual void				set_bounce_cont( ContFloatC* pCont );
	virtual void				set_width_cont( ContFloatC* pCont );
	virtual void				set_height_cont( ContFloatC* pCont );
	virtual void				set_variation_cont( ContFloatC* pCont );
	virtual void				set_chaos_cont( ContFloatC* pCont );
	virtual void				set_friction_cont( ContFloatC* pCont );
	virtual void				set_inherit_vel_cont( ContFloatC* pCont );

	virtual PajaTypes::uint32	save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32	load( FileIO::LoadC* pLoad );

protected:
	PajaTypes::float32		m_f32Bounce;
	PajaTypes::float32		m_f32Width;
	PajaTypes::float32		m_f32Height;
	PajaTypes::float32		m_f32Variation;
	PajaTypes::float32		m_f32Chaos;
	PajaTypes::float32		m_f32Friction;
	PajaTypes::float32		m_f32InheritVel;

	ContFloatC*				m_pBounceCont;
	ContFloatC*				m_pWidthCont;
	ContFloatC*				m_pHeightCont;
	ContFloatC*				m_pVariationCont;
	ContFloatC*				m_pChaosCont;
	ContFloatC*				m_pFrictionCont;
	ContFloatC*				m_pInheritVelCont;

	PajaTypes::float32		m_f32RandomFloat[RANDOM_FLOAT_COUNT];
};


//
// WSM Object
//

class WSMObjectC : public ScenegraphItemI
{
public:
	WSMObjectC();
	virtual ~WSMObjectC();

	virtual PajaTypes::int32			get_type();

	virtual void						set_position( const PajaTypes::Vector3C& rPos );
	virtual const PajaTypes::Vector3C&	get_position();

	virtual void						set_rotation( const PajaTypes::QuatC& rRot );
	virtual const PajaTypes::QuatC&		get_rotation();

	virtual void						eval_state( PajaTypes::int32 i32Time );
	virtual void						eval_geom( PajaTypes::int32 i32Time );

	virtual const PajaTypes::Matrix3C&	get_inv_tm();

	virtual void						set_position_controller( ContVector3C* pCont );
	virtual ContVector3C*				get_position_controller();

	virtual void						set_rotation_controller( ContQuatC* pCont );
	virtual ContQuatC*					get_rotation_controller();

	virtual void						update_dependencies( std::vector<ScenegraphItemI*> rScenegraph );

	virtual void						set_force_field( ForceFieldI* pField );
	virtual ForceFieldI*				get_force_field();

	virtual void						set_collision_object( CollisionObjectI* pObj );
	virtual CollisionObjectI*			get_collision_object();

	virtual PajaTypes::uint32			save( FileIO::SaveC* pSave );
	virtual PajaTypes::uint32			load( FileIO::LoadC* pLoad );

private:
	PajaTypes::Vector3C	m_rPosition;
	PajaTypes::QuatC	m_rRotation;

	PajaTypes::Matrix3C	m_rInvTM;

	ForceFieldI*		m_pForceField;
	CollisionObjectI*	m_pCollisionObject;

	ContVector3C*		m_pPosCont;
	ContQuatC*			m_pRotCont;
};


#endif // WSMOBJECT_H