/*
 * Example 2
 *
 * This program copies the first block reference from the
 * example drawing to a new drawing file.
 */
#include "OdaCommon.h"

#include "DbBlockTableRecord.h"
#include "DbDatabase.h"
#include "DbIdMapping.h"
#include "DbObject.h"
#include "DbObjectId.h"
#include "DbSystemServices.h"
#include "DynamicLinker.h"
#include "ExHostAppServices.h"
#include "ExPrintConsole.h"
#include "ExSystemServices.h"
#include "IdArrays.h"
#include "OdCodePage.h"
#include "OdModuleNames.h"
#include "RxInit.h"
#include "diagnostics.h"
#include <iostream>

static void
MyAssert(const char *expression, const char *fileName, int nLineNo) {
  OdString message;
  message.format(L"\n!!! Assertion failed: \"%s\"\n    file: %ls, line %d\n\n",
                 OdString(expression).c_str(),
                 OdString(fileName).c_str(),
                 nLineNo);
  odPrintConsoleString(message);
}

class MyServices : public ExSystemServices, public ExHostAppServices {};

void InitServices(OdStaticRxObject<MyServices> *svcs) {
  odSetAssertFunc(MyAssert);
  odInitialize(svcs);
  svcs->disableOutput(true);

  // load dynamic block related modules
  ::odrxInitialize(svcs);
  ::odrxDynamicLinker()->loadModule(DbConstraintsModuleName);
  ::odrxDynamicLinker()->loadModule(OdDynBlocksModuleName);

  // set codepage to avoid AutoCAD warning pop-up when creating DWGs from linux
  svcs->setSystemCodePage(OdCodePageId::CP_ANSI_1252);
}

void UninitializeServices(OdStaticRxObject<MyServices> *svcs) {
  odrxUninitialize();
  odUninitialize();
}

void Run(OdStaticRxObject<MyServices> *svcs);

int main(int argc, char **argv) {
  // create and initialize the services
  OdStaticRxObject<MyServices> svcs;
  InitServices(&svcs);

  // try to run the code and catch any exceptions
  try {
    Run(&svcs);
  } catch(const OdError &e) {
    odPrintConsoleString(L"OdError: ");
    odPrintConsoleString(e.description());
    odPrintConsoleString(L"\n");
  } catch(const std::exception &e) {
    std::wcout << L"std::exception: " << e.what() << std::endl;
  } catch(...) { odPrintConsoleString(L"Unknown exception\n"); }

  // uninitialize the services and exit
  UninitializeServices(&svcs);
  return 0;
}

void Run(OdStaticRxObject<MyServices> *svcs) {
  // read the example drawing
  OdDbDatabasePtr sourceDb = svcs->readFile(L"./dyn-table.dwg");
  // create a new empty drawing that the contents of the
  // example drawing will be copied to
  OdDbDatabasePtr targetDb = svcs->createDatabase();

  // get the id of the first block reference in the example file
  OdDbObjectIdArray sourceIds;
  OdDbBlockTableRecordPtr sourceMsp = sourceDb->getModelSpaceId().openObject();
  // this is the handle of the first block reference in the example drawing
  OdString targetHandle = "25D";
  bool found = false;
  for(auto iter = sourceMsp->newIterator(); !iter->done(); iter->step()) {
    OdDbObjectId id = iter->objectId();
    OdString handle = id.getHandle().ascii();
    if(handle == targetHandle) {
      sourceIds.push_back(id);
      found = true;
    }
  }

  if(!found) {
    odPrintConsoleString(L"Error: entity with handle " + targetHandle +
                         L" not found in the source drawing.\n");
    return;
  }

  // copy the entities to the new drawing
  OdDbObjectId targetMspId = targetDb->getModelSpaceId();
  OdDbIdMappingPtr idMap = OdDbIdMapping::createObject();
  targetDb->wblockCloneObjects(
      sourceIds, targetMspId, *idMap, OdDb::kDrcIgnore);

  // write the new drawing to disk
  targetDb->writeFile(L"./example2.dwg", OdDb::kDwg, OdDb::kDHL_CURRENT);
  odPrintConsoleString(L"Success: created example2.dwg\n");
}
