/***************************************************************************
 *                          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 configuration file
 *--------------------------------------------------------------------------
 * @histroy: 23.09.2002. Libraries with plug-ins helper macros
 */
#ifndef zlibrary_h_included
#define zlibrary_h_included
#include <core/libs/ILibrary.h>
#include <core/IRepository.h>
#include <map>

/*------------------------------------------------------------------------
 In most of cases the following code fits you library needs to be loaded:
ZM_LIBRARY_DEFAULT_DECLARE()
  ZM_LIBRARY_NO_COPYRIGHT_INFO()
  ZM_LIBRARY_COLLECTION_BEGIN()
    ZM_LIBRARY_REG(company::part::CMoveTool, kind)
    ZM_LIBRARY_REG2(company::part::CRotateTool, CMyRotateTool, kind)
  ZM_LIBRARY_COLLECTION_END()
  ZM_LIBRARY_REQUIRES(ZM_LIBREQURIES_*)   //opt
  ZM_LIBRARY_STARTUP(startupLibrary)      //opt
  ZM_LIBRARY_INITIALIZATION(initLibrary)  //opt
  ZM_LIBRARY_DYNAMIC_UNLOAD(unloadLibrary)//opt
ZM_LIBRARY_DEFAULT_END()

ZM_DLLMAIN_DEFAULT_BEGIN()
  ZM_LIBRARY_DEFAULT()
  ZM_LIBRARY_DESCRIPTION("Description of your library")
  ZM_LIBRARY_REGISTER()
ZM_DLLMAIN_DEFAULT_END()

ZM_NEED_DLL_HANDLE(name)
ZM_NEED_APP_HANDLE(name)
ZM_AUTO_HANDLE_SWITCH()
 *-----------------------------------------------------------------------*/
namespace core
{
  namespace libs
  {
    class CDefaultLibrary : public ILibrary
    {
    public:
      INTERFACE_FUNCTIONS_DEFAULT(CDefaultLibrary)
    public:
      virtual ZRESULT getDescription(ZStringSeq& desc) { return ZRESULT_FALSE; }
      virtual ZRESULT getCopyrightInfo(core::ICopyrightInfo** ppInfo) { return ZRESULT_FALSE; }
      virtual ZRESULT getClassesList(tClassInfoSeq& classList) { return ZRESULT_FALSE; }
      virtual ZRESULT createClass(ZString name, ZUnknown** ppUnk) { return ZRESULT_FALSE; }
      virtual ZRESULT getHandle(tModuleHandle& handle) { return ZRESULT_FALSE; }
      virtual ZRESULT setHandle(tModuleHandle handle) { return ZRESULT_FALSE; }
      virtual ZRESULT requires(DWORD& dwFlags) { dwFlags = 0; return ZRESULT_FALSE; }
      virtual ZRESULT initialize(void) { return ZRESULT_OK; }
      virtual ZRESULT startup(void) { return ZRESULT_OK; }
      virtual ZRESULT unload(bool bClose=false) { return ZRESULT_FALSE; }
    };//class CDefaultLibrary
  };//libs
};//core


/*------------------------------------------------------------------------
 * ZM_DLLMAIN_LOAD_BEGIN
 * Hides DllMain function's behavior on libary initialization.
 *-----------------------------------------------------------------------*/
#define ZM_DLLMAIN_LOAD_BEGIN()                             \
HINSTANCE   g_hDLLHandle;                                   \
BOOL WINAPI DllMain(                                        \
    HINSTANCE hinstDLL,                                     \
    DWORD fdwReason,                                        \
    LPVOID lpReserved )                                     \
{                                                           \
  g_hDLLHandle = hinstDLL;                                  \
  switch( fdwReason )                                       \
  {                                                         \
    case DLL_PROCESS_ATTACH:

/*------------------------------------------------------------------------
 * ZM_DLLMAIN_LOAD_END
 * end if default libary initialization.
 *-----------------------------------------------------------------------*/
#define ZM_DLLMAIN_LOAD_END()                               \
      break;                                                \
    case DLL_THREAD_ATTACH:                                 \
      break;                                                \
    case DLL_THREAD_DETACH:                                 \
      break;

/*------------------------------------------------------------------------
 * ZM_DLLMAIN_UNLOAD_BEGIN
 * end if default libary unload.
 *-----------------------------------------------------------------------*/
#define ZM_DLLMAIN_UNLOAD_BEGIN()                           \
    case DLL_PROCESS_DETACH:


/*------------------------------------------------------------------------
 * ZM_DLLMAIN_UNLOAD_END
 * end if default libary unload.
 *-----------------------------------------------------------------------*/
#define ZM_DLLMAIN_UNLOAD_END()                             \
      break;                                                \
  }                                                         \
  return TRUE;                                              \
}


/*------------------------------------------------------------------------
 * ZM_DLLMAIN_DEFAULT_BEGIN
 * Default behavior for most of the libraries:
 *-----------------------------------------------------------------------*/
#define ZM_DLLMAIN_DEFAULT_BEGIN  ZM_DLLMAIN_LOAD_BEGIN

/*------------------------------------------------------------------------
 * ZM_DLLMAIN_DEFAULT_END
 * Default behavior for most of the libraries:
 *-----------------------------------------------------------------------*/
#define ZM_DLLMAIN_DEFAULT_END    ZM_DLLMAIN_UNLOAD_END



/*------------------------------------------------------------------------
 * ZM_LIBRARY_DEFAULT_DECLARE
 * Hides default implementation of CLibrary class
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_DEFAULT_DECLARE()                        \
class CLibrary : public core::libs::CDefaultLibrary         \
{                                                           \
  public:                                                   \
    INTERFACE_DECLAREMAP(CLibrary)                          \
    CLibrary() : core::libs::CDefaultLibrary()              \
      { m_Handle = 0; }                                     \
  public:

#define ZM_LIBRARY_NO_COPYRIGHT_INFO()                      \
    ZRESULT getCopyrightInfo(core::ICopyrightInfo** ppInfo) \
    {                                                       \
      return ZRESULT_NOT_IMPLEMENTED;                       \
    }

#define ZM_LIBRARY_COLLECTION_BEGIN()                       \
    tClassMap m_mapClasses;                                 \
    void InitToolsMap()                                     \
    {
/*------------------------------------------------------------------------
 * ZM_LIBRARY_REG?
 * Several class-registering macros
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_REG(name, kind)                          \
      m_mapClasses[#name] = tLibClassInfo(                  \
             name::CreateInstance, kind);

#define ZM_LIBRARY_REG2(declname, implname, kind)           \
      m_mapClasses[#declname] =                             \
             tLibClassInfo(implname::CreateInstance, kind);

#define ZM_LIBRARY_COLLECTION_END()                         \
    }                                                       \
    ZRESULT getClassesList(tClassInfoSeq& classList)        \
    {                                                       \
      if (0==m_mapClasses.size())                           \
        InitToolsMap();                                     \
      tClassMap::iterator it = m_mapClasses.begin();        \
      classList.clear();                                    \
      int pos = 0;                                          \
      while (it != m_mapClasses.end())                      \
      {                                                     \
        classList[pos].m_strClassName = it->first;          \
        classList[pos].m_info = it->second;                 \
        it++;                                               \
        pos++;                                              \
      }                                                     \
      return ZRESULT_OK;                                    \
    }                                                       \
    ZRESULT createClass(ZString name,                       \
                        ZUnknown** ppUnk)                   \
    {                                                       \
      if (NULL==ppUnk)                                      \
        return ZRESULT_INVALID_ARG;                         \
      (*ppUnk) = NULL;                                      \
      if (0==m_mapClasses.size())                           \
        InitToolsMap();                                     \
      tClassMap::iterator it = m_mapClasses.find(name);     \
      if (it == m_mapClasses.end())                         \
        return ZRESULT_FALSE;                               \
      return it->second.m_creator((void**)ppUnk);           \
    }                                                       \
    ZRESULT getDescription(ZStringSeq& strDesc)             \
    {                                                       \
      strDesc = m_strModuleDesc;                            \
      return ZRESULT_OK;                                    \
    }                                                       \
    ZRESULT getHandle(tModuleHandle& handle)                \
    {                                                       \
      handle = m_Handle;                                    \
      return (0==handle) ? ZRESULT_FALSE : ZRESULT_OK;      \
    }                                                       \
    ZRESULT setHandle(tModuleHandle  handle)                \
    {                                                       \
      m_Handle = handle;                                    \
      return ZRESULT_OK;                                    \
    }

/*------------------------------------------------------------------------
 * ZM_LIBRARY_REQURES(n)
 * Library requirements bit
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_REQUIRES(n)                              \
    ZRESULT requires(DWORD& dwFlags)                        \
    {                                                       \
      dwFlags = n;                                          \
      return ZRESULT_OK;                                    \
    }

/*------------------------------------------------------------------------
 * ZM_LIBRARY_INITIALIZATION
 * Deligates initialization to extern ZRESULT _function() routine
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_INITIALIZATION(_function)                \
    ZRESULT initialize()                                    \
    {                                                       \
      extern ZRESULT _function();                           \
      AfxSetResourceHandle(m_Handle);                       \
      ZRESULT zr = _function();                             \
      extern DLL_LINKAGE HINSTANCE g_hAppHandle;            \
      AfxSetResourceHandle(g_hAppHandle);                   \
      return zr;                                            \
    }

/*------------------------------------------------------------------------
 * ZM_LIBRARY_STARTUP
 * Deligates startup to extern ZRESULT _function() routine
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_STARTUP(_function)                       \
    ZRESULT startup()                                       \
    {                                                       \
      extern ZRESULT _function();                           \
      AfxSetResourceHandle(m_Handle);                       \
      ZRESULT zr = _function();                             \
      extern DLL_LINKAGE HINSTANCE g_hAppHandle;            \
      AfxSetResourceHandle(g_hAppHandle);                   \
      return zr;                                            \
    }

/*------------------------------------------------------------------------
 * ZM_LIBRARY_DYNAMIC_UNLOAD
 * Deligates unload of library to extern ZRESULT _function() routine
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_DYNAMIC_UNLOAD(_function)                \
    ZRESULT unload(bool bClose=false)                       \
    {                                                       \
      extern ZRESULT _function(bool bClose);                \
      AfxSetResourceHandle(m_Handle);                       \
      ZRESULT zr = _function(bClose);                       \
      extern DLL_LINKAGE HINSTANCE g_hAppHandle;            \
      AfxSetResourceHandle(g_hAppHandle);                   \
      return zr;                                            \
    }

/*------------------------------------------------------------------------
 * ZM_LIBRARY_DEFAULT_END
 * Hides tail of default implementation of CLibrary class
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_DEFAULT_END()                            \
    ZStringSeq    m_strModuleDesc;                          \
    tModuleHandle m_Handle;                                 \
};                                                          \
INTERFACE_BEGINMAP(CLibrary)                                \
  INTERFACE_ENTRY(core::libs::ILibrary)                     \
INTERFACE_ENDMAP()


/*------------------------------------------------------------------------
 * ZM_LIBRARY_DEFAULT
 * Creates in instance of CLibrary and returns it as library
 * info source to ZModeler
 *-----------------------------------------------------------------------*/
#define ZM_LIBRARY_DEFAULT()                                \
    ZPtr<CLibrary> pCLib;                                   \
    CLibrary::CreateInstance(&pCLib);                       \
    if (!pCLib)                                             \
      return FALSE;                                         \
    pCLib->setHandle(hinstDLL);

#define ZM_LIBRARY_DESCRIPTION(desc)                        \
    pCLib->m_strModuleDesc.add(desc);

#define ZM_LIBRARY_REGISTER()                               \
    if (g_pZModeler)                                        \
    {                                                       \
      ZPtr<core::IRepository> pRepos;                       \
      g_pZModeler->getRepository(&pRepos);                  \
      if (pRepos)                                           \
        return ZRESULT_OK == pRepos->addLibrary(pCLib);     \
    }

/*------------------------------------------------------------------------
 * ZM_NEED_DLL_HANDLE
 * Macro provides DLL handle in supplied variable
 *-----------------------------------------------------------------------*/
#define ZM_NEED_DLL_HANDLE(varName)                         \
extern HINSTANCE g_hDLLHandle;                              \
HINSTANCE &varName = g_hDLLHandle;


/*------------------------------------------------------------------------
 * ZM_NEED_APP_HANDLE
 * Macro provides ZModeler's APP handle in supplied variable
 *-----------------------------------------------------------------------*/
#define ZM_NEED_APP_HANDLE(varName)                         \
extern DLL_LINKAGE HINSTANCE g_hAppHandle;                  \
HINSTANCE &varName = g_hAppHandle;

/*------------------------------------------------------------------------
 * ZM_AUTO_HANDLE_SWITCH
 * Implements a class which will switch handles automatically
 *-----------------------------------------------------------------------*/
#define ZM_AUTO_HANDLE_SWITCH() CZMModuleHandleAutoSwitcher zm_handle_switcher_var;

class CZMModuleHandleAutoSwitcher
{
  HINSTANCE m_hDll, m_hOld;
public:
  CZMModuleHandleAutoSwitcher()
  {
    extern HINSTANCE g_hDLLHandle;
    m_hDll = g_hDLLHandle;
    m_hOld = AfxGetResourceHandle();
    AfxSetResourceHandle(m_hDll);
  };
  ~CZMModuleHandleAutoSwitcher()
  {
    AfxSetResourceHandle(m_hOld);
  }
};

#endif //zlibrary_h_included
