/*************************************************************************
Copyright © 1999-2002 Novell, Inc. All Rights Reserved. 

THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND 
TREATIES. USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE
AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS
THIS WORK. PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS
TO DEVELOPER A ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S
SAMPLE CODE IN ITS PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION
RIGHTS TO MARKET, DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT
OF DEVELOPER'S PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR
DEVELOPER'S CUSTOMERS WITH RESPECT TO THIS CODE.

***************************************************************************/
/*******************************************************************
* Name: define_interface.h
* Description: define macros for defining interfaces that work with
* both C and C++
* Tabs: 4
*******************************************************************/

#ifndef _DEFINE_INTERFACE_H_
#define	_DEFINE_INTERFACE_H_

/*******************************************************************
*	These macros are used to define an interface, conceptually similar
*	to a Java interface.
*
*	There are two parts to defining an interface: declaring the interface
*	name and defining the methods.
*
*	The INTERFACE(name) macro and END_INTERFACE(name) macros are used to declare the 
*	interface.
*
*	The METHOD(interface,name,return) and END_METHOD macros are used to
*	define a method. The METHOD_PARM1(parm) macro is used to define the first
*	parameter to a method, and the METHOD_PARM(parm) macro is used to define all
*	subsequent parameters to a method.
*
*	The following example will illustate how to define an interface:
*
*	INTERFACE(Document)
*		METHOD(Document,getStream,char *)
*			METHOD_PARM1(char * encoding)
*			METHOD_PARM(int bigEndian)
*		ENDMETHOD
*	END_INTERFACE(Document)
*
*	This will result, in C++, in the following class declaration:
*
*	class Document
*	{
*	public:
*		virtual char * METHOD_CALL getStream(char * encoding, int bigEndian) = 0;
*	};
*
*	In C, the following declaration results:
*
*	struct Document;
*	typedef struct
*	{
*		char * (METHOD_CALL * getStream)(struct Document * _this, char * encoding, int bigEndian);
*	} DocumentVTbl;
*	typedef struct Document
*	{
*		DocumentVTbl * vTbl;
*	} Document;
*
*	In C, you should also define a macro for calling the interface methods:
*	#define Document_getStream(_this,enc,end)\
*		(*_this->vTbl->getStream)(_this,enc,end)
*
*	To define an interface that inherits from another interface, use
*	the DERIVED_INTERFACE macro:
*	
*	DERIVED_INTERFACE(NewDocument,Document)
*		METHOD(NewDocument,getSubTree,char *)
*			METHOD_PARM1(char * elementName)
*		END_METHOD
*	END_INTERFACE(NewDocument)
*
*	In C++, this will result in:
*
*	class NewDocument
*		: public Document
*	{
*	public:
*		virtual char * METHOD_CALL getSubTree(char * elementName) = 0;
*	};
*
*	Note that a consequence of this is that an implementation class that
*	implements a derived interface in terms of an implementation class of
*	the base interface will need to implement methods for all declared interface
*	methods, both in the derived interface and the base interface.
*
*	In C, the above DERIVED_INTERFACE declaration will result in:
*
*	struct NewDocument;
*	typedef struct
*	{
*		DocumentVTbl _DocumentVTbl;
*		char * (METHOD_CALL * getSubTree)(NewDocument * _this, char * elementName);
*	} NewDocumentVTbl;
*	typedef struct NewDocument
*	{
*		NewDocumentVTbl * vTbl;
*	} NewDocument;
*
*	Once again, in C, you should define macros for calling the interface methods,
*	and note that you should defined macros also for calling the inherited methods.
*
*	#define NewDocument_getStream(_this,enc,end)\
*		(*((Document *)_this)->vTbl->getStream)(_this,enc,end)
*	#define NewDocument_getSubTree(_this,elName)\
*		(*_this->vTbl->getSubTree)(_this,elName)
*
*	IMPLEMENTATION:
*
*		To implement an interface in C++, simply derive a class from the 
*		interface name and supply implementations for the interface methods:
*
*		class DocumentImpl
*			: public Document
*		{
*		public:
*			DECLARE_IMPL(Document);
*			char * METHOD_CALL getStream(char * encoding, int bigEndian)
*			{return myStream;};
*
*			DocumentImpl(){myStream = strdup("Hello");};
*		private:
*			char * myStream;
*		}
*
*		To implement a derived interface in C++ in terms of an implementation class
*		of the base interface, you must derive the implementation class from both
*		the derived interface and the base implementation class.
*
*		class NewDocumentImpl
*			: public NewDocument, public DocumentImpl
*		{
*		public:
*			DECLARE_IMPL(Document);
*			DECLARE_IMPL(NewDocument);
*			char * METHOD_CALL getStream(char * encoding, int bigEndian)
*			{return DocumentImpl::getStream(encoding,bigEndian);};
*			char * METHOD_CALL getSubTree(char * elementName)
*			{...whatever...};
*
*			NewDocumentImpl(){};
*		}
*
*		To implement an interface in C, create implementations in C and
*		a function pointer table (the vTbl). The create the interface structure
*		and initialize the vTbl and any other private data you may have:
*
*		static char * METHOD_CALL getStreamImpl(char * encoding, int bigEndian);
*		typedef struct DocumentImpl
*		{
*			Document vTbl;
*			char * myStream;
*		} DocumentImpl;
*		DocumentVTbl vTbl = {getStreamImpl};
*		static char * METHOD_CALL getStreamImpl(Document * _this, char * encoding, int bigEndian)
*		{
*			return ((DocumentImpl *)_this)->myStream;
*		}
*		Document * getDocument()
*		{
*			DocumentImpl * doc = (DocumentImpl *)malloc(sizeof(DocumentImpl));
*			doc->vTbl.vTbl = &vTbl;
*			doc->myStream = strdup("Hello");
*			return (Document *)doc;
*		}
*
*		Implementing a derived interface in C simply requires filling in the function pointer
*		table appropriately (since you're not dealing with C++ multiple inheritance)
*
*
*********************************************************************/

//macro to allow namespace qualifier in both C/C++ defs
#if	defined(__cplusplus)
#define	NAMESPACE(ns) ns::
#else	//__cplusplus
#define	NAMESPACE(ns)
#endif	//__cplusplus

#if	defined(_MSC_VER)
//disable casting to incompatible types warning
//so C call macros with derived interfaces don't whine
#pragma warning(disable : 4133)
//disable some warnings about deriving a __declspec(dllexport) class
//from a non-dll export class
#pragma warning(disable : 4275)
#endif

#if defined(METHOD_CALL)
#undef METHOD_CALL
#endif
#if defined(WIN32) || defined(NETWARE) || defined(__NETWARE__)
#define METHOD_CALL __stdcall
#else
#define	METHOD_CALL
#endif

#if defined(INTERFACE)
#undef INTERFACE
#endif

#if defined(DERIVED_INTERFACE)
#undef DERIVED_INTERFACE
#endif

#if	defined(DEFINE_METHOD)
#undef DEFINE_METHOD
#endif

#if defined(END_INTERFACE)
#undef END_INTERFACE
#endif


#if defined(__cplusplus)
//////////////////////////////////////////////////////////////////////
// C++ macros definitions
//
// In C++ an interface is defined as a pure virtual class, i.e., only
// pure virtual functions and no data.
//////////////////////////////////////////////////////////////////////

//define an interface that isn't derived from another
#define INTERFACE(name)\
	class name\
	{\
	public:\
	virtual void * __stdcall get##name##Impl() = 0;

//define an interface that is derived from another
#define DERIVED_INTERFACE(name,baseName)\
	class name : public baseName\
	{\
	public:\
	virtual void * __stdcall get##name##Impl() = 0;


#define END_INTERFACE(name)\
	protected:\
	~name(){};\
	};

//define an interface method
#define METHOD(thisName,name,ret)\
	virtual ret __stdcall name(

#define	END_METHOD\
	 ) = 0;

#define METHOD_PARM1(parm)\
	parm
#define METHOD_PARM(parm)\
	,parm

#define INTERFACE_FWD_DECL(name)\
	class name

//macros to make repetitive task of declaring and defining
//the get implementation methods less painful:

#define DECLARE_IMPL(name)\
public:\
void * __stdcall get##name##Impl()

#define DEFINE_IMPL(impl,interface)\
void * __stdcall impl::get##interface##Impl() { return static_cast<impl *>(this); }

#define DEFINE_BASE_IMPL(impl,baseImpl,interface)\
void * __stdcall impl::get##interface##Impl() { return static_cast<baseImpl *>(this); }

//declare a get implementation method (use in class body)
#define DECLARE_GET_IMPL(name) void * __stdcall get##name##Impl()

//define a get implementation method (use in implementation file)
#define DEFINE_GET_IMPL(impl,result,name) void * __stdcall impl::get##name##Impl() { return static_cast<result *>(this); }


#else /* C */
//////////////////////////////////////////////////////////////////////
// C macros definitions
//
// In C an interface is as a function table. The actual interface is
// defined as a structure with a pointer to the function table. This
// mimics the C++ virtual table structure in Windows and Netware and
// allows C to call interfaces implemented in C++ and vice-versa.
//////////////////////////////////////////////////////////////////////

//define an interface that isn't derived from another
#define INTERFACE(name)\
	struct name;\
	typedef struct \
	{\
		void * (__stdcall * get##name##Impl)(struct name * _this);\

//define an interface that is derived from another
#define DERIVED_INTERFACE(name,baseName)\
	struct name;\
	typedef struct \
	{\
		baseName##VTbl	 _##baseName;\
		void * (__stdcall * get##name##Impl)(struct name * _this);\

#define END_INTERFACE(name)\
	} name##VTbl;\
	typedef struct name\
	{\
		name##VTbl	* vTbl;\
	} name;

//define an interface method
#define METHOD(thisName,name,ret)\
	ret (__stdcall * name)(struct thisName * _this
#define END_METHOD\
	);

#define METHOD_PARM1(parm)\
	, parm
#define METHOD_PARM(parm)\
	, parm


#define INTERFACE_FWD_DECL(name)\
	typedef struct name name


#endif /* if defined(__cplusplus) */

#endif /* #ifdef _DEFINE_INTERFACE_H_ */
