//===========================================================================//
// File:	cmpnnt.hh                                                           //
// Project: MUNGA           Brick: Watcher											  //
// Contents: 						  															  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 12/14/94  ECH  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Receiver.hpp"

namespace Adept {
	class ComponentID;
}

namespace GetHashFunctions {
	unsigned
		GetHashValue(const Adept::ComponentID &value);
}

namespace Adept {

	class Channel;
	class ComponentWeb;

	class ComponentID
	{
	public:
		ResourceID
			scriptResourceID;
		int
			componentNumber;

		bool
			operator==(const ComponentID& component) const;
		bool
			operator!=(const ComponentID& component) const;
		bool
			operator>(const ComponentID& component) const;

		friend unsigned
			GetHashFunctions::GetHashValue(const ComponentID &value)
				{
					//
					// Verify that the unsigned is 32 bits wide
					// Hash value is first 16 bits of fileID and first 16 bits of recordID
					//
					Verify(sizeof(unsigned) == sizeof(DWORD));
					return
						(GetHashValue(value.scriptResourceID) << 8)
						 | (value.componentNumber&0xFF);
				}

		void
			TestInstance()
				{}
	};

	class Component__FactoryRequestParameters;

	//##########################################################################
	//############################  Component  #################################
	//##########################################################################

	//##########################################################################
	// The following classes must always be typedef'd or overriden by an
	// inheritor
	//

	typedef Receiver__ClassData		Component__ClassData;
	typedef Receiver__Message			Component__Message;
	class Component__FactoryRequestParameters;

	//---------------------  End of inheritance stuff -------------------------

	class Component:
		public Receiver
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	public:
		typedef Component__ClassData			ClassData;
		typedef Component__Message				Message;
		typedef Component__FactoryRequestParameters
			FactoryRequestParameters;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	public:
		Component(ClassData *class_data);
		virtual
			~Component();

	protected:
		Component(
			ClassData *class_data,
			Stuff::MemoryStream *stream,
			ComponentWeb *owning_web
		);

		static Component*
			DoesComponentExist(
				Stuff::MemoryStream *stream,
				ComponentWeb *owningWeb
			);

		void
			SkipStreamData(Stuff::MemoryStream *stream);

		static unsigned
			GetStreamSize(Stuff::MemoryStream *stream);

		void
			ReadInputsFromStream(
				Stuff::MemoryStream *stream,
				ComponentWeb *owning_web
			);

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Component execution
	//
	public:
		virtual void
			Execute();
		virtual void
			ChannelChanged(Channel *channel);

		const ComponentID&
			GetComponentID()
				{Check_Object(this); return componentID;}

		ComponentWeb*
			GetComponentWeb()
				{Check_Object(this); return componentWeb;}

	protected:
		ComponentID
			componentID;
		ComponentWeb
			*componentWeb;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Flags Support
	//
	public:	
		enum {
			SharedBit = 0,
			SimulationShouldExecuteBit,
			RendererShouldExecuteBit,
			SimulationShouldExecuteOnceBit,
			RendererShouldExecuteOnceBit,
			DoesReceiveCommandsBit,
			NextBit
		};

		#if NextBit > INT_BITS
			#error Too many flag bits requested!
		#endif

		enum {
			SharedFlag							= 1<<SharedBit,
			SimulationShouldExecuteFlag			= 1<<SimulationShouldExecuteBit,
			RendererShouldExecuteFlag			= 1<<RendererShouldExecuteBit,
			SimulationShouldExecuteOnceFlag		= 1<<SimulationShouldExecuteOnceBit,
			RendererShouldExecuteOnceFlag		= 1<<RendererShouldExecuteOnceBit,
			DoesReceiveCommandsFlag				= 1<<DoesReceiveCommandsBit
		};

		bool
			IsShared()
				{Check_Object(this); return (componentFlags & SharedFlag) != 0;}

		bool
			ShouldSimulationExecute()
				{Check_Object(this); return (componentFlags & SimulationShouldExecuteFlag) != 0;}

		bool
			ShouldRendererExecute()
				{Check_Object(this); return (componentFlags & RendererShouldExecuteFlag) != 0;}

		bool
			ShouldSimulationExecuteOnce()
				{Check_Object(this); return (componentFlags & SimulationShouldExecuteOnceFlag) != 0;}
		void
			SetSimulationShouldExecuteOnce()
				{Check_Object(this); componentFlags |= SimulationShouldExecuteOnceFlag;}
		void
			ClearSimulationShouldExecuteOnce()
				{Check_Object(this); componentFlags &= ~SimulationShouldExecuteOnceFlag;}

		bool
			ShouldRendererExecuteOnce()
				{Check_Object(this); return (componentFlags & RendererShouldExecuteOnceFlag) != 0;}
		void
			SetRendererShouldExecuteOnce()
				{Check_Object(this); componentFlags |= RendererShouldExecuteOnceFlag;}
		void
			ClearRendererShouldExecuteOnce()
				{Check_Object(this); componentFlags &= ~RendererShouldExecuteOnceFlag;}

		int
			GetWatcherPriority()
				{Check_Object(this); return watcherPriority;}
		bool
			DoesReceiveCommands()
				{Check_Object(this); return (componentFlags & DoesReceiveCommandsFlag) != 0;}

		int
			componentFlags;

	protected:
		int
			watcherPriority;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool Support
	//
	public:
		typedef int
			(*CommandEncoder)(const char* command_name);

		typedef ClassData*
			(*FactoryRequestCreator)(FactoryRequestParameters* parameters);

		static ClassData*
			CreateFactoryRequest(FactoryRequestParameters *parameters);

		static bool
			ReadInputsFromPage(
				FactoryRequestParameters *parameters,
				Component::ClassData *required_class
			);

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

	class ComponentDescriptor
	{
	public:
		Component::ClassData
			*m_classData;
		Stuff::MString
			m_name;

		void
			TestInstance() const
				{}

		static int
			FindName(
				Stuff::DynamicArrayOf<ComponentDescriptor> *array,
				int size,
				const char* name
			);
	};

	class Component__FactoryRequestParameters
	{
	public:
		Stuff::MemoryStream
			*m_stream;
		int
			m_index;
		Stuff::Page
			*m_page;

		Stuff::DynamicArrayOf<ComponentDescriptor>
			*m_components;

		void
			TestInstance() const
				{}
	};
}

namespace MemoryStreamIO {

	inline Stuff::MemoryStream&
		Read(
			Stuff::MemoryStream* stream,
			Adept::ComponentID *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline Stuff::MemoryStream&
		Write(
			Stuff::MemoryStream* stream,
			const Adept::ComponentID *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

}

