//-----------------------------------------------------------------------------
//
//  $Logfile:: /game/gravpath.h                                               $
// $Revision:: 2                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 12/27/00 7:06 PM                                               $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// Gravity path - Used for underwater currents and wells.

#ifndef __GRAVPATH_H__
#define __GRAVPATH_H__

#include "g_local.h"
#include "class.h"
#include "container.h"
#include "archive.h"

class GravPathNode : public Entity
{
private:
	float speed;
	float radius;
	qboolean headnode;

public:
	qboolean active;

	CLASS_PROTOTYPE( GravPathNode );
	GravPathNode();
	void           CreatePath( Event* ev );
	void           Activate( Event* ev );
	void           Deactivate( Event* ev );
	float          Speed( void );
	float          Radius( void )
	{
		return radius;
	};
	virtual void   Archive( Archiver& arc );
	virtual void   Unarchive( Archiver& arc );
};

inline void GravPathNode::Archive( Archiver& arc )
{
	Entity::Archive( arc );

	arc.WriteFloat( speed );
	arc.WriteFloat( radius );
	arc.WriteBoolean( headnode );
	arc.WriteBoolean( active );
}

inline void GravPathNode::Unarchive( Archiver& arc )
{
	Entity::Unarchive( arc );

	speed = arc.ReadFloat();
	radius = arc.ReadFloat();
	headnode = arc.ReadBoolean();
	active = arc.ReadBoolean();
}

typedef SafePtr<GravPathNode> GravPathNodePtr;

//
// Exported templated classes must be explicitly instantiated
//

class GravPath : public Listener
{
private:
	Container<GravPathNodePtr>  pathlist;
	float pathlength;

	GravPathNodePtr from;
	GravPathNodePtr to;
	int nextnode;

public:
	CLASS_PROTOTYPE( GravPath );

	GravPath();
	~GravPath();
	void                  Clear( void );
	void                  Reset( void );
	void                  AddNode( GravPathNode* node );
	GravPathNode*      GetNode( int num );
	GravPathNode*      NextNode( void );
	Vector            ClosestPointOnPath( Vector pos, Entity& ent, float* bestdist, float* speed, float* radius );
	float                 DistanceAlongPath( const Vector& pos, float* speed );
	Vector            PointAtDistance( float dist );
	void                  DrawPath( Event* ev );
	int               NumNodes( void );
	float                 Length( void );
	GravPathNode*       Start( void );
	GravPathNode*       End( void );
	virtual void      Archive( Archiver& arc );
	virtual void      Unarchive( Archiver& arc );

	Vector mins;
	Vector maxs;
	Vector origin;
	qboolean force;
};

inline void GravPath::Archive( Archiver& arc )
{
	int i, num;

	Listener::Archive( arc );

	num = pathlist.NumObjects();
	arc.WriteInteger( num );
	for( i = 1; i <= num; i++ )
	{
		arc.WriteSafePointer( pathlist.ObjectAt( i ) );
	}

	arc.WriteFloat( pathlength );
	arc.WriteSafePointer( from );
	arc.WriteSafePointer( to );
	arc.WriteInteger( nextnode );
	arc.WriteVector( mins );
	arc.WriteVector( maxs );
	arc.WriteVector( origin );
	arc.WriteBoolean( force );
}

inline void GravPath::Unarchive( Archiver& arc )
{
	int i, num;

	Reset();

	Listener::Unarchive( arc );

	num = arc.ReadInteger();
	pathlist.Resize( num );
	for( i = 1; i <= num; i++ )
	{
		arc.ReadSafePointer( pathlist.AddressOfObjectAt( i ) );
	}

	pathlength = arc.ReadFloat();
	arc.ReadSafePointer( &from );
	arc.ReadSafePointer( &to );
	nextnode = arc.ReadInteger();
	arc.ReadVector( &mins );
	arc.ReadVector( &maxs );
	arc.ReadVector( &origin );
	force = arc.ReadBoolean();
}

class GravPathManager : public Class
{
private:
	Container<GravPath*>    pathList;

public:
	CLASS_PROTOTYPE( GravPathManager );
	~GravPathManager();
	void     Reset( void );
	void     AddPath( GravPath* p );
	void     RemovePath( GravPath* p );
	Vector   CalculateGravityPull( Entity& ent, Vector position, qboolean* force );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void GravPathManager::Archive( Archiver& arc )
{
	int i, num;

	Class::Archive( arc );

	num = pathList.NumObjects();
	arc.WriteInteger( num );
	for( i = 1; i <= num; i++ )
	{
		arc.WriteObject( pathList.ObjectAt( i ) );
	}
}

inline void GravPathManager::Unarchive( Archiver& arc )
{
	int i, num;

	Reset();

	Class::Unarchive( arc );

	num = arc.ReadInteger();
	for( i = 1; i <= num; i++ )
	{
		GravPath* ptr;

		ptr = new GravPath;
		arc.ReadObject( ptr );
		pathList.AddObject( ptr );
	}
}

extern GravPathManager gravPathManager;

extern Event EV_DrawGravPath;

#endif /* gravpath.h */
