/* ***** BEGIN LICENSE BLOCK ***** 
 * Version: RCSL 1.0/RPSL 1.0 
 *  
 * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
 *      
 * The contents of this file, and the files included with this file, are 
 * subject to the current version of the RealNetworks Public Source License 
 * Version 1.0 (the "RPSL") available at 
 * http://www.helixcommunity.org/content/rpsl unless you have licensed 
 * the file under the RealNetworks Community Source License Version 1.0 
 * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
 * in which case the RCSL will apply. You may also obtain the license terms 
 * directly from RealNetworks.  You may not use this file except in 
 * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
 * applicable to this file, the RCSL.  Please see the applicable RPSL or 
 * RCSL for the rights, obligations and limitations governing use of the 
 * contents of the file.  
 *  
 * This file is part of the Helix DNA Technology. RealNetworks is the 
 * developer of the Original Code and owns the copyrights in the portions 
 * it created. 
 *  
 * This file, and the files included with this file, is distributed and made 
 * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
 * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 * 
 * Technology Compatibility Kit Test Suite(s) Location: 
 *    http://www.helixcommunity.org/content/tck 
 * 
 * Contributor(s): 
 *  
 * ***** END LICENSE BLOCK ***** */

// rta includes
#include "ihxtprofile.h"
#ifdef _MAC_MACHO
#include <Carbon/Carbon.h>
#endif
#include "ihxtbase.h"				
#include "ihxtinputformathelper.h"
#include "ihxtconstants.h"			
#include "ihxtaudioformat.h"

// reader includes 
#include <stdio.h>				
#include <sys/stat.h>
#include "InWAVReader.h"

// filter includes
#include "InWAVFilter.h"	

// agent includes
#include "ihxtconfigagenthelper.h"	
#include "InWAVAgent.h"		
#include "rtainwavplugin.h"		
//#include <string.h>
#include "assert.h"

#include <string>
using namespace std;

/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSInWAVAgent  ( Probably leave as is )
// Purpose:
//	Constructor
//
//	STEP 1 - Fill in your agent's class name 
//
CRSInWAVAgent::CRSInWAVAgent( ) 
	: m_pOutputFormat( NULL )
	, m_pConnectedOutputFormat( NULL )
	, m_pAudioTrack( NULL )
	, m_pAudioDuration( NULL )
	, m_pIFH( NULL )
	, m_lRefCount( 0 )
{
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	~CRSInWAVAgent  ( Probably leave as is )
// Purpose:
//	Destructor
CRSInWAVAgent::~CRSInWAVAgent( )
{
	HX_RELEASE( m_pOutputFormat );
	HX_RELEASE( m_pConnectedOutputFormat );
	HX_RELEASE( m_pAudioTrack );
	HX_RELEASE( m_pAudioDuration );
	HX_RELEASE( m_pIFH );
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	FillInPropertyBags	(Probably Leave as is) 
// Purpose:
//	helper for filling in properties bags -- gets factory from filter
HX_RESULT CRSInWAVAgent::FillInPropertyBags()
{
	//	STEP 2 - Possibly add additional read only properties
	GetActualPropertyBag()->SetBool( kPropIsRealTime, FALSE );
	GetActualPropertyBag()->SetBool( kPropIsRepeatable, TRUE );
	GetActualPropertyBag()->SetString( kPropPluginName, kValuePluginNameAVFileWAVUncomp );

	//	STEP 3 - Possibly Create other relevant property bags 
	HX_RESULT res = HXR_OK;
	if (m_pOutputFormat == NULL)
	{
		res = m_pFactory->CreateInstance( IID_IHXTPropertyBag, (void **) &m_pOutputFormat );
	}
	return res;
}



//
//	STEP 4 - override any of the OnSetXXX for any values this filter supports
//

/////////////////////////////////////////////////////////////////////////
// LOGGING NOTES 
//	
//	Most logging occurs on the onsetxxx functions where parameters are
//	sent into the plugin and validated
//	
//	Log an error in the following situations:
//		if a required parameter is missing
//		if an unrecognized property is sent in
//		if incoming parameters do not conform to the proper range 
//		wherever a serious assert is presented

/////////////////////////////////////////////////////////////////////////
// Method:
//	OnSetString  ( Leave as is unless new strings/types are needed )
// Purpose:
//	Override to handle setting the one acceptable string -- the filename
STDMETHODIMP CRSInWAVAgent::OnSetString( const char* szName, const CHAR *cszValue ) 
{ 
	if (!szName || !cszValue)
	{
		return HXR_POINTER;
	}

	// if incoming string is not a filename then fail
	if ( strcmp( kPropInputPathname, szName ) )
	{
		if( m_pLogWriter )
			m_pLogWriter->LogMessage( kRealNetworks, LC_APP_ERROR, FILEREAD, NO_TRANSLATE, "Unrecognized parameter passed to rn-avfile-wavuncompressed.");

		assert( FALSE );
		return HXR_FAIL;
	}

	// fail on the null string
	if ( 0 == strcmp( cszValue, "" ) )
	{
		if( m_pLogWriter )
			m_pLogWriter->LogMessage( kRealNetworks, LC_APP_ERROR, FILEREAD, NO_TRANSLATE, "Empty filename sent to rn-avfile-wavuncompressed.");
		
		assert( FALSE );
		return HXR_FAIL;
	}

	// switch separators if need be for a cross platform path
	string strFilename = cszValue;

	basic_string<char>::iterator posIter;
	for(posIter = strFilename.begin(); posIter != strFilename.end(); ++posIter)
	{
		if ( (*posIter == '\\' || *posIter == '/' ) )
			*posIter = OS_SEPARATOR_CHAR;
	}
	
	// Other required operations may occur at this point 
	HX_RESULT res = DoOpen( strFilename.c_str() );

	if (SUCCEEDED(res))
	{
		//	STEP 5 - fill in required properties appropriate for the media format
		m_pOutputFormat->SetString( kPropMediaFormat, kValueMediaFormatUncompAudio );
		m_pOutputFormat->SetUint( kPropAudioChannelFormat, HXT_MAKE_CHANNELMASK( GetNumChannels() ) );
		m_pOutputFormat->SetUint( kPropAudioSampleFormat, 
										// XXXRB - refine BYTES_PER_SAMPLE calc GetBitsPerSample()/ 8 in future
										HXT_MAKE_SAMPLE_FORMAT( HXT_ENDIANNESS_LITTLE, GetBitsPerSample(), GetBitsPerSample()/ 8 ));

		m_pOutputFormat->SetUint( kPropAudioSampleRate, GetSampleRate() );
	}
	else
	{
		if (m_pLogWriter && res == HXR_INVALID_FILE)
			m_pLogWriter->LogMessage( kRealNetworks, LC_APP_DIAG, FILEREAD, NO_TRANSLATE, "Invalid filename sent to rn-avfile-wavuncompressed.");

		assert( FALSE );
	}

	if (SUCCEEDED(res))
		res = FillTrackBag( cszValue );	
	
	if (SUCCEEDED(res))
		GetActualPropertyBag()->SetString( kPropStatus, kValueOkayStatus );
	else
		GetActualPropertyBag()->SetString( kPropStatus, kValueErrorStatus );

	return res;
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	FillTrackBag ( Change to fit particular input properties ) 
// Purpose:
//	Helper to fill in property info once file has been loaded
//
//	STEP 6 - fill in appropriate info bag properties for this type of input file
//
HX_RESULT CRSInWAVAgent::FillTrackBag( const CHAR *cszValue ) 
{
	// must set filename
	HX_RESULT res = GetActualPropertyBag()->SetString( kPropInputPathname, cszValue );

	if (SUCCEEDED(res))
		res = m_pFactory->CreateInstance( IID_IHXTTime, (void**) &m_pAudioDuration );
	
	if (SUCCEEDED(res))
		m_pAudioDuration->SetMilliSeconds( GetDuration() );

	// must set duration
	if (SUCCEEDED(res))
		GetActualPropertyBag()->SetUnknown( kPropDuration, m_pAudioDuration );

	// must set kPropNumTracks 
	if (SUCCEEDED(res))
		GetActualPropertyBag()->SetUint( kPropNumTracks, 1 );

	if (SUCCEEDED(res))
		res = m_pFactory->CreateInstance( IID_IHXTInputFormatHelper, (void**)&m_pIFH );

	if (SUCCEEDED(res))
		m_pIFH->BeginFormatInputInfo(	kValuePluginTypeInputAVFile, 
										GetActualPropertyBag(), 
										kValuePluginNameAVFileWAVUncomp );

	if (SUCCEEDED(res))
		res = m_pFactory->CreateInstance( IID_IHXTPropertyBag, (void **) &m_pAudioTrack );
	
	if (SUCCEEDED(res))
	{		
		m_pIFH->FormatAudioProperties(	m_pAudioTrack,
										GetActualPropertyBag(),
										0,	// track num
										HXT_MAKE_CHANNELMASK( GetNumChannels() ), 
										HXT_MAKE_SAMPLE_FORMAT( HXT_ENDIANNESS_LITTLE, GetBitsPerSample(), GetBitsPerSample()/ 8 ),
										GetSampleRate(),
										m_pAudioDuration);
	}
	m_pIFH->EndFormatInputInfo( );
	return res;
}


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// The following methods provide a default set of services that are less 
// likely to need changing, so you can probably ignore them, unless you 
// have multi stream inputs or extra property bag needs. 
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////
// Method:
//	GetOutputStreamCount (Probably Leave as is) 
// Purpose:
//	Gets the total number of output streams
STDMETHODIMP_(UINT32) CRSInWAVAgent::GetOutputStreamCount ()
{
	// for this plugin Only ever a single output - but some could be more
	// STEP 7 - Possibly change the number of outputs 
	return 1;
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	GetSupportedOutputFormat (Probably Leave as is) 
// Purpose:
//	Gets the supported output connection properties for a particular stream
STDMETHODIMP CRSInWAVAgent::GetSupportedOutputFormat ( UINT32 ulOutputStreamID, IHXTPropertyBag** ppSupportedFormats )
{
	if (!ppSupportedFormats)
	{
		return HXR_POINTER;
	}
	
	if (ulOutputStreamID != 0)
	{
		return HXR_INVALID_PARAMETER;
	}

	// addreffed every time its asked for
	// All inputs must be ASM packetized  -- 
	*ppSupportedFormats = m_pOutputFormat;
	(*ppSupportedFormats)->AddRef();
	return HXR_OK;		
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	SetNegotiatedOutputFormat (Probably Leave as is) 
// Purpose:
//	Notification of the output format for a particular stream
STDMETHODIMP CRSInWAVAgent::SetNegotiatedOutputFormat ( UINT32 ulOutputStreamID, IHXTPropertyBag* pOutputFormat )
{
	if ( ulOutputStreamID != 0 || pOutputFormat == NULL )	
	{
		return HXR_INVALID_PARAMETER;		
	}
	
	SetFormatReady( TRUE );
	m_pConnectedOutputFormat = pOutputFormat;	
	m_pConnectedOutputFormat->AddRef();
	return HXR_OK;		
}



/////////////////////////////////////////////////////////////////////////
// The following methods will most likely never need to be changed
// (except for changing class names) so you can leave them as is
/////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////
// Method:
//	SetFactory		(Leave as is) 
// Purpose:
//	intercepts filter's SetFactory call, passes factory to filter, initializes configuration
//  agent with factory.  Use m_pFactory for any object creation.
STDMETHODIMP CRSInWAVAgent::SetFactory( IHXCommonClassFactory* pFactory )
{
	if (!pFactory)
	{
		return HXR_POINTER;
	}

	HX_RESULT res = CRSInWAVFilter::SetFactory( pFactory );
	if (SUCCEEDED(res))
	{
		res = CHXTConfigurationAgentHelper::init( pFactory );
		if (SUCCEEDED(res))
			res = FillInPropertyBags();
	}	
	return res;
}	


/////////////////////////////////////////////////////////////////////////
// Method:
//	Prime
// Purpose:
//	Override to set property changes flag in config agent helper
STDMETHODIMP CRSInWAVAgent::Prime( UINT32 ulOutputStreamID )
{
	HX_RESULT res = CRSInWAVFilter::Prime( ulOutputStreamID );
	if (SUCCEEDED(res))
		setAllowPropertyChanges( FALSE );
	return res;
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	Teardown
// Purpose:
//	Override to set property changes flag in config agent helper
STDMETHODIMP CRSInWAVAgent::Teardown( UINT32 ulOutputStreamID )
{
	HX_RESULT res = CRSInWAVFilter::Teardown( ulOutputStreamID );
	setAllowPropertyChanges( TRUE );
	return res;
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	QueryInterface ( change class name below )
// Purpose:
//	QI for agent interfaces -- and a delegat to filter interfaces
STDMETHODIMP CRSInWAVAgent::QueryInterface(REFIID riid, void** ppvObj)
{
	if (IsEqualIID(riid, IID_IUnknown))
	{
		AddRef();
		*ppvObj = (IUnknown*) (IHXTConfigurationAgent*) this;
		return HXR_OK;
	}
	else if (IsEqualIID(riid, IID_IHXTPropertyBag))
	{
		AddRef();
		*ppvObj = (IHXTPropertyBag*) this;
		return HXR_OK;
	}
	else if (IsEqualIID(riid, IID_IHXTConnectionAgent))
	{
		AddRef();
		*ppvObj = (IHXTConnectionAgent*) this;
		return HXR_OK;
	}
	else if (IsEqualIID(riid, IID_IHXTConfigurationAgent))
	{
		AddRef();
		*ppvObj = (IHXTConfigurationAgent*) this;
		return HXR_OK;
	}

	//  STEP 8 - fill in appropriate filter class name
	else if ( CRSInWAVFilter::QueryInterface(riid, ppvObj ) == HXR_OK)
	{
		return HXR_OK;
	}
	*ppvObj = NULL;
	return HXR_NOINTERFACE;
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	AddRef  ( Leave as is ) 
// Purpose:
//	ref counting
STDMETHODIMP_(ULONG32) CRSInWAVAgent::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	Release ( Leave as is ) 
// Purpose:
//	ref counting
STDMETHODIMP_(ULONG32) CRSInWAVAgent::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }
    delete this;
    return 0;
}



