/****************************************************************************************

		BasicCOMImplementations.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		11/28/99	Nba			removed pure virtual Release in basicunknown, this corrupts the vtable in some cases
		8/10/99		cph			remove TBasicExtension (now part of TBasicDataExchanger)
		05/04/99	del			added CloneData() methods
		2/25/99		Alec		moved extension specific TBasicObjectFactory and 
									extension calls to BasicCOMExtImplementations
		1/9/99		tsh			remove MCF headers [unused]
		11/23/98	pbk			Separating ComSupport from MCFrame
    	11/23/98	Charles		modified STANDARD_RELEASE to have it work
		11/20/98	Nba			added Added STANDARD_RELEASE_BRANCH
		10/29/98	EricG		Made members of TBasicMouseAction and TBasicAction public
		10/1/98		Eml			Added IMCUnknown* pUnkOuter to Clone
		8/25/98		Eml			Added TBasicListPart
		6/18/98		Greg		Added SelfPrepareMenus to TBasicPart
		6/17/98		Eml			Split Basic3DCOMImplementations and BasicCOMImplementations
		6/17/98		Greg		Added SelfMenuAction to TBasicPart, TBasicModule
		5/8/98		Eml			Added Basic objects for Render Features
		5/4/98		Greg		Updated to new COM macros and added TBasicModule
								and TBasicPart

*****************************************************************************************/
#ifndef __BASICCOMIMPLEMENTATIONS__
#define __BASICCOMIMPLEMENTATIONS__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicTypes.h"
#include "MCBasicDefines.h"
#include "MCException.h"

#include "IExtension.h"
#include "IExRegisterer.h"

extern int32 gBasicComRefCount;


struct IShParameterComponent;


//Regular extensions don't need to define Init/CleanUpUtilities
//(implemented in COMUtilities.cpp that is included with every extension)
//Extensions or dlls using another memory allocator can only use the safe utilities (Init/CleanUpSafeUtilities)
//and should implement those as empty functions
void InitUtilities		(IMCUnknown* utilities);
void CleanUpUtilities	();


//******************************************************************

#if defined(_MAC) && (defined(_MSC_VER) || !defined(__cplusplus)) && !defined(qEmulateSingleObject)
#define qEmulateSingleObject
#endif

#if defined(qEmulateSingleObject)
//On the Mac it is very important to get the v-table in the following format
//		NULL
//		NULL  
//		&fn1
//		&fn2
//		&fn3
//		...
//which is the format agreed for SingleObject in Metrowerks and Apple CFront
//In case a compiler uses this format by default, just don't do anything.
//In case a compiler doesn't add a NULL entry, define EMULATE_SINGLEOBJECT.
//In case a compiler as entry larger than 4 bytes, it WON'T work.

#ifndef SINGLEOBJECT
struct SingleObject : public TMCObject
{
    virtual int32 PADMETHOD1() {return 0;}
    virtual int32 PADMETHOD2() {return 0;}
};
#define SINGLEOBJECT SingleObject
#endif
class TBasicUnknown: public SingleObject,
					 public IMCUnknown
{
#else
class TBasicUnknown : public TMCObject, public IMCUnknown
{
#endif
	public:
		TBasicUnknown();
		~TBasicUnknown();

 		virtual MCCOMErr MCCOMAPI QueryInterface	(const MCIID& riid, void** ppvObj);
 		virtual uint32	 MCCOMAPI AddRef 			();
 			// We cannot make the destructor virtual, so everyone has to implement
 			// Release(): use STANDARD_RELEASE(), below

		void SetControllingUnknown(IMCUnknown* controllingUnknown);

	protected:
		// This copy method should be used by deriving classes. 
		// Never make it virtual. It must remain protected.
		// If you're adding a field, remember to reflect the change in the copy.
		void CloneData(TBasicUnknown *destUnknown, IMCUnknown *pUnkOuter);

		uint32		fRefCount;
		IMCUnknown*	fControllingUnknown;
};


inline uint32 TBasicUnknown::AddRef()
{
	if (fControllingUnknown)
	{
		return fControllingUnknown->AddRef();
	}
	else
	{
		fRefCount++;
		return fRefCount;
	}
}

//
/// Place this macro in your class declaration to get a standard
/// implementation of release that handles aggregation
//
#define STANDARD_RELEASE \
virtual uint32 MCCOMAPI Release() { \
	if (fControllingUnknown)\
	{\
		uint32 releaseResult = fControllingUnknown->Release();\
		if (releaseResult == -1)\
		{\
			delete this;\
		}\
		return releaseResult;\
	}\
	else \
	{\
		fRefCount--; \
		uint32 res = fRefCount; \
		if (fRefCount == 0) \
		{ \
			delete this; \
		} \
		else if (int32(fRefCount) < 0) \
		{ \
			throw TMCException(-2); \
		} \
		return res; \
	}\
}

#define STANDARD_RELEASE_BRANCH(X) \
virtual uint32 MCCOMAPI Release() { \
	if (X::fControllingUnknown)\
	{\
		uint32 releaseResult = X::fControllingUnknown->Release();\
		if (releaseResult == -1)\
		{\
			delete this;\
		}\
		return releaseResult;\
	}\
	else \
	{\
		X::fRefCount--; \
		uint32 res = X::fRefCount; \
		if (X::fRefCount == 0) \
		{ \
			delete this; \
		} \
		else if (int32(X::fRefCount) < 0) \
		{ \
			throw TMCException(-2, 0); \
		} \
		return res; \
	}\
}

#define QUERY_INTERFACE(X, iid, obj) \
	if (MCIsEqualIID(iid, IID_##X)) \
	{ \
		TMCCountedGetHelper<X> result(obj); \
		result = this; \
		return MC_S_OK; \
	}

#define QUERY_CLASS(X, iid, obj) \
	if (MCIsEqualIID(iid, X::sClassId)) \
	{ \
		TMCCountedGetHelper<X> result(obj); \
		result = this; \
		return MC_S_OK; \
	}
	

//******************************************************************

/// \addtogroup BaseClass
/// \{

/// Basic implementation of a Data Exchanger.  Provides a default implementation of 
/// functions of an IExDataExchanger.
/// \see IExDataExchanger
class TBasicDataExchanger : public TBasicUnknown, public IExDataExchanger
{
public:
	virtual MCCOMErr 			MCCOMAPI QueryInterface			(const MCIID &riid, void** ppvObj);
	virtual uint32				MCCOMAPI AddRef					()							{ return TBasicUnknown::AddRef(); }
	
	virtual void				MCCOMAPI Clone					(IExDataExchanger** clonedObject,IMCUnknown* pUnkOuter);
	virtual boolean				MCCOMAPI IsEqual				(IExDataExchanger * otherDataExchanger);
	virtual MCCOMErr			MCCOMAPI GetParameter			(IDType keyword, void *parameter);
	virtual MCCOMErr			MCCOMAPI SetParameter			(IDType keyword, void *parameter);
	///You MUST implement this method if you have a pmap (the default returns NULL).
	virtual void*				MCCOMAPI GetExtensionDataBuffer	();
	virtual MCCOMErr 			MCCOMAPI ExtensionDataChanged	();
	virtual MCCOMErr 			MCCOMAPI HandleEvent			(MessageID message, IMFResponder* source, void* data);
	virtual MCCOMErr			MCCOMAPI SimpleHandleEvent		(MessageID message, IMFResponder* source, void* data);
	virtual void				MCCOMAPI GetUIHandler			(TUIHandlerFunctionPtr& outHandler);
	virtual int16 				MCCOMAPI GetResID				();
	//Implement both the following functions to be able to override the MiniPartID
	virtual int16				MCCOMAPI GetMiniPartID			();
	virtual MCCOMErr			MCCOMAPI OverridesMiniPartID	();
	//
	virtual MCCOMErr			MCCOMAPI InitComponent			()							{ return kNotImplementedError; }
	virtual MCCOMErr			MCCOMAPI CopyComponentExtraData (IExDataExchanger* dest)	{ return kNotImplementedError; }
	
protected:
	
	/// This copy method should be used by deriving classes. Never made it virtual. 
	/// It must remain protected.
	/// If you're adding some fields, remember to reflect the change in the copy.
	void	CloneData(TBasicDataExchanger *destExchanger, IMCUnknown* pUnkOuter);
	
public:
	// -Description:
	//		returns the component (if any) that stores this component's preferences
	// -Returns:
	//		null if this component has no prefs
	IShParameterComponent*	GetMyPrefsComponent ();
};


//******************************************************************

/// Basic implementation of a Registerer.  Provides a default implementation of an IExRegisterer.
/// \see IExRegisterer
class TBasicRegisterer : public TBasicUnknown, public IExRegisterer 
{
public:
	virtual MCCOMErr MCCOMAPI QueryInterface(const MCIID &riid, void** ppvObj);
	virtual uint32	 MCCOMAPI AddRef		()					{ return TBasicUnknown::AddRef(); }

	virtual uint32   MCCOMAPI GetComponentCount();
	virtual MCCOMErr MCCOMAPI GetComponentData(
								uint32 index,
								APICOMPData &	compData, 
								TMCResource*&	privateData,
								APIGUIDData &	guidData);
	virtual MCCOMErr MCCOMAPI UnregisterComponents();
};

/// \}

#endif

