#pragma once

#include "Adept.hpp"
#include "State.hpp"

namespace Adept {

	class Entity;

	//##########################################################################
	//#####################    Entity::StateEngine    ##########################
	//##########################################################################

	class Entity__ExecutionStateEngine__ClassData;

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

		typedef StateEngine BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance support
	//
	public:
		typedef Entity__ExecutionStateEngine__ClassData ClassData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef Entity__ExecutionStateEngine*
			(*Factory)(
				Entity *entity,
				const FactoryRequest *request
			);

		static Entity__ExecutionStateEngine*
			Make(
				Entity *entity,
				const FactoryRequest *request
			);

	protected:
		Entity__ExecutionStateEngine(
			ClassData *class_data,
			Entity *entity,
			const FactoryRequest *request
		);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			NeverExecuteState = StateEngine::StateCount,
			AlwaysExecuteState,
			ExecuteOnceState,
			StateCount
		};

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

	protected:
		static const StateEntry
			StateEntries[];

		Entity
			*owningEntity;

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

	//##########################################################################
	//#####    Entity::StateEngine::ClassData    ##########
	//##########################################################################

	class Entity__ExecutionStateEngine__ClassData:
		public StateEngine::ClassData
	{
		friend class Entity__ExecutionStateEngine;

	public:
		typedef StateEngine::ClassData BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction
	//
	public:
		Entity__ExecutionStateEngine__ClassData(
			Stuff::RegisteredClass::ClassID class_id,
			const char *class_name,
			StateEngine::ClassData *parent,
			int state_count,
			const StateEngine__StateEntry *state_entries,
			Entity__ExecutionStateEngine::Factory engine_factory,
			Entity__ExecutionStateEngine::FactoryRequest::Factory request_factory
		):
			StateEngine__ClassData(
				class_id,
				class_name,
				parent,
				state_count,
				state_entries,
				(StateEngine::Factory)engine_factory,
				request_factory
			)
				{}

		Entity__ExecutionStateEngine*
			Make(
				Entity *entity,
				const Entity__ExecutionStateEngine::FactoryRequest *request
			)
				{
					Check_Object(this); Check_Pointer(entity); Check_Object(request);
					Check_Pointer(engineFactory);
					return (*(Entity__ExecutionStateEngine::Factory)engineFactory)(entity, request);
				}
		
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
			TestInstance();
	};

	inline Entity__ExecutionStateEngine::Entity__ExecutionStateEngine(
		ClassData *class_data,
		Entity *entity,
		const FactoryRequest *request
	):
		BaseClass(class_data, request),
		owningEntity(entity)
	{
		Check_Pointer(entity);
	}

	inline Entity__ExecutionStateEngine::ClassData*
		Entity__ExecutionStateEngine::GetClassData()
	{
		Check_Object(this);
		return Cast_Pointer(ClassData*, classData);
	}

}

