#pragma once

#include "Adept.hpp"
#include "VideoComponentWeb.hpp"

using ElementRenderer::Element;

namespace ElementRenderer
{
	class GroupElement;
};

namespace Adept {

	//#########################################################################
	//########################  VideoComponent  #############################
	//#########################################################################
	//
	// When instantiating this class, the following methods must be explicitly
	// defined:
	//
	//   void InitializeClass()
	//   void SetOrigin(...)
	//	  Derivation* CreateFactoryRequest(..,)
	//
	// The methods having templates in this header file should work fine, but
	// explicitly define whatever you need.
	//

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

		static ClassData
			*DefaultData;

		typedef Component BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	protected:
		VideoComponent(
			ClassData *class_data,
			MemoryStream *stream,
			VideoComponentWeb *owning_web,
			Element* child
		);

		void
			SkipStreamData(MemoryStream *stream);

		static unsigned
			GetStreamSize(MemoryStream *stream);

	public:
		~VideoComponent();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Component support
	//
	public:
		void
			Execute();

		Element*
			GetElement()
				{Check_Object(this); return componentElement;}

		VideoComponentWeb*
			GetComponentWeb()
				{
					Check_Object(this);
					VideoComponentWeb* renderer =
						Cast_Object(
							VideoComponentWeb*,
							Component::GetComponentWeb()
						);
					Verify(renderer->GetClassID() == VideoComponentWebClassID);
					return renderer;
				}

	protected:
		Element*
			componentElement;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessors
	//
	public:
		void
			TestInstance();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool-related Functions
	//
	public:
		static ClassData*
			CreateFactoryRequest(FactoryRequestParameters *parameters);
	};

	//#########################################################################
	//########################  GroupComponent  #############################
	//#########################################################################
	//
	// WARNING: class GroupElement must be a descendant of class Element!
	//
	// When instantiating this class, the following methods must be explicitly
	// defined:
	//
	//   void InitializeClass();
	//   GroupElement* AllocateGroup();
	//   DeallocateGroup(GroupElement*);
	//   void AttachVideoComponent(VideoComponent*);
	//	  Derivation* CreateFactoryRequest(...)
	//
	// The methods having templates in this header file should work fine, but
	// explicitly define whatever you need.
	//

	class GroupComponent:
		public VideoComponent
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef VideoComponent BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructor
	//
	protected:
		GroupComponent(
			ClassData *class_data,
			MemoryStream *stream,
			VideoComponentWeb *owning_web,
			ElementRenderer::GroupElement* holder = NULL
		);

		void
			SkipStreamData(MemoryStream *stream);

		static ElementRenderer::GroupElement*
			AllocateGroup(MemoryStream *stream);

	public:
		static GroupComponent*
			Make(
				MemoryStream *stream,
				VideoComponentWeb *owning_web
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Virtual data
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Component support
	//
	public:
		ElementRenderer::GroupElement*
			GetGroupElement()
				{
					Check_Object(this);
					return
						Cast_Pointer(
							ElementRenderer::GroupElement*,
							componentElement
						);
				}

		void
			AttachChild(VideoComponent* child);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessors
	//
	public:
		void
			TestInstance();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool-related Functions
	//
	public:
		static ClassData*
			CreateFactoryRequest(FactoryRequestParameters *parameters);
	};

}

