//===========================================================================//
// File:	SREffect.hpp																		  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 2/8/99	  DPB	 Created File
//---------------------------------------------------------------------------//
// Copyright (C) 1995-97, Virtual World Entertainment, Inc.                  //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "Adept.hpp" 
#include "Mover.hpp"

namespace Adept
{

	class Effect;
	class Site;

	//##########################################################################
	//###############    Effect::ExecutionStateEngine    #######################
	//##########################################################################

	class Effect__ExecutionStateEngine:
		public Entity__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Entity__ExecutionStateEngine BaseClass;

		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef Mover__ExecutionStateEngine*
			(*Factory)(
				Effect *effect,
				FactoryRequest *request
			);

		static Effect__ExecutionStateEngine*
			Make(
				Effect *effect,
				FactoryRequest *request
			);

	protected:
		Effect__ExecutionStateEngine(
			ClassData *class_data,
			Effect *effect,
			FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			StoppedState = Entity__ExecutionStateEngine::StateCount,
			StoppingState,
			RunningState,
			KillingState,
			StateCount
		};

	int
		RequestState(
			int new_state,
			void* data = NULL
		);

	protected:
		static const StateEntry
			StateEntries[];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
			TestInstance();
	};

	//##########################################################################
	//##################    Effect::CreateMessage    ###########################
	//##########################################################################

	class Effect__CreateMessage:
		public Mover__CreateMessage
	{
	public:
		Effect__CreateMessage(
			size_t length,
			int priority,
			int message_flags,
			Stuff::RegisteredClass::ClassID class_id,
			int replicator_flags,
			const ResourceID& data_list_id,
			const Stuff::LinearMatrix4D &creation_matrix,
			Stuff::Scalar age,
			int execution_state,
			int name_id,
			int entity_alignment,
			const Stuff::Motion3D &initial_velocity = Stuff::Motion3D::Identity,
			const Stuff::Motion3D &initial_acceleration = Stuff::Motion3D::Identity
		):
			Mover__CreateMessage(
				length, 
				priority, 
				message_flags, 
				class_id,
				replicator_flags,
				data_list_id,
				creation_matrix,
				age,
				execution_state,
				name_id,
				entity_alignment
			)
				{}

		static void
			ConstructCreateMessage(Script *script);
	};

	//##########################################################################
	//#######################    Effect__GameModel    ##########################
	//##########################################################################

	class Effect__GameModel:
		public Mover__GameModel
	{
	public:
		bool
			startsRunning;
		Stuff::Point3D
			translation;
		Stuff::UnitQuaternion
			rotation;
		bool
			killOnAttachedEntityDeath;

		enum{
			NoRotation = 0,
			AgainstMotionRotation,
			IntoMotionRotation,
			UseRotation
		};

		int
			rotationType;

		enum {
			StartsRunningAttributeID = Mover__GameModel::NextAttributeID,
			TranslationAttributeID,
			RotationAttributeID,
			KillOnAttachedEntityDeathAttributeID,
			NextAttributeID
		};

		static bool
			ReadAndVerify(
				Effect__GameModel *model,
				ModelAttributeEntry *attribute_entry, 
				const char *data,
				char **error,
				int error_buffer = 128
			);

		static void
			ConstructGameModel(Script *script);

		static int
			RotationTypeTextToAscii(const char *roation_string);
		static const char *
			RotationTypeAsciiToText(int rotation_type);
	};

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef Entity__ClassData						Effect__ClassData;
	typedef Entity__Message							Effect__Message;
	typedef Entity__UpdateMessage					Effect__UpdateMessage;

	//##########################################################################
	//############################    Effect    ################################
	//##########################################################################

	class Effect:
		public Mover
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Mover BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance support
	//
	public:
		typedef Effect__ClassData						ClassData;
		typedef Effect__GameModel						GameModel;
		typedef Effect__Message							Message;
		typedef Effect__ExecutionStateEngine			ExecutionStateEngine;
		typedef Effect__CreateMessage					CreateMessage;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef Effect__CreateMessage
			CreateMessage;

		static Effect* 
			Make(
				const CreateMessage *message,
				ReplicatorID *base_id
			);
		~Effect();

		void
			Reuse(
				const CreateMessage *message,
				ReplicatorID *base_id
			);

	protected:
		Effect(
			ClassData *class_data,
			const CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);
		
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data & Game Model Support
	//
	public:
		typedef Effect__GameModel		
			GameModel;

		static ClassData
			*DefaultData;

		const GameModel*
			GetGameModel()
				{return Cast_Pointer(const GameModel*, gameModelResource.GetPointer());}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Flag Support
	//
	public:
		enum
		{
			LoopBit = Mover::NextFlagBit,
			FollowBit,
			NextFlagBit
		};

		enum 
		{
			LoopFlag = 1<<LoopBit,
			FollowFlag = 1<<FollowBit,
			DefaultFlags = HermitMode
		};

		bool
			IsLooped()
				{Check_Object(this); return (replicatorFlags&LoopFlag) != 0;}
		bool
			IsFollowing()
				{Check_Object(this); return (replicatorFlags&FollowFlag) != 0;}
		void
			SetFollowing()
				{Check_Object(this); replicatorFlags |= FollowFlag;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	public:
		int
			GetExecutionSlot();

		void
			PreCollisionExecute(Stuff::Time till);
		#if defined(LAB_ONLY)
			void
				SyncMatrices(bool update_matrix);
		#endif
		void
			PostCollisionExecute(Stuff::Time till);

		void
			BecomeInteresting(bool render_me);

		void
			SetFollowEntity(Entity *entity);
		void
			SetFollowEntity(Site *site);
		void
			PlaceOnEntity(Stuff::LinearMatrix4D offsetOnEntity);
		void 
			PlaceOnEntity();
		void
			PlaceOnSite();

		Stuff::SlotOf<Entity *>
			followEntity;
		Stuff::SlotOf<Site *>
			followSite;
		Stuff::LinearMatrix4D
			effectOffset;

#if defined (_ARMOR)
		bool iAmDead;
#endif

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		enum {
			VideoStatusAttributeID = Mover::NextAttributeID,
			AudioStatusAttributeID,
			NextAttributeID
		};

		bool
			videoStatus;
		int
			audioStatus;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
			TestInstance();
	};

	inline Effect__ExecutionStateEngine::Effect__ExecutionStateEngine(
		ClassData *class_data,
		Effect *effect,
		FactoryRequest *request
	):
		BaseClass(class_data, effect, request)
			{}

}
