#pragma once

#include "MW4.hpp"
#include "WeaponMover.hpp"

namespace Adept{class Effect;}

namespace MechWarrior4
{	

	class StickyMover;

	//##########################################################################
	//###############    StickyMover::ExecutionStateEngine    ##################
	//##########################################################################

	class StickyMover__ExecutionStateEngine:
		public WeaponMover__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef WeaponMover__ExecutionStateEngine BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef StickyMover__ExecutionStateEngine*
			(*Factory)(
				StickyMover *weapon,
				FactoryRequest *request
			);

		static StickyMover__ExecutionStateEngine*
			Make(
				StickyMover *weapon,
				FactoryRequest *request
			);

	protected:
		StickyMover__ExecutionStateEngine(
			ClassData *class_data,
			StickyMover *weapon,
			FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			StickyExecutionState = WeaponMover__ExecutionStateEngine::StateCount,
			StateCount
		};

	protected:
		static const StateEntry
			StateEntries[];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      		TestInstance() const;
	};
	
	//##########################################################################
	//###########################   StickyMover::GameModel    ##################
	//##########################################################################

	class StickyMover__GameModel:
		public WeaponMover__GameModel
	{
	public:
		
		Adept::ResourceID
			idleLoopResource;
		Stuff::Scalar
			activeTime;

		enum {
			ActiveTimeAttributeID = WeaponMover__GameModel::NextAttributeID,
			IdleLoopResourceAttributeID,
			NextAttributeID
		};

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

		static void
			ConstructGameModel(Script *script);
	};

	
	//##########################################################################
	//############################    StickyMover    ###########################
	//##########################################################################

	//-------------------------------------------------------------------------
	// The following helper classes must always be typedef'd or overriden by an
	// inheritor
	//
	typedef WeaponMover__ClassData						StickyMover__ClassData;
	typedef WeaponMover__Message						StickyMover__Message;
	typedef WeaponMover__CreateMessage					StickyMover__CreateMessage;
	
	//-----------------------  End of inheritance stuff ------------------------

	class StickyMover:
		public WeaponMover
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef WeaponMover BaseClass;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef StickyMover__ClassData						ClassData;
		typedef StickyMover__GameModel						GameModel;
		typedef StickyMover__Message						Message;
		typedef StickyMover__ExecutionStateEngine			ExecutionStateEngine;
		typedef StickyMover__CreateMessage					CreateMessage;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static StickyMover* 
			Make(
				CreateMessage *message,
				ReplicatorID *base_id
			);
	
		StickyMover(
			ClassData *class_data,
			CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);

		~StickyMover();

		void SentenceToDeathRow();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Game Model support
	//
	public:
		const GameModel*
			GetGameModel()
				{return Cast_Pointer(const GameModel*, gameModelResource.GetPointer());}

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

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

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
		void
			PreCollisionExecute(Stuff::Time till);
		bool
			CollisionHandler(
				Stuff::LinearMatrix4D *new_position,
				Stuff::DynamicArrayOf<CollisionData> *collisions
			);
		void
			PostCollisionExecute(Stuff::Time till);
		virtual void
			OnActiveTimeStart()
				{}
		virtual void
			OnActiveTimeEnd()
				{}
		void
			CreateIdleEffect();

		Stuff::SlotOf<Adept::Entity *>
			attachedEntity;
		Stuff::Point3D
			entityOffset;

		Stuff::SlotOf<Adept::Effect*>
			idleEffect;

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

	inline
		StickyMover__ExecutionStateEngine::StickyMover__ExecutionStateEngine(
			ClassData *class_data,
			StickyMover *mover,
			FactoryRequest *request
		):
			WeaponMover__ExecutionStateEngine(class_data, mover, request)
	{
	}
}
