////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 RWS Inc, All Rights Reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as published by
// the Free Software Foundation
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// SndRelay.cpp
// Project: Nostril (aka Postal)
// 
// History:
//		08/11/97 JMI	Stole infrastructure from SoundThing.
//
//		08/11/97	JMI	Now verifies that the parent ID is that of a CSoundThing
//							before using it.  Don't know what would happen otherwise
//							but I'm sure it would suck.
//
//		09/27/99	JMI	Eliminated boolean performance warnings.
//
//////////////////////////////////////////////////////////////////////////////
//
// This CThing-derived class will relay sound volumes based on 
//	DistanceToVolume() (i.e., the distance to the ear (usually the local dude))
// to the selected CSoundThing.
//
//////////////////////////////////////////////////////////////////////////////
#define SNDRELAY_CPP

#include "RSPiX.h"
#include "SndRelay.h"
#include "SoundThing.h"
#include "game.h"

// This class has its own GetRandom() to keep it from de-synching the game.
#ifdef GetRandom
	#undef GetRandom
#endif

#ifdef GetRand
	#undef GetRand
#endif


////////////////////////////////////////////////////////////////////////////////
// Macros/types/etc.
////////////////////////////////////////////////////////////////////////////////

#define IMAGE_FILE			"soundSatellite.bmp"

#define GUI_FILE_NAME		"res/editor/SndRelay.gui"

////////////////////////////////////////////////////////////////////////////////
// Class statics.
////////////////////////////////////////////////////////////////////////////////

int16_t	CSndRelay::ms_sFileCount			= 0;	// File count.         

////////////////////////////////////////////////////////////////////////////////
// Load object (should call base class version!)
////////////////////////////////////////////////////////////////////////////////
int16_t CSndRelay::Load(								// Returns 0 if successfull, non-zero otherwise
	RFile* pFile,											// In:  File to load from
	bool bEditMode,										// In:  True for edit mode, false otherwise
	int16_t sFileCount,										// In:  File count (unique per file, never 0)
	uint32_t	ulFileVersion)									// In:  Version of file format to load.
	{
	int16_t sResult = CThing::Load(pFile, bEditMode, sFileCount, ulFileVersion);
	if (sResult == 0)
		{
		// If new file . . . 
		if (sFileCount != ms_sFileCount)
			{
			ms_sFileCount	= sFileCount;
			
			// Do one time stuff.
			}

		switch (ulFileVersion)
			{
			default:
			case 44:
			case 43:
			case 42:
			case 41:
			case 40:
			case 39:
			case 38:
			case 37:
			case 36:
			case 35:
			case 34:
			case 33:
			case 32:
			case 31:
			case 30:
			case 29:
			case 28:
			case 27:
			case 26:
			case 25:
			case 24:
			case 23:
			case 22:
			case 21:
			case 20:
			case 19:
			case 18:
			case 17:
			case 16:
			case 15:
			case 14:
			case 13:
			case 12:
			case 11:
			case 10:
			case 9:
			case 8:
			case 7:
			case 6:
			case 5:
			case 4:
			case 3:
			case 2:
			case 1:
				pFile->Read(&m_dX);
				pFile->Read(&m_dY);
				pFile->Read(&m_dZ);

				int32_t	lBool;
				pFile->Read(&lBool);
				m_bInitiallyEnabled	= lBool ? true : false;

				pFile->Read(&m_idParent);

				break;
			}

		// Make sure there were no file errors or format errors . . .
		if (!pFile->Error() && sResult == 0)
			{
			sResult = Init();
			}
		else
			{
			sResult = -1;
			TRACE("CSndRelay::Load(): Error reading from file!\n");			
			}
		}

	return sResult;
	}

////////////////////////////////////////////////////////////////////////////////
// Startup object
////////////////////////////////////////////////////////////////////////////////
int16_t CSndRelay::Startup(void)								// Returns 0 if successfull, non-zero otherwise
	{
	return 0;
	}


////////////////////////////////////////////////////////////////////////////////
// Shutdown object
////////////////////////////////////////////////////////////////////////////////
int16_t CSndRelay::Shutdown(void)							// Returns 0 if successfull, non-zero otherwise
	{
	return 0;
	}


////////////////////////////////////////////////////////////////////////////////
// Suspend object
////////////////////////////////////////////////////////////////////////////////
void CSndRelay::Suspend(void)
	{
	m_sSuspend++;
	}


////////////////////////////////////////////////////////////////////////////////
// Resume object
////////////////////////////////////////////////////////////////////////////////
void CSndRelay::Resume(void)
	{
	m_sSuspend--;
	}


////////////////////////////////////////////////////////////////////////////////
// Update object
////////////////////////////////////////////////////////////////////////////////
void CSndRelay::Update(void)
	{
	if (!m_sSuspend)
		{
		// If enabled . . .
		if (m_bEnabled == true)
			{
			// Attempt to get ptr to our parent . . .
			CSoundThing*	pst	= NULL;	// Safety.
			if (m_pRealm->m_idbank.GetThingByID((CThing**)&pst, m_idParent) == 0)
				{
				// Make sure this is what we think it is . . .
				if (pst->GetClassID() == CSoundThingID)
					{
					// Report volume based on our distance to the ear.
					pst->RelayVolume(DistanceToVolume(m_dX, m_dY, m_dZ, pst->m_lVolumeHalfLife) );
					}
				else
					{
					TRACE("Update(): ID %hu is not a \"SoundThing\", it is a \"%s\".\n",
						pst->GetClassID(),
						ms_aClassInfo[pst->GetClassID()].pszClassName);
					}
				}
			}

		// Process messages.
		ProcessMessages();

		switch (m_state)
			{
			case State_Happy:
				break;
			case State_Delete:
				// Banzai!
				delete this;
				return ;
			}
		}
	}


////////////////////////////////////////////////////////////////////////////////
// Render object
////////////////////////////////////////////////////////////////////////////////
void CSndRelay::Render(void)
	{
	}


////////////////////////////////////////////////////////////////////////////////
// Helper function/macro for changing a GUIs text value.
////////////////////////////////////////////////////////////////////////////////
inline void SetGuiItemVal(	// Returns nothing.
	RGuiItem*	pguiRoot,	// In:  GUI Root.
	int32_t			lId,			// In:  ID of item whose text we'll change.
	int32_t			lVal)			// In:  New value.
	{
	RGuiItem*	pgui	= pguiRoot->GetItemFromId(lId);
	if (pgui)
		{
		pgui->SetText("%ld", lVal);
		pgui->Compose();
		}
	}

////////////////////////////////////////////////////////////////////////////////
// Callback from multibtn checkbox.
////////////////////////////////////////////////////////////////////////////////
static void CheckEnableGuiCall(	// Returns nothing.
	RGuiItem*	pgui_pmb)			// In:  GUI pointer to the multi button that was 
											// pressed.
	{
	ASSERT(pgui_pmb->m_type == RGuiItem::MultiBtn);

	RMultiBtn*	pmb	= (RMultiBtn*)pgui_pmb;

	// Show based on value stored in GUI.
	int16_t	sVisible	= pmb->m_ulUserData;
	// If unchecked . . .
	if (pmb->m_sState == 1)
		{
		// Opposite show/hide state.
		sVisible	= !sVisible;
		}

	RGuiItem*	pguiLoopSettingsContainer	= pmb->GetParent()->GetItemFromId(pmb->m_ulUserInstance);
	if (pguiLoopSettingsContainer)
		{
		pguiLoopSettingsContainer->SetVisible(sVisible);
		}
	}

////////////////////////////////////////////////////////////////////////////////
// Init object
////////////////////////////////////////////////////////////////////////////////
int16_t CSndRelay::Init(void)							// Returns 0 if successfull, non-zero otherwise
	{
	int16_t sResult = 0;

	Kill();

	m_bEnabled = m_bInitiallyEnabled;
// todo?
	/*if (m_sprite.m_pImage == 0)
		{
		sResult = rspGetResource(&g_resmgrGame, m_pRealm->Make2dResPath(IMAGE_FILE), &m_sprite.m_pImage);
		if (sResult == 0)
			{
			// This is a questionable action on a resource managed item, but it's
			// okay if EVERYONE wants it to be an FSPR8.
			if (m_sprite.m_pImage->Convert(RImage::FSPR8) != RImage::FSPR8)
				{
				sResult = -1;
				TRACE("CSndRelay::GetResource() - Couldn't convert to FSPR8\n");
				}
			}
		}*/

	return sResult;
	}


////////////////////////////////////////////////////////////////////////////////
// Kill object
////////////////////////////////////////////////////////////////////////////////
int16_t CSndRelay::Kill(void)							// Returns 0 if successfull, non-zero otherwise
	{
//	if (m_sprite.m_pImage != 0)
//		rspReleaseResource(&g_resmgrGame, &m_sprite.m_pImage);

	m_pRealm->m_scene.RemoveSprite(&m_sprite);

	return 0;
	}


////////////////////////////////////////////////////////////////////////////////
// Process our message queue.
////////////////////////////////////////////////////////////////////////////////
void CSndRelay::ProcessMessages(void)
	{
	// Check queue of messages.
	GameMessage	msg;
	while (m_MessageQueue.DeQ(&msg) == true)
		{
		switch(msg.msg_Generic.eType)
			{
			case typeObjectDelete:
				m_state	= State_Delete;
				break;
			}
		
		}
	}

////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
