/* ***** 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 "ihxtconstants.h"			
#include "ihxtaudioformat.h"

// transform includes
#include "PrefilterExampleTransform.h"	

// filter includes
#include "PrefilterExampleFilter.h"		

// agent includes
#include "ihxtconfigagenthelper.h"	
#include "PrefilterExampleAgent.h"		

// plugin includes
#include "rtaprefilterexampleplugin.h"		

// local includes
#include "assert.h"		



/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSPrefilterExampleAgent  ( Probably leave as is )
// Purpose:
//	Constructor
//
//	STEP 1 - Change class name in all methods to reflect your plugin agent's class name 
//
CRSPrefilterExampleAgent::CRSPrefilterExampleAgent( ) 
	: m_pOutputFormat( NULL )
	, m_pInputFormat( NULL )
	, m_pConnectedOutputFormat( NULL )
	, m_pConnectedInputFormat( NULL )
	, m_bEnabled( FALSE )
	, m_lRefCount( 0 )
{
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	~CRSPrefilterExampleAgent  ( Probably leave as is )
// Purpose:
//	Destructor
CRSPrefilterExampleAgent::~CRSPrefilterExampleAgent( )
{
	HX_RELEASE( m_pInputFormat );
	HX_RELEASE( m_pOutputFormat );
	HX_RELEASE( m_pConnectedInputFormat );
	HX_RELEASE( m_pConnectedOutputFormat );
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSPrefilterExampleAgent::MakePropertyBags
// Purpose:
//	helper for onetime creation of property bags -- gets factory from filter
HX_RESULT CRSPrefilterExampleAgent::FillInPropertyBags()
{
	HX_RESULT res = HXR_OK;
	
	if (SUCCEEDED(res))
	{
		//	STEP 2 - Fill in read only properties in actual property bag
		GetActualPropertyBag()->SetUint( kPropIsRealTime, FALSE );
		GetActualPropertyBag()->SetUint( kPropIsRepeatable, TRUE );

		// STEP 3 - Fill in the name and type of this prefilter (from rtaprefilterexampleplugin.h )
		GetActualPropertyBag()->SetString( kPropPluginName, kValuePluginNamePrefilterExample );
		GetActualPropertyBag()->SetString( kPropEncodingType, kValuePluginTypePrefilterExample );
	}

	//	STEP 4 - Create InputFormat bag appropriate to plugin's supported media formats
	if (SUCCEEDED(res) && m_pInputFormat == NULL )
		res = m_pFactory->CreateInstance( IID_IHXTPropertyBag, (void **) &m_pInputFormat );

	if (SUCCEEDED(res))
		res = m_pInputFormat->SetString( kPropMediaFormat, kValueMediaFormatUncompVideo );

	if ( SUCCEEDED( res ) )
		res = m_pInputFormat->SetUint( kPropVideoColorFormat, HXT_VIDEO_FORMAT_I420 );	

	if ( SUCCEEDED( res ) )
		res = PrepareRange( 32, 2048, 4, kPropVideoFrameWidth ); 

	if ( SUCCEEDED( res ) )
		res = PrepareRange( 32, 2048, 4, kPropVideoFrameHeight ); 

	if ( SUCCEEDED( res ) )
		res = PrepareDoubleRange( 0, 60, kPropVideoFrameRate ); 


	if (SUCCEEDED(res) && m_pOutputFormat == NULL )
		res = m_pFactory->CreateInstance( IID_IHXTPropertyBag, (void **) &m_pOutputFormat );

	if (SUCCEEDED(res))
		m_pOutputFormat->SetString( kPropMediaFormat, kValueMediaFormatUncompVideo );

	return res;
}


//
//	STEP 5 - override any of the OnSetXXX for any values this agent 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:
//	OnSetBool	(change to recognize supported properties) 
// Purpose:
//	example of an "enabled" plugin property
STDMETHODIMP CRSPrefilterExampleAgent::OnSetBool( const char* szName, BOOL bValue )
{
	if ( strcmp ( szName, kPropIsEnabled ) == 0 )
	{
		m_bEnabled = bValue;
	}
	else
	{
		if( m_pLogWriter )
			m_pLogWriter->LogMessage( kRealNetworks, LC_APP_ERROR, VIDPREFIL, NO_TRANSLATE, 
									  "Unrecognized BOOL parameter passed to rn-prefilter-example." );
		
		return HXR_FAIL;
	}
	return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	OnSetString
// Purpose:
//	Handle string-based configuration properties.  
// NOTE:
//	Returning a success code means that the value will be added to the property bag.
//  Set properties on any accepted strings by checking for accepted property name
//  Other required operations may occur at this point 
STDMETHODIMP CRSPrefilterExampleAgent::OnSetString( const CHAR* szName, const CHAR* szValue )
{
	if (!szName || !szValue)
	{
		assert( FALSE );
		return HXR_POINTER;
	}

	HX_RESULT res;
	if ( strcmp( kPropPluginType, szName ) == 0 )
	{
		res = HXR_OK;
	}
	else
	{
		assert( FALSE );
		if( m_pLogWriter )
			m_pLogWriter->LogMessage( kRealNetworks, LC_APP_ERROR, VIDPREFIL, NO_TRANSLATE, 
									  "Unrecognized string parameter passed to rn-prefilter-example." );
		
		res = HXR_INVALID_PARAMETER;
	}
	return res;
}



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


/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSPrefilterExampleAgent::GetInputCount  (Probably Leave as is) 
// Purpose:
//	Gets the total number of input streams
// NOTE for this plugin Only ever a single input - but some could be more
// STEP 6 - Possibly change the number of inputs
STDMETHODIMP_(UINT32) CRSPrefilterExampleAgent::GetInputStreamCount ()
{
	return 1;
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSPrefilterExampleAgent::GetSupportedInputProperties  (Probably Leave as is) 
// Purpose:
//	Gets the supported input connection properties for a particular stream
STDMETHODIMP CRSPrefilterExampleAgent::GetSupportedInputFormat ( UINT32 ulInputStreamID, IHXTPropertyBag** ppSupportedFormats )
{
	if (!ppSupportedFormats)
	{
		return HXR_POINTER;
	}

	if (ulInputStreamID >= 1)
	{
		return HXR_INVALID_PARAMETER;
	}
	if (ulInputStreamID == 0)
	{
		*ppSupportedFormats = m_pInputFormat;
		(*ppSupportedFormats)->AddRef();
	}
	return HXR_OK;		
}

/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSPrefilterExampleAgent::SetNegotiatedInputFormat  (Probably Leave as is) 
// Purpose:
//	Notification of the input format for a particular stream
STDMETHODIMP CRSPrefilterExampleAgent::SetNegotiatedInputFormat ( UINT32 ulStreamID, IHXTPropertyBag* pConnectedFormat )
{
	m_pOutputFormat = pConnectedFormat;
	m_pOutputFormat->AddRef();
	return HXR_OK;		
}


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

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

	// addreffed every time its asked for
	*ppSupportedFormats = m_pOutputFormat;
	(*ppSupportedFormats)->AddRef();
	return HXR_OK;		
}


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


/////////////////////////////////////////////////////////////////////////
// Method:
//	CRSPrefilterExampleAgent::QueryInterface  ( change class name below )
// Purpose:
//	QI for agent interfaces -- and delegate to filter interfaces
STDMETHODIMP CRSPrefilterExampleAgent::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 - change the class name in the line below to match your plugin's filter class name
	else if (CRSPrefilterExampleFilter::QueryInterface(riid, ppvObj) == HXR_OK)
	{
		return HXR_OK;
	}
	*ppvObj = NULL;
	return HXR_NOINTERFACE;
}


/////////////////////////////////////////////////////////////////////////
// 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 CRSPrefilterExampleAgent::SetFactory( IHXCommonClassFactory* pFactory )
{
	if (!pFactory)
	{
		return HXR_POINTER;
	}
	
	// STEP 9 - change the class name in the line below to match your plugin's filter class name
	HX_RESULT res = CRSPrefilterExampleFilter::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 CRSPrefilterExampleAgent::Prime( UINT32 ulOutputStreamID )
{
	HX_RESULT res = CRSPrefilterExampleFilter::Prime( ulOutputStreamID );
	if (SUCCEEDED(res))
		setAllowPropertyChanges( FALSE );
	return res;
}

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


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

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

/////////////////////////////////////////////////////////////////////////
// Method:
//	PrepareList	(Leave as is) 
// Purpose:
//	Helper function -- Handle uint32 list creation and assignment
HX_RESULT CRSPrefilterExampleAgent::PrepareList( UINT32 arr[], INT32 nCnt, const char *kProp )
{
	IHXTUintList*	pList = NULL;
	HX_RESULT res  = m_pFactory->CreateInstance( IID_IHXTUintList, (void **) &pList );
	if (FAILED(res))
		return res;

	INT32 ii=0;
	for (ii=0; ii < nCnt; ii++ )
	{
		pList->PushBack(arr[ii]);
	}
	res = m_pInputFormat->SetUintList( kProp, pList );
	HX_RELEASE( pList );
	return res;
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	PrepareRange (Leave as is) 
// Purpose:
//	Helper function -- Handle uint32 range creation and assignment
HX_RESULT CRSPrefilterExampleAgent::PrepareRange( UINT32 uBeg, UINT32 uEnd, UINT32 uStep, const char *kProp )
{
	IHXTUintRange*	pRange = NULL;
	HX_RESULT res  = m_pFactory->CreateInstance( IID_IHXTUintRange, (void **) &pRange );

	if (SUCCEEDED(res))
		res = pRange->Set( uBeg, uEnd, uStep );

	if (SUCCEEDED(res))
		res = m_pInputFormat->SetUintRange( kProp, pRange );

	HX_RELEASE( pRange );
	return res;
}


/////////////////////////////////////////////////////////////////////////
// Method:
//	PrepareRange (Leave as is) 
// Purpose:
//	Helper function -- Handle uint32 range creation and assignment
HX_RESULT CRSPrefilterExampleAgent::PrepareDoubleRange( double dBeg, double dEnd, const char *kProp )
{
	IHXTDoubleRange*	pRange = NULL;
	HX_RESULT res  = m_pFactory->CreateInstance( IID_IHXTDoubleRange, (void **) &pRange );

	if (SUCCEEDED(res))
		res = pRange->Set( dBeg, dEnd, 0, 0 );

	if (SUCCEEDED(res))
		res = m_pInputFormat->SetDoubleRange( kProp, pRange );
	
	HX_RELEASE( pRange );
	return res;
}



