/***************************************************************************
 *                          Zanoza Modeler v2.x                            *
 *      This is unpublished propietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                   Copyright (c) 2002 Zanoza Software.                   *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler's base interface file: ZUnknown
 *--------------------------------------------------------------------------
 * @histroy: 23.09.2002. Created
 */
#ifndef zinterface_h_included
#define zinterface_h_included


#define SAFEPOINTER  64
#define zmoffsetofclass(base, derived) ((DWORD)(static_cast<base*>((derived*)SAFEPOINTER))-SAFEPOINTER)


class ZUnknown;
struct tInterfaceMap
{
  DWORD                 m_dwOffset;
  DWORD                 m_dwFlags;
  const char*           m_UID;
  BYTE*                 m_pReserved;
};

#ifdef _DEBUG
# define IID_(x)         (const char*)((long)#x + 0*(zmoffsetofclass(x, x)))
#else
# define IID_(x)         #x
#endif
/*------------------------------------------------------------------------
 * INTERFACE_ entries:
 *
 * @purpose: Macros for defining interface map and common functions.
 * @author: Oleg Melashenko
 *-----------------------------------------------------------------------*/
/*------------------------------------------------------------------------
 * INTERFACE_DECLARE_EMBEDMAP
 * If you get a 'FinalConstruct undefined' error, then you need to add
 * void FinalConstruct() function and instantate there all embedded objects.
 *-----------------------------------------------------------------------*/
#define INTERFACE_DECLARE_EMBEDMAP(_class)                                    \
  INTERFACE_MAPHEADER(_class)                                                 \
  INTERFACE_FUNCTIONS()                                                       \
  INTERFACE_EMBED_INSTANCE_CREATOR()                                          \

#define INTERFACE_DECLAREMAP(_class)                                          \
  INTERFACE_MAPHEADER(_class)                                                 \
  INTERFACE_FUNCTIONS()                                                       \
  INTERFACE_INSTANCE_CREATOR()                                                \

/*------------------------------------------------------------------------
 * INTERFACE_DECLAREMAP_INLINE
 * Allows declare interfacemap and supported interface entries inline in
 * class declaration (right in .h file)
 *-----------------------------------------------------------------------*/
#define INTERFACE_DECLAREMAP_INLINE(_class)                                   \
  typedef _class _ThisClass;                                                  \
  INTERFACE_FUNCTIONS()                                                       \
  INTERFACE_INSTANCE_CREATOR()                                                \
  ZStdPtr<ZUnknown> m_pOuter;                                                 \
  DWORD   m_cRefs;                                                            \
  const static tInterfaceMap* _GetEntries() {                                 \
    static const tInterfaceMap _InterfaceEntries[] = {

#define INTERFACE_MAPHEADER(_class)                                           \
  ZStdPtr<ZUnknown> m_pOuter;                                                 \
  DWORD   m_cRefs;                                                            \
  typedef _class _ThisClass;                                                  \
  static const tInterfaceMap _InterfaceEntries[];                             \
  const static tInterfaceMap* _GetEntries() { return _InterfaceEntries; }

#define INTERFACE_BEGINMAP(_class)                                            \
  const tInterfaceMap _class::_InterfaceEntries[] = {
/* end of INTERFACE_BEGINMAP*/

#define ZM_DELIGATED        0x00000001
#define ZM_EMBEDDED         0x00000002
#define ZM_ZUNKNOWN         0x00000008
#define ZM_CHAIN            0x00000010

#define ZM_LAST             0x80000000

#define INTERFACE_ENTRY(_class) \
  { zmoffsetofclass(_class, _ThisClass), 0, IID_(_class), NULL},
#define INTERFACE_CONTROLLING_UNKNOWN(_class) \
  { zmoffsetofclass(_class, _ThisClass), ZM_ZUNKNOWN, IID_(_class), NULL},
#define INTERFACE_RELATIVE_ENTRY(_class, _throughclass) \
  { (DWORD)((_class*)(_throughclass*)((_ThisClass*)SAFEPOINTER))-SAFEPOINTER, 0, IID_(_class)},
#define INTERFACE_DELIGATE( _class, _pUnknown) \
  { 0, ZM_DELIGATED, IID_(_class), (BYTE*)&_pUnknown},
#define INTERFACE_DELIGATE_CHAIN(_pUnknown) \
  { offsetof(_ThisClass, _pUnknown), ZM_DELIGATED | ZM_CHAIN, NULL, NULL},
#define INTERFACE_EMBED( _class, _pUnknown) \
  { offsetof(_ThisClass, _pUnknown), ZM_EMBEDDED, IID_(_class)},
#define INTERFACE_CHAIN(_class) \
  { zmoffsetofclass(_class, _ThisClass) + _class::_GetEntries()[0].m_dwOffset, ZM_CHAIN | (_class::_GetEntries()[0].m_dwFlags & ZM_ZUNKNOWN), (char*)zmoffsetofclass(_class, _ThisClass), (BYTE*)_class::_GetEntries()},
#define INTERFACE_EMBEDDED_CHAIN(_class, _pUnknown) \
  { offsetof(_ThisClass, _pUnknown) + _class::_GetEntries()[0].m_dwOffset, ZM_EMBEDDED | ZM_CHAIN | (_class::_GetEntries()[0].m_dwFlags & ZM_ZUNKNOWN), (char*)offsetof(_ThisClass, _pUnknown), (BYTE*)_class::_GetEntries()},
#define INTERFACE_ENDMAP()                                  \
      { 0, ZM_LAST, NULL, NULL}                             \
    };
#define INTERFACE_ENDMAP_INLINE()                           \
      { 0, ZM_LAST, NULL, NULL}                             \
    };                                                      \
    return _InterfaceEntries;                               \
  }

/* end of INTERFACE_ENDMAP*/


/*------------------------------------------------------------------------
 * INTERFACE_FUNCTIONS_PURE_VIRTUAL
 *
 * @author: Oleg Melashenko
 *-----------------------------------------------------------------------*/
#define INTERFACE_FUNCTIONS_PURE_VIRTUAL()                              \
  virtual DWORD AddRef(void) = 0;                                       \
  virtual DWORD Release(void) = 0;                                      \
  virtual ZRESULT QueryInterface(LPCSTR uid, void**) = 0;               \
  virtual ZUnknown* GetControllingUnknown() = 0;

/*------------------------------------------------------------------------
 * INTERFACE_FUNCTIONS
 * declares implementation of ZUnknown functions
 *-----------------------------------------------------------------------*/
#define INTERFACE_FUNCTIONS()                                           \
  virtual DWORD AddRef(void)                                            \
  {                                                                     \
    if (m_pOuter)                                                       \
      return m_pOuter->AddRef();                                        \
    if (0 == m_cRefs)                                                   \
      return 0;                                                         \
    return ++m_cRefs;                                                   \
  }                                                                     \
  virtual DWORD Release(void)                                           \
  {                                                                     \
    if (m_pOuter)                                                       \
    {                                                                   \
      if (0 == m_pOuter->AddRef())                                      \
      {                                                                 \
        delete this;                                                    \
        return 0;                                                       \
      }                                                                 \
      m_pOuter->Release();                                              \
      return m_pOuter->Release();                                       \
    }                                                                   \
    if (0 == m_cRefs)                                                   \
      return 0;                                                         \
    else                                                                \
    if (0 == --m_cRefs)                                                 \
    {                                                                   \
      delete this;                                                      \
      return 0;                                                         \
    }                                                                   \
    return m_cRefs;                                                     \
  }                                                                     \
  ZRESULT QueryInterface(LPCSTR uid, void** pTarget)                    \
  {                                                                     \
    if (m_pOuter)                                                       \
      return m_pOuter->QueryInterface(uid, pTarget);                    \
    else                                                                \
      return InternalQueryInterface(uid, pTarget, this, _GetEntries()); \
  }                                                                     \
  ZUnknown* GetControllingUnknown()                                     \
  {                                                                     \
    if (m_pOuter)							\
      return m_pOuter;                                                  \
    return (ZUnknown*)((BYTE*)this+                                     \
        ((_GetEntries()[0].m_dwFlags & ZM_ZUNKNOWN) ?                   \
            _GetEntries()[0].m_dwOffset: 0));                           \
  }                                                                     \
  const ZRESULT InternalQueryInterface(                                 \
      LPCSTR uid,                                                       \
      void** pTarget,                                                   \
      void* pBaseAddress,                                               \
      const tInterfaceMap* pMap)                                        \
  {                                                                     \
    if (!pMap)                                                          \
      return ZRESULT_NOT_SUPPORTED;                                     \
    int i = 0;                                                          \
    if (!strcmp(uid, IID_(ZUnknown)))                                   \
    {                                                                   \
      *pTarget = GetControllingUnknown();                               \
      AddRef();                                                         \
      return ZRESULT_OK;                                                \
    }                                                                   \
    while (0 == (pMap[i].m_dwFlags & ZM_LAST))                          \
    {                                                                   \
      if (0 != (pMap[i].m_dwFlags & ZM_CHAIN))                          \
      {                                                                 \
        if ((pMap[i].m_dwFlags & ZM_EMBEDDED) &&                      \
           (ZRESULT_OK == InternalQueryInterface(uid, pTarget,          \
                (void*)(*(ZUnknown**)(((char*)pBaseAddress)+            \
                                      (DWORD)pMap[i].m_UID)),           \
                (const tInterfaceMap*)pMap[i].m_pReserved)))            \
          return ZRESULT_OK;                                            \
        else                                                            \
        if ((pMap[i].m_dwFlags & ZM_DELIGATED) &&                       \
           (ZRESULT_OK == (*(ZUnknown**)((char*)pBaseAddress +          \
                  pMap[i].m_dwOffset))->QueryInterface(uid, pTarget)))  \
          return ZRESULT_OK;                                            \
        else                                                            \
          if (ZRESULT_OK == InternalQueryInterface(uid, pTarget,        \
                  (void*)(((char*)pBaseAddress)+(DWORD)pMap[i].m_UID),  \
                  (const tInterfaceMap*)pMap[i].m_pReserved))           \
            return ZRESULT_OK;                                          \
      }                                                                 \
      else                                                              \
      if (!strcmp(uid, pMap[i].m_UID))                                  \
      {                                                                 \
        if (pMap[i].m_dwFlags & ZM_DELIGATED)                           \
          *pTarget = (void*)(*(ZUnknown**)pMap[i].m_pReserved);         \
        else                                                            \
        if (pMap[i].m_dwFlags & ZM_EMBEDDED)                            \
          *pTarget = (void*)(*(ZUnknown**)((char*)pBaseAddress +        \
                                             pMap[i].m_dwOffset));      \
        else                                                            \
          *pTarget = (void*)((char*)pBaseAddress + pMap[i].m_dwOffset); \
        AddRef();                                                       \
        return ZRESULT_OK;                                              \
      }                                                                 \
      i++;                                                              \
    }                                                                   \
    return ZRESULT_NOT_SUPPORTED;                                       \
  }                                                                     \
  static ZRESULT ZAPICALL CreateInstance(_ThisClass** ppTarget)         \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(_ThisClass** ppTarget,    \
                                              ZUnknown* pOuter)         \
  {                                                                     \
    ZUnknown* pTarget = NULL;                                           \
    ZRESULT zr;                                                         \
    if (ZFAILED(zr = CreateOwnedInstance((void**)&pTarget, pOuter)))    \
      return zr;                                                        \
    (*ppTarget) = (_ThisClass*)((BYTE*)pTarget-                         \
        ((_GetEntries()[0].m_dwFlags & ZM_ZUNKNOWN) ?                   \
            _GetEntries()[0].m_dwOffset: 0));                           \
    return ZRESULT_OK;                                                  \
  }                                                                     \
  static ZRESULT ZAPICALL InternalCreateInstance(void** ppTarget,       \
                                                 ZUnknown* pOuter)      \
  {                                                                     \
    _ThisClass* p = NULL;                                               \
    p = new _ThisClass();                                               \
    p->m_pOuter = pOuter;                                               \
    p->m_cRefs = 1;                                                     \
    (*ppTarget) = (void*)((BYTE*)p +                                    \
        ((_GetEntries()[0].m_dwFlags & ZM_ZUNKNOWN) ?                   \
            _GetEntries()[0].m_dwOffset: 0));                           \
    return ZRESULT_OK;                                                  \
  }

// instead of:
//  (*ppTarget) = (void*)((BYTE*)p +
//      ((_InterfaceEntries[0].m_dwFlags & ZM_ZUNKNOWN) ?
//          _InterfaceEntries[0].m_dwOffset: 0));
// there was:
//    *ppTarget = (void*)p->GetControllingUnknown();

/*------------------------------------------------------------------------
 * INTERFACE_DEFAULT_INSTANCE_CREATOR
 * implementation of CreateInstance() function when your class DOES NOT
 * provide interfaces set macro.
 * Warning: Your class have to 
 *-----------------------------------------------------------------------*/
#define INTERFACE_DEFAULT_INSTANCE_CREATOR(theClass)                    \
  static ZRESULT ZAPICALL CreateInstance(void** ppTarget)               \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(void** ppTarget,          \
                                              ZUnknown* pOuter)         \
  {                                                                     \
    theClass* p = NULL;                                                 \
    p = new theClass();                                                 \
    p->m_pOuter = pOuter;                                               \
    p->m_cRefs = 1;                                                     \
    (*ppTarget) = (void*)p;                                             \
    return ZRESULT_OK;                                                  \
  }

/*------------------------------------------------------------------------
 * INTERFACE_OVERLOAD_INSTANCE_CREATOR
 * overloaded implementation of CreateInstance() function used when your
 * class is derieved from complete component class (with interface set)
 *-----------------------------------------------------------------------*/
#define INTERFACE_OVERLOAD_INSTANCE_CREATOR(theClass)                   \
  static ZRESULT ZAPICALL CreateInstance( theClass** ppTarget)          \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(theClass** ppTarget,      \
                                              ZUnknown* pOuter)         \
  {                                                                     \
    theClass* p = NULL;                                                 \
    p = new theClass();                                                 \
    p->m_pOuter = pOuter;                                               \
    p->m_cRefs = 1;                                                     \
    (*ppTarget) =  p;                                                   \
    return ZRESULT_OK;                                                  \
  }                                                                     \
  static ZRESULT ZAPICALL CreateInstance( void** ppTarget)              \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(void** ppTarget,          \
                                              ZUnknown* pOuter)         \
  {                                                                     \
    theClass* p = NULL;                                                 \
    p = new theClass();                                                 \
    p->m_pOuter = pOuter;                                               \
    p->m_cRefs = 1;                                                     \
    (*ppTarget) = (void*)((BYTE*)p +                                    \
        ((_GetEntries()[0].m_dwFlags & ZM_ZUNKNOWN) ?                   \
            _GetEntries()[0].m_dwOffset: 0));                           \
    return ZRESULT_OK;                                                  \
  }

/*------------------------------------------------------------------------
 * INTERFACE_INSTANCE_CREATOR
 * default implementation of CreateInstance() function
 *-----------------------------------------------------------------------*/
#define INTERFACE_INSTANCE_CREATOR()                                    \
  static ZRESULT ZAPICALL CreateInstance(void** ppTarget)               \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(void** ppTarget,          \
                                              ZUnknown* pOuter)         \
    { return InternalCreateInstance(ppTarget, pOuter);}


/*------------------------------------------------------------------------
 * INTERFACE_EMBED_INSTANCE_CREATOR
 * Implementation of CreateInstance() function for an owner of embedded
 * interfaces. It calles FinalConstruct() to allow container create all
 * embedded objects.
 *-----------------------------------------------------------------------*/
#define INTERFACE_EMBED_INSTANCE_CREATOR()                              \
  static ZRESULT ZAPICALL CreateInstance(void** ppTarget)               \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(void** ppTarget,          \
                                         ZUnknown* pOuter)              \
  {                                                                     \
    ZRESULT zr = InternalCreateInstance(ppTarget, pOuter);              \
    if (zr == ZRESULT_OK)                                               \
      (*((_ThisClass**)ppTarget))->FinalConstruct();                    \
    return zr;                                                          \
  }



//-------------------------------------------------------
// @name : INTERFACE_FUNCTIONS_DEFAULT
// macro used to implement default addref/release function
// in interfaces that has no any specific interface.
//-------------------------------------------------------
#define INTERFACE_FUNCTIONS_DEFAULT(_class)                             \
  ZStdPtr<ZUnknown> m_pOuter;                                           \
  DWORD   m_cRefs;                                                      \
  typedef _class _ThisClass;                                            \
  virtual DWORD AddRef(void)                                            \
  {                                                                     \
    if (m_pOuter)                                                       \
      return m_pOuter->AddRef();                                        \
    if (0 == m_cRefs)                                                   \
      return 0;                                                         \
    return ++m_cRefs;                                                   \
  }                                                                     \
  virtual DWORD Release(void)                                           \
  {                                                                     \
    if (m_pOuter)                                                       \
    {                                                                   \
      if (0 == m_pOuter->AddRef())                                      \
      {                                                                 \
        delete this;                                                    \
        return 0;                                                       \
      }                                                                 \
      m_pOuter->Release();                                              \
      return m_pOuter->Release();                                       \
    }                                                                   \
    if (0 == m_cRefs)                                                   \
      return 0;                                                         \
    if (0 == --m_cRefs)                                                 \
    {                                                                   \
      delete this;                                                      \
      return 0;                                                         \
    }                                                                   \
    return m_cRefs;                                                     \
  }                                                                     \
  ZRESULT QueryInterface(LPCSTR uid, void** pTarget)                    \
  {                                                                     \
    if (m_pOuter)                                                       \
      return m_pOuter->QueryInterface(uid, pTarget);                    \
    else                                                                \
      return InternalQueryInterface(uid, pTarget, this, NULL);          \
  }                                                                     \
  ZUnknown* GetControllingUnknown()                                     \
  {                                                                     \
    if (m_pOuter)							\
      return m_pOuter;                                                  \
    return (ZUnknown*)(void*)this;                                      \
  }                                                                     \
  const ZRESULT InternalQueryInterface(                                 \
      LPCSTR uid,                                                       \
      void** pTarget,                                                   \
      void* pBaseAddress,                                               \
      const tInterfaceMap* pMap)                                        \
  {                                                                     \
    return ZRESULT_NOT_SUPPORTED;                                       \
  }                                                                     \
  static ZRESULT ZAPICALL CreateInstance(_ThisClass** ppTarget)         \
  { return CreateOwnedInstance(ppTarget, NULL); }                       \
  static ZRESULT ZAPICALL CreateOwnedInstance(_ThisClass** ppTarget,    \
                                         ZUnknown* pOuter)              \
    { return InternalCreateInstance((void**)ppTarget, pOuter);}         \
  static ZRESULT ZAPICALL InternalCreateInstance(void** ppTarget,       \
                                                 ZUnknown* pOuter)      \
  {                                                                     \
    _ThisClass* p = NULL;                                               \
    p = new _ThisClass();                                               \
    p->m_pOuter = pOuter;                                               \
    p->m_cRefs = 1;                                                     \
    *ppTarget = (void*)p;                                               \
    return ZRESULT_OK;                                                  \
  }


/*------------------------------------------------------------------------
 * DELIGATE macro
 *
 * Used to delicate call to member pointer
 *
 * @author: Oleg Melashenko
 *----------------------------------------------------------------------*/
#define DELIGATE(_ptr) (!_ptr) ? ZRESULT_FAIL : _ptr->

/*------------------------------------------------------------------------
 * DOWNCAST macro
 *
 * Used to call a function from inherited class
 *
 * @author: Oleg Melashenko
 *----------------------------------------------------------------------*/
#define DOWNCAST(_class) ((_class*)this)->

/*------------------------------------------------------------------------
 * ZUnknown class
 *
 * Used to derive server-side classes. It includes pure virtual
 * non-implemened AddRef, Release and QueryInterface functions.
 *
 * @author: Oleg Melashenko
 *----------------------------------------------------------------------*/
class DLL_LINKAGE ZUnknown
{
public:
  INTERFACE_FUNCTIONS_PURE_VIRTUAL()
};


/* function pointers */
typedef ZRESULT (ZAPICALL* ZM_CREATOR_FN)(void** ppTarget);
#endif //ifndef zinterface_h_included
