
/*
  File: include/mia/mgeneric.h
  Description: MIA reference counting definitions
  Part of the Mantis project
  (c) 2002 Lycos Inc.

  This file is distributed for the sole purpose of allowing you to write
  software to interface with Sonique 2 and other Mantis programs. It is
  not to be modified or used for any other purpose without written
  authorization.

  If you redistribute this file, it must be in the original package
  complete with all other files provided, including the usage agreement.

  Do not remove this notice.
*/

#ifndef _MGENERIC_H_
#define _MGENERIC_H_

#ifdef DEBUG_INCLUDE_ORDER
#pragma message("Including " __FILE__ "\n" )
#endif

#if _MSC_VER > 1000
#pragma once
#endif


//#include <memory.h>
#include <stdlib.h>

#include "thread.h"
#ifndef COMPILE_WITHOUT_MIA 
#include "MID.h"
#endif

#if defined(_DEBUG) && defined(_DEBUG_REFCOUNT)
#include "Interface_Debug.h"
#endif

#ifndef COMPILE_WITHOUT_MIA
DEFINE_MID(MID_MGENERIC, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);

#endif


typedef long						MRESULT;

#define M_OK						0

#ifndef SUCCEEDED
#define SUCCEEDED(x) ((x)>=0)
#endif//SUCCEEDED
#ifndef FAILED
#define FAILED(x) ((x)<0)
#endif//FAILED



class MReferenceCounter
{
public:
	virtual unsigned long __stdcall AddRef()															= 0; // Add reference // returns reference count
	virtual unsigned long __stdcall Release()															= 0; // Sub reference // returns reference count
};

class MGeneric
{
public:
#ifndef COMPILE_WITHOUT_MIA
	virtual MRESULT __stdcall QueryModule(const MID &iid, void **ppv, bool bAddReference = true, const MGeneric* pPrev = NULL )	= 0; // Query for a particular interface
#endif
	virtual unsigned long __stdcall AddRef()																= 0; // Add reference // returns reference count
	virtual unsigned long __stdcall Release()																= 0; // Sub reference // returns reference count
};

class MGeneric; 
class MInnerGeneric : public MGeneric
{
public:
#ifndef COMPILE_WITHOUT_MIA
	virtual MGeneric* __stdcall InnerCast(const MID &iid)	= 0; // Query for a particular interface
#endif
	virtual unsigned long __stdcall InnerAddRef()																= 0; // Add reference // returns reference count
	virtual unsigned long __stdcall InnerRelease()																= 0; // Sub reference // returns reference count
};


class MObject : public MGeneric
{ 
public:
	virtual MRESULT __stdcall AddObject(	MInnerGeneric* pObj )	= 0; // Sub reference // returns reference count
	virtual MRESULT __stdcall AddObject(	const MID& mIFactory, const MID& mInterface )	= 0;
};

#ifndef COMPILE_WITHOUT_MIA
#define IMPLEMENT_QUERYMODULE()\
public:\
virtual MRESULT __stdcall QueryModule(const MID& /*mid*/, void** /*ppv*/,  bool /*bAddReference*/, const MGeneric* /*pPrev*/) { return GetBasicError(ERR_BASIC_UNKNOWNOBJECT); }
#define IMPLEMENT_QUERYMODULE1(whichmid,type)\
public:\
virtual MRESULT __stdcall QueryModule(const MID& mid, void** ppv, bool bAddReference, const MGeneric* /*pPrev*/) { if( mid == whichmid ) { *ppv = (type*)this; if( bAddReference ) AddRef(); return M_OK; } return GetBasicError(ERR_BASIC_UNKNOWNOBJECT); }
#else
#define IMPLEMENT_QUERYMODULE()
#endif

#define __STRINGIZER__(x) #x

#define __SILLY_STEP__(x) __STRINGIZER__(x)

#define  MGENERIC_CONSTRUCTOR()\
{\
	m_RefCount = 0;\
}
#define  MGENERIC_CONSTRUCTOR_REF1()\
{\
	m_RefCount = 1;\
}



#if defined(_DEBUG) && defined(_DEBUG_REFCOUNT)
#define IncrementRefCount(o,x) (RefCountDebugPtr->LogAddRef(/*(MGeneric*)*/o,(long*)&(x)))
#define DecrementRefCount(o,x) (RefCountDebugPtr->LogSubRef(/*(MGeneric*)*/o,(long*)&(x)))
#define IncrementInnerRefCount(o,x) (RefCountDebugPtr->LogAddRef(/*(MInnerGeneric*)*/o,(long*)&(x)))
#define DecrementInnerRefCount(o,x) (RefCountDebugPtr->LogSubRef(/*(MInnerGeneric*)*/o,(long*)&(x)))
#else	
#define IncrementRefCount(o,x) (AtomicIncrement((long*)&(x)))
#define DecrementRefCount(o,x) (AtomicDecrement((long*)&(x)))
#define IncrementInnerRefCount(o,x) IncrementRefCount(o,x)
#define DecrementInnerRefCount(o,x) DecrementRefCount(o,x)
#endif


#define IMPLEMENT_REFERENCECOUNT()\
public:\
	virtual unsigned long __stdcall AddRef()	{ ASSERT(*((int *)this) != 0xdddddddd); return IncrementRefCount(this, m_RefCount); }\
	virtual unsigned long __stdcall Release()	{ ASSERT(*((int *)this) != 0xdddddddd); int32 ret = DecrementRefCount(this, m_RefCount); ASSERT( ret >= 0 ); if( !ret ) delete this; return ret; }\
protected:\
	long m_RefCount;

#define IMPLEMENT_REFERENCECOUNT1(x)\
public:\
	virtual unsigned long __stdcall AddRef()	{ ASSERT(*((int *)this) != 0xdddddddd); return IncrementRefCount(( x *)this, m_RefCount); }\
	virtual unsigned long __stdcall Release()	{ ASSERT(*((int *)this) != 0xdddddddd); int32 ret = DecrementRefCount(( x *)this, m_RefCount); ASSERT( ret >= 0 ); if( !ret ) delete this; return ret; }\
protected:\
	long m_RefCount;


#define IMPLEMENT_EMPTY_REFERENCECOUNT()\
public:\
	virtual unsigned long __stdcall AddRef()	{ return 1; }\
	virtual unsigned long __stdcall Release()	{ return 1; }


#define IMPLEMENT_NULL_REFERENCECOUNT()\
public:\
	virtual unsigned long __stdcall AddRef()	{ return IncrementRefCount(this, m_RefCount); }\
	virtual unsigned long __stdcall Release()	{ unsigned long ret = DecrementRefCount(this, m_RefCount); /*if( !ret ) delete this;*/ return ret; }\
protected:\
	long m_RefCount;

#define IMPLEMENT_NULL_REFERENCECOUNT1(x)\
public:\
	virtual unsigned long __stdcall AddRef()	{ return IncrementRefCount(( x *) this, m_RefCount); }\
	virtual unsigned long __stdcall Release()	{ unsigned long ret = DecrementRefCount(( x *)this, m_RefCount); /*if( !ret ) delete this;*/ return ret; }\
protected:\
	long m_RefCount;



#define IMPLEMENT_INNERREFERENCECOUNT()\
public:\
	virtual unsigned long __stdcall InnerAddRef()	{ return IncrementInnerRefCount(this, m_RefCount); }\
	virtual unsigned long __stdcall InnerRelease()	{ int32 ret = DecrementInnerRefCount(this, m_RefCount); ASSERT( ret >= 0 ); if( !ret ) delete this; return ret; }\
protected:\
	long m_RefCount;

#define IMPLEMENT_INNERREFERENCECOUNT_HEIR(x)\
public:\
	virtual unsigned long __stdcall InnerAddRef()	{ return IncrementInnerRefCount(( x *)this, m_RefCount); }\
	virtual unsigned long __stdcall InnerRelease()	{ int32 ret = DecrementInnerRefCount(( x *)this, m_RefCount); ASSERT( ret >= 0 ); if( !ret ) delete this; return ret; }


#define IMPLEMENT_EMPTY_INNERREFERENCECOUNT()\
public:\
	virtual unsigned long __stdcall InnerAddRef()	{ return 1; }\
	virtual unsigned long __stdcall InnerRelease()	{ return 1; }



#define IMPLEMENT_NULL_INNERREFERENCECOUNT()\
public:\
	virtual unsigned long __stdcall InnerAddRef()	{ return IncrementInnerRefCount(this, m_RefCount); }\
	virtual unsigned long __stdcall InnerRelease()	{ unsigned long ret = DecrementInnerRefCount(this, m_RefCount); /*if( !ret ) delete this;*/ return ret; }\
protected:\
	long m_RefCount;



#define IMPLEMENT_OUTERMGENERIC(x)\
public:\
virtual MRESULT __stdcall QueryModule(const MID &iid, void **ppv, bool bAddReference = true, const MGeneric* pPrev = NULL) {ASSERT(!x || (x && (*((int *)x) != 0xdddddddd))); if( x ) return x ->QueryModule(iid, ppv, bAddReference, pPrev); else { MGeneric* p = InnerCast(iid); if( p == NULL ) return GetBasicError(ERR_BASIC_UNKNOWNOBJECT); *ppv = p; if( bAddReference ) AddRef(); return M_OK; } }\
virtual unsigned long __stdcall AddRef()  { if( x ) return x ->AddRef(); else return InnerAddRef(); }\
virtual unsigned long __stdcall Release() { if( x ) return x ->Release(); else return InnerRelease(); }


#define INNER_IMP() \
protected: \
	mutable MObject* m_pOuter;\
	IMPLEMENT_OUTERMGENERIC(m_pOuter)\
	IMPLEMENT_INNERREFERENCECOUNT()


// these must be in any class that inherits from a class that has the INNER_IMP macro (MItem!!)

#define INNER_IMP_HEIR(x)\
	IMPLEMENT_OUTERMGENERIC( m_pOuter )\
	IMPLEMENT_INNERREFERENCECOUNT_HEIR( x )
	


#define DEFFUNC_GETIMP(classtype,classid)\
	public:\
	__inline classtype* GetImpParent() const\
	{\
		classtype* pReturn = NULL;\
		ASSERT( m_pOuter );\
		VERIFY( SUCCEEDED( m_pOuter->QueryModule( classid, (void**)&pReturn, false, this ) ) );\
		ASSERT( pReturn );\
		return pReturn;\
	}\
	__inline classtype* GetImpLastHeir() const\
	{\
		classtype* pReturn = NULL;\
		ASSERT( m_pOuter );\
		VERIFY( SUCCEEDED( m_pOuter->QueryModule( classid, (void**)&pReturn, false ) ) );\
		ASSERT( pReturn );\
		return pReturn;\
	}

#define DEFFUNC_INNERCAST_SINGLE(classtype,classid)\
virtual MGeneric* __stdcall InnerCast(const MID &iid )\
{\
	if( iid == classid )\
		return (classtype*)this;\
	return NULL;\
}

#define DEFFUNC_INNERCAST(classtype,classid,parentclass)\
	virtual MGeneric* __stdcall InnerCast(const MID &iid )\
	{\
		if( iid == classid )\
			return (classtype*)this;\
		return parentclass::InnerCast(iid);\
	}
#define DEFFUNC_INNERCAST_START(classtype,classid)\
	virtual MGeneric* __stdcall InnerCast(const MID &iid )\
	{\
		if( iid == classid )\
			return (classtype*)this;
#define DEFFUNC_INNERCAST_NTH(classtype,classid)\
		else if( iid == classid )\
			return (classtype*)this;
#define DEFFUNC_INNERCAST_END(classtype,classid,parentclass)\
		else if( iid == classid )\
			return (classtype*)this;\
		return parentclass::InnerCast(iid);\
	}

#define DEFFUNC_INNERCAST_END_NULL(classtype,classid)\
		else if( iid == classid )\
			return (classtype*)this;\
		return NULL;\
	}



#ifdef DEBUG_INCLUDE_ORDER
#pragma message("Done including " __FILE__ "\n" )
#endif

#endif

