//===========================================================================//
// 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 "Component.hpp"

namespace Adept {

	class Renderer;
	class Entity__ClassData;

	//##########################################################################
	//###########################  ComponentWeb  ###############################
	//##########################################################################

	class _declspec(novtable) ComponentWeb:
		public Stuff::Plug
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	public:
		ComponentWeb(
			ClassData *class_data,
			const ResourceID &script_id,
			ComponentWeb *parent_web = NULL
		);
		~ComponentWeb();

		void
			TestInstance();

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

		virtual void
			LoadComponentWeb() = 0;

		virtual bool
			ShouldWebBeKilled();

		const ResourceID &
			GetScriptResourceID()
				{Check_Object(this); return scriptResourceID;}

		ComponentWeb*
			GetParentWeb()
				{Check_Object(this); return parentWeb;}

	protected:
		ComponentWeb 
			*parentWeb;
		ResourceID
			scriptResourceID;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Web building
	//
	public:
		virtual Component*
			AddComponent(Component *component);
		void
			AddComponentWeb(ComponentWeb *web);
		virtual Component*
			FindComponent(const ComponentID &component);

	protected:
		Stuff::ChainOf<Component*>
			ownedComponents;
		Stuff::ChainOf<ComponentWeb*>
			ownedWebs;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Web execution
	//
	public:
		void
			ExecuteWatcherComponents();
		void
			AddTemporaryWatcher(Component *component);
		void
			SendCommand(int component_command);

	protected:
		Stuff::ChainOf<Component*>
			commandReceivers;
		Stuff::ChainOf<Component*>
			watcherComponents;
		Stuff::SortedChainOf<Component*, int>
			temporaryWatchers;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool support
	//
	public:
		typedef Component::ClassData*
			(*FactoryRequestCreator)(
				const char* component_type,
				Component::FactoryRequestParameters *parameters
			);

		static bool
			CreateComponentStream(
				ResourceID						*stream_resource,
				Stuff::NotationFile 			*model_file,
				Stuff::NotationFile				*component_file,
				FactoryRequestCreator			component_builder,
				Component::CommandEncoder		command_encoder
			);
	};

	//##########################################################################
	//######################  EntityComponentWeb  ##########################
	//##########################################################################

	class EntityComponentWeb:
		public ComponentWeb
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	public:
		EntityComponentWeb(
			ClassData *class_data,
			Entity *entity,
			const ResourceID &script_id,
			EntityComponentWeb *parent_web = NULL
		);
		~EntityComponentWeb();

		void
			TestInstance();

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

		void
			LoadComponentWeb() = 0;

		EntityComponentWeb*
			GetParentWeb()
				{
					Check_Object(this);
					return Cast_Object(EntityComponentWeb*, parentWeb);
				}

		Entity*
			GetEntity()
				{Check_Object(this); return owningEntity;}

	protected:
		Entity
			*owningEntity;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool support
	//
	public:
		typedef Component::ClassData*
			(*FactoryRequestCreator)(
				const char* component_type,
				Component::FactoryRequestParameters *parameters,
				Entity__ClassData *class_data
			);

		static bool
			CreateComponentStream(
				ResourceID					*stream_resource,
				Entity__ClassData			*class_data,
				Stuff::NotationFile 		*model_file,
				Stuff::NotationFile			*component_file,
				FactoryRequestCreator		component_builder,
				Component::CommandEncoder	command_encoder
			);
	};

	//##########################################################################
	//#######################  RendererComponentWeb  ###########################
	//##########################################################################

	class _declspec(novtable) RendererComponentWeb:
		public EntityComponentWeb
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	public:
		RendererComponentWeb(
			ClassData *class_data,
			Entity *entity,
			Renderer *renderer,
			const ResourceID &script_id,
			RendererComponentWeb *parent_web = NULL
		);
		~RendererComponentWeb();

		void
			TestInstance();

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

		void
			LoadComponentWeb();
		void
			LoadFromStream(Stuff::MemoryStream *stream);

		RendererComponentWeb*
			GetParentWeb()
				{
					Check_Object(this);
					return Cast_Object(RendererComponentWeb*, parentWeb);
				}
		virtual void
			SetInterest(bool rendered)=0;

		Renderer*
			GetRenderer()
				{Check_Object(this); return owningRenderer;}

	protected:
		Renderer
			*owningRenderer;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Web building
	//
	public:
		Component*
			AddComponent(Component *component);
		Component*
			FindComponent(const ComponentID &component);
	};

}
