//===========================================================================//
// File:	audiorenderer.hpp                                                //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 03/22/99  SMJ  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1999, Microsoft Corporation		                         //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Renderer.hpp"
#include "AudioChannel.hpp"

namespace Adept {

	class AudioChannel;
	class AudioCommand;
	class Interface;

	//##########################################################################
	//############################    ChannelType    ###########################
	//##########################################################################

	class ChannelType
	{
		friend class AudioRenderer;

	public:
		ChannelType();

		void SetChannelActive(AudioChannel *channel);
		void SetChannelInactive(AudioChannel *channel);

		void SetVolume(Stuff::Scalar volume);
		Stuff::Scalar GetVolume()
			{Check_Object(this); return m_volume;}

		bool IsQueued()
			{Check_Object(this); return m_queued;}
		void StopAll();

		void PauseAll();
		void ResumeAll();

		void TestInstance() const
			{}

		Stuff::ChainOf<AudioChannel*>
			m_inactiveChannels,
			m_activeChannels;
		Stuff::ChainOf<AudioCommand*>
			m_queuedCommands,
			m_loopCommands;

		static Stuff::Scalar
			s_sfxVolume,
			s_musicVolume;
		int m_type;

	protected:
		bool m_queued;
		Stuff::Scalar m_volume;
	};

	//##########################################################################
	//###########################    AudioRenderer    ##########################
	//##########################################################################

	class AudioRenderer:
		public Renderer
	{
		friend class AudioChannel;
		friend class AudioSample;

	public:
		typedef Renderer BaseClass;

		static void InitializeClass();
		static void TerminateClass();

		static ClassData *DefaultData;

		static HGOSHEAP s_Heap;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Destruction, and Testing
	//
	public:
		~AudioRenderer();
		AudioRenderer();

		static AudioRenderer *Instance;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Control and processing
	//
	public:
		enum {
			MusicType,
			VOType,
			BettyType,
			MechanicalType,
			GeneralType,
			TypeCount
		};

		void SetRendererStatus(RendererStatus status);

		void SetChannelActive(AudioChannel *channel)
			{
				Check_Object(this); Check_Object(channel);
				m_channelTypes[channel->m_type].SetChannelActive(channel);
			}

		void SetChannelInactive(AudioChannel *channel)
			{
				Check_Object(this); Check_Object(channel);
				m_channelTypes[channel->m_type].SetChannelInactive(channel);
			}

		AudioSample* UseSample(const ResourceID &handle_id);

		void AddNewCommand(AudioCommand *command)
			{Check_Object(this); Check_Pointer(command); m_newCommands.Add(command);}

		DynamicArrayOf<ChannelType> m_channelTypes;

		void PauseAll();
		void ResumeAll();

	protected:
		void ExecuteCommands(Stuff::Time target_time);
		void ExecuteImplementation(Stuff::Time target_time);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Component management
	//
	protected:
		void FlushUnusedCache();

		DynamicArrayOf<AudioChannel*> m_channels;
		Stuff::HashOf<AudioSample*, ResourceID> m_sampleCache;
		Stuff::ChainOf<AudioSample*> m_unusedSamples;
		unsigned m_cacheSize;

		//
		// Command chains
		//
		Stuff::ChainOf<AudioCommand*> m_executingCommands;
		Stuff::ChainOf<AudioCommand*> m_newCommands;

		Interface* iface;

	public:
		Component* CreateComponent(
			ClassID component_class,
			Stuff::MemoryStream *stream,
			RendererComponentWeb *web,
			Entity *entity
		);

		void SetInterface(Interface* i)
			{iface = i;}
		Interface* GetInterface()
			{return iface;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Interest Manager support
	//
	public:
		void EntityIsInteresting(
			Entity *entity,
			bool render_me
		);
		void EntityIsUninteresting(Entity *entity);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test functions
	//
	public:
		void TestInstance();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Tool functions
	//
	public:
		static Component__ClassData* CreateFactoryRequest(
			const char* component_type,
			Component__FactoryRequestParameters *parameters,
			Entity__ClassData *class_data
		);

		static void CreateRendererData(
			ResourceID							*stream_resource,
			Entity__ClassData					*class_data,
			Stuff::NotationFile					*renderer_file
		);

		static int FindChannelType(const char* channel);
	};
}

#if 1
#define AUDIO_RENDER(string) RENDER("Audio::" string)
#else
#define AUDIO_RENDER(string)
#endif

#if 1
#define AUDIO_LOAD(string) LOAD_LOGIC("Audio::" string)
#else
#define AUDIO_LOAD(string)
#endif
