/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Copyright 1995-1997, Don Box
  
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
  
    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
    This file contains a datatype, INTERFACE_ENTRY that can be used to build
    tables that map IIDs onto vptrs. 

    The data structure INTERFACE_ENTRY should be considered opaque, and the
    the following preprocesor macros:

      BEGIN_INTERFACE_TABLE(tablename) - begins function GetInterfaceEntries
      INTERFACE_TABLE_ENTRY(piid, pfnFindItf, dwData) - generic entry
      IMPLEMENTS_INTERFACE(itf) - IID_itf -> (itf*)this;
      IMPLEMENTS_INTERFACE_AS(req, itf) - IID_req -> (itf*)this;
      IMPLEMENTS_INTERFACE_WITH_COMPOSITE(itf, innerclass, member) - IID_itf -> (itf*)&this->member;
      END_INTERFACE_TABLE() - terminates table/function definition

    where pfnFindItf can be any function with the following prototype:

      HRESULT STDAPICALLTYPE Find(void *pThis, DWORD dwData, REFIID, void **);
 
    This file contains the prototype for a routine that implements
    QueryInterface based on an interface table.

      InterfaceTableQueryInterface - finds and AddRef's vptr on an object
*/     

#ifndef _INTTABLE_H
#define _INTTABLE_H

#include "cscom/com.h"
#include "cscom/impunk.h"

typedef HRESULT (STDAPICALLTYPE *INTERFACE_FINDER)(void *pThis, unsigned long dwData, REFIID riid, void **ppv);
#define ENTRY_IS_OFFSET INTERFACE_FINDER(-1)

// basic table layout
typedef struct _INTERFACE_ENTRY
{
  const IID * pIID;			// the IID to match
  INTERFACE_FINDER pfnFinder;		// finder function
  long dwData;				// aux data for finder function
} INTERFACE_ENTRY;

// the routine that implements QueryInterface basd on the table
EXTERN_C HRESULT STDAPICALLTYPE InterfaceTableQueryInterface (void *pThis,
  const INTERFACE_ENTRY *pTable, REFIID riid, void **ppv);

#define BASE_OFFSET(ClassName, BaseName) \
  (DWORD(STATIC_CAST(BaseName*)(REINTERPRET_CAST(ClassName*)(0x10000000))) - 0x10000000)

#define COMPOSITE_OFFSET(ClassName, BaseName, MemberType, MemberName) \
    (DWORD(STATIC_CAST(BaseName*)(REINTERPRET_CAST(MemberType*)(0x10000000 + offsetof(ClassName, MemberName)))) - 0x10000000)

#define DECLARE_INTERFACE_TABLE(ClassName) \
/* typedef ClassName _InterfaceTableClassName; */ \
virtual const INTERFACE_ENTRY* GetInterfaceTable();

#define BEGIN_INTERFACE_TABLE(ClassName) \
const INTERFACE_ENTRY *ClassName::GetInterfaceTable () \
{ \
  typedef ClassName _InterfaceTableClassName; \
  CS_STATIC_TABLE INTERFACE_ENTRY InterfaceTable[] = \
  {
#define INTERFACE_TABLE_ENTRY(piid, pfn, dwData) \
    { piid, pfn, dwData },
#define IMPLEMENTS_INTERFACE(ItfName) \
    { &IID_##ItfName, ENTRY_IS_OFFSET,  BASE_OFFSET(_InterfaceTableClassName, ItfName) },
#define IMPLEMENTS_INTERFACE_AS(RequestedItfName, BaseClassName) \
    { &IID_##RequestedItfName, ENTRY_IS_OFFSET, BASE_OFFSET(_InterfaceTableClassName, BaseClassName)},
#define IMPLEMENTS_COMPOSITE_INTERFACE(Name) \
    { &IID_I##Name, ENTRY_IS_OFFSET , COMPOSITE_OFFSET(_InterfaceTableClassName, I##Name, I##Name, m_x##Name) },
#define IMPLEMENTS_COMPOSITE_INTERFACE_EX(Name, CompositeName) \
    { &IID_##Name, ENTRY_IS_OFFSET, COMPOSITE_OFFSET(_InterfaceTableClassName, Name, I##CompositeName, m_x##CompositeName) },
#define END_INTERFACE_TABLE() \
    { 0, 0, 0 } \
  }; \
  return InterfaceTable; \
}

// used for composition
#define DECLARE_COMPOSITE_INTERFACE(Name) \
  friend struct I##Name; \
  I##Name m_x##Name; 

// used for composition
#define DECLARE_COMPOSITE_INTERFACE_EMBEDDED(Name) \
  friend class X##Name; \
  X##Name m_x##Name;
    
#endif
