/////////////////////////////////////////////////////////////////////////////// 
// Copyright (C) 2003-2012, Open Design Alliance (the "Alliance"). 
// All rights reserved. 
// 
// This software and its documentation and related materials are owned by 
// the Alliance. The software may only be incorporated into application 
// programs owned by members of the Alliance, subject to a signed 
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable  
// trade secrets of the Alliance and its suppliers. The software is also 
// protected by copyright law and international treaty provisions. Application  
// programs incorporating this software must include the following statement 
// with their copyright notices:
//   
//   This application incorporates Teigha(R) software pursuant to a license 
//   agreement with Open Design Alliance.
//   Teigha(R) Copyright (C) 2003-2012 by Open Design Alliance. 
//   All rights reserved.
//
// By use of this software, its documentation or related materials, you 
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////

/************************************************************************/
/* This console application reads a DWG file and dumps its contents     */
/* to the console.                                                      */
/*                                                                      */
/* Calling sequence:                                                    */
/*                                                                      */
/*    OdReadEx <filename>                                               */
/*                                                                      */
/************************************************************************/

#ifdef _MSC_VER
#define _WIN32_WINNT 0x0400 // to enable Windows Cryptographic API
#endif

#include "OdaCommon.h"
#include "diagnostics.h"
#include "DbDatabase.h"
#include "DbEntity.h"
#include "DbDimAssoc.h"

#include "OdCharMapper.h"
#include "RxObjectImpl.h"

#include "ExSystemServices.h"
#include "ExHostAppServices.h"
#include "ExProtocolExtension.h"
#include "OdFileBuf.h"
#include "RxDynamicModule.h"
#include "FdField.h"

#define STL_USING_IOSTREAM
#include "OdaSTL.h"
#define  STD(a)  std:: a

#include "DbDumper.h"

#if defined(TARGET_OS_MAC) && !defined(__MACH__)
#include <console.h>
#endif

/************************************************************************/
/* Compile password support for R18 Drawings                            */
/************************************************************************/
#ifdef _MSC_VER
#pragma message ("Compiling password support for R18 drawings")
#include "WinNTCrypt.cpp"
#endif

#pragma comment(lib, "TD_Db.lib")
#pragma comment(lib, "TD_Ge.lib")
#pragma comment(lib, "TD_Gi.lib")
#pragma comment(lib, "TD_Root.lib")
#pragma comment(lib, "TD_Alloc.lib")
#pragma comment(lib, "TD_DbRoot.lib")
#pragma comment(lib, "DbCommands.lib")
#pragma comment(lib, "RxRasterServices.lib")
#pragma comment(lib, "DwgCommonLib.lib")

/************************************************************************/
/* Freeze a local time                                                  */
/************************************************************************/
typedef void (*PgetLocalTime)( OdTimeStamp& ts );
extern FIRSTDLL_EXPORT_STATIC PgetLocalTime g_pLocalTimeFunc; // global variable defined in TD_Root
static void getLocalTime(OdTimeStamp &localTime)
{
  localTime.setDate(12, 22, 2009);
  localTime.setTime(18, 0, 0, 0);
}

/************************************************************************/
/* Define a Custom Services class.                                      */
/*                                                                      */
/* Combines the platform dependent functionality of                     */
/* ExSystemServices and ExHostAppServices                               */ 
/************************************************************************/
class MyServices : public ExSystemServices, public ExHostAppServices
{
protected:
  ODRX_USING_HEAP_OPERATORS(ExSystemServices);

private:

#ifdef _MSC_VER

  /**********************************************************************/
  /* Define a console interface for password support.                   */
  /**********************************************************************/
  bool getPassword(const OdString& dwgName, bool /*isXref*/, OdPassword& password)
  {
    odPrintConsoleString(L"Enter password to open drawing: %ls\n", dwgName.c_str());
    wchar_t pwdBuff[_MAX_PATH] = {0};
    STD(wcin).get(pwdBuff, L'\n').get();
    ::CharUpperW(pwdBuff);
    password = pwdBuff;
    return !password.isEmpty();
  }
#endif
};

/************************************************************************/
/* Define a module map for statically linked modules:                   */
/************************************************************************/
#ifndef _TOOLKIT_IN_DLL_

ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ModelerModule);
ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRecomputeDimBlockModule);
ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ExFieldEvaluatorModule);

ODRX_BEGIN_STATIC_MODULE_MAP()
  ODRX_DEFINE_STATIC_APPLICATION(OdModelerGeometryModuleName,   ModelerModule)
  ODRX_DEFINE_STATIC_APPLICATION(OdRecomputeDimBlockModuleName, OdRecomputeDimBlockModule)
  ODRX_DEFINE_STATIC_APPMODULE(OdExFieldEvaluatorModuleName, ExFieldEvaluatorModule)
ODRX_END_STATIC_MODULE_MAP()

#endif

/********************************************************************************/
/* Define Assert function to not crash Debug application if assertion is fired. */
/********************************************************************************/
static void MyAssert(const char* expression, const char* fileName, int nLineNo)
{
  OdString message;
  message.format(L"\n!!! Assertion failed: \"%ls\"\n    file: %ls, line %d\n", OdString(expression).c_str(), OdString(fileName).c_str(), nLineNo);
  odPrintConsoleString(message);
}
/********************************************************************************/
/* Define Ge error handler to not crash OdReadEx application and dump errors.   */
/********************************************************************************/
static void MyGeError(OdResult res)
{
  OdString message;
  message.format(L"\n!!! Ge error: \"%ls\"\n", OdError(res).description().c_str());
  odPrintConsoleString(message);
}

/************************************************************************/
/* Main                                                                 */
/************************************************************************/
#if (defined(WIN32) || defined(WIN64))
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
#if defined(TARGET_OS_MAC) && !defined(__MACH__)
  argc = ccommand(&argv);
#endif
  
  /**********************************************************************/
  /* Verify the argument count and display an error message as required */
  /**********************************************************************/
  if (argc < 2) 
  {
    odPrintConsoleString(L"OdReadEx sample program. Copyright (c) 2006, Open Design Alliance\n");
    odPrintConsoleString(L"\tusage: OdReadEx filename [MT] [DO] [PL]\n");
    odPrintConsoleString(L"\tMT - loading using multithread mode\n");
    odPrintConsoleString(L"\tDO - disable output\n");
    odPrintConsoleString(L"\tPL - enable partial loading\n");
    odPrintConsoleString(L"\nPress ENTER to continue...\n");
    STD(cin).get();
    return 1;
  }
  else
  {
#ifndef _TOOLKIT_IN_DLL_
    ODRX_INIT_STATIC_MODULE_MAP();
#endif

    bool isMTMode = false;
    bool enablePartialLoading = false;
    bool disableSvcsOutput = false;
    for (int i = 2; i < argc; ++i)
    {
      /**********************************************************************/
      /* Use MT loading mode                                                */
      /**********************************************************************/
      if (!OdString(argv[i]).iCompare(L"MT"))
        isMTMode = true;
      /**********************************************************************/
      /* Disable progress meter                                             */
      /**********************************************************************/
      else if (!OdString(argv[i]).iCompare(L"DO"))
        disableSvcsOutput = true;
      /**********************************************************************/
      /* Enable partial loading                                             */
      /**********************************************************************/
      else if (!OdString(argv[i]).iCompare(L"PL"))
        enablePartialLoading = true;
    }

    /********************************************************************/
    /* Create a custom Services instance.                               */
    /********************************************************************/
    OdStaticRxObject<MyServices> svcs;
    svcs.disableOutput(disableSvcsOutput);

    /**********************************************************************/
    /* Overload OdTimeStamp::getLocalTime internal implementation         */
    /**********************************************************************/
    g_pLocalTimeFunc = getLocalTime;

    /**********************************************************************/
    /* Set customized assert function                                     */
    /**********************************************************************/
    odSetAssertFunc(MyAssert);

    /**********************************************************************/
    /* Set customized Ge exception processing                             */
    /**********************************************************************/
    OdGeContext::gErrorFunc = MyGeError;

    /********************************************************************/
    /* Initialize Teigha.                                               */
    /********************************************************************/
    odInitialize(&svcs);
#ifdef _MSC_VER

    /********************************************************************/
    /* Initialize Windows NT Encription/Decription                      */
    /********************************************************************/
    ::odrxInitWinNTCrypt();
#else

    /********************************************************************/
    /* Find the data file and and initialize the character mapper       */
    /********************************************************************/
    OdString iniFile = svcs.findFile(OD_T("adinit.dat"));
    if (!iniFile.isEmpty())
      OdCharMapper::initialize(iniFile);
#endif

// ODA_MT_DBIO_BEGIN
    /********************************************************************/
    /* Create protocol extension for MT loading.                        */
    /********************************************************************/
    OdStaticRxObject<OdDbHostAppMTServicesPE> svcsExt;
    if (isMTMode)
    {
      OdDbHostAppServices::desc()->addX(OdDbHostAppMTServicesPE::desc(), &svcsExt);
    }
// ODA_MT_DBIO_END

    /********************************************************************/
    /* Display the Product and Version that created the executable      */
    /********************************************************************/
    odPrintConsoleString(L"\nOdReadEx developed using %ls ver %ls\n", 
      svcs.product().c_str(), svcs.versionString().c_str());

    /********************************************************************/
    /* This ExProtocolExtension class defines an OdDbEntity_Dumper      */
    /* protocol extension for each of the supported OdDbEntity classes  */
    /* and a default dumper for the non-supported classes.              */
    /********************************************************************/
    ExProtocolExtension theProtocolExtensions;
    /********************************************************************/
    /* Initialize protocol extensions                                   */
    /********************************************************************/
    theProtocolExtensions.initialize();
    bool bSuccess = true;
    try 
    {
      ::odrxDynamicLinker()->loadModule(OdExFieldEvaluatorModuleName);
      ::odrxDynamicLinker()->loadModule(OdDynBlocksModuleName);
//      ::odrxDynamicLinker()->loadModule(DbConstraintsModuleName);
      /******************************************************************/
      /* Create a database and load the drawing into it.                */
      /*                                                                */
      /* Specified arguments are as followed:                           */
      /*     filename, allowCPConversion, partialLoad, openMode         */      
      /******************************************************************/
      OdString f(argv[1]); // for UNIX UNICODE support
      OdDbDatabasePtr pDb = svcs.readFile(
        f.c_str(), true, enablePartialLoading, Oda::kShareDenyNo); 

      if (!pDb.isNull())
      {
        oddbEvaluateFields(pDb, OdDbField::kOpen);
        /****************************************************************/
        /* Display the File Version                                     */
        /****************************************************************/
        odPrintConsoleString(L"\nFile Version: %d\n", pDb->originalFileVersion()); 
        
        if (enablePartialLoading)
        {
          /****************************************************************/
          /* Will reload all objects
          /****************************************************************/
          pDb->closeInput();
        }

        /****************************************************************/
        /* Dump the database                                            */
        /****************************************************************/
        DbDumper dumper;
        dumper.dump(pDb);
        odPrintConsoleString(L"Dumping finished\n");
      }
    }
    /********************************************************************/
    /* Display the error                                                */
    /********************************************************************/
    catch (OdError& e)
    {
      odPrintConsoleString(L"\nTeigha Error: %ls\n",svcs.getErrorDescription(e.code()).c_str());
      bSuccess = false;
    }
    catch (...)
    {
      odPrintConsoleString(L"\nUnknown Error.\nPress ENTER to continue...\n");
      STD(cin).get();
      return 0;
    }

// ODA_MT_DBIO_BEGIN
    /********************************************************************/
    /* Uninitialize protocol extension for MT loading.                  */
    /********************************************************************/
    if (isMTMode)
    {
      OdDbHostAppServices::desc()->delX(OdDbHostAppMTServicesPE::desc());
    }
// ODA_MT_DBIO_END

#ifdef _MSC_VER
    /********************************************************************/
    /* Uninitialize Windows NT Encription/Decription                    */
    /********************************************************************/
    ::odrxUninitWinNTCrypt();
#endif

    /********************************************************************/
    /* Uninitialize protocol extensions                                 */
    /********************************************************************/
    theProtocolExtensions.uninitialize();
    odPrintConsoleString(L"Protocol Extensions uninitialized\n");

    /********************************************************************/
    /* Uninitialize Teigha                                              */
    /********************************************************************/
    odUninitialize();
    odPrintConsoleString(L"Teigha uninitialized\n");
    if (bSuccess)
      odPrintConsoleString(L"OdReadEx Finished Successfully\n");
    return 0;
  }
}
