/////////////////////////////////////////////////////////////////////////////////////////
//
// Please refer to "COPYRIGHT.md" for the relevant copyright statement of this software.
//
/////////////////////////////////////////////////////////////////////////////////////////
//
#ifndef _GCDBTRANS_H__
#define _GCDBTRANS_H__

#include "dbmain.h"
#include "dbapserv.h"
#include "GcDbCore2dDefs.h"

#pragma pack(push, 8)

class GcTransaction;
class GcTransactionReactor;

class GCDB_PORT GcDbTransactionManager : public GcRxObject
{
public:
  GCRX_DECLARE_MEMBERS(GcDbTransactionManager);

  virtual GcTransaction* startTransaction() = 0;
  virtual Gcad::ErrorStatus endTransaction() = 0;
  virtual Gcad::ErrorStatus abortTransaction() = 0;
  virtual int numActiveTransactions() = 0;
  virtual int numOpenedObjects() = 0;
  virtual GcTransaction* topTransaction() = 0;
  virtual Gcad::ErrorStatus addNewlyCreatedDBRObject(GcDbObject* obj, bool add = true) = 0;
  virtual Gcad::ErrorStatus getAllObjects(GcArray<GcDbObject*>& objs) = 0;

  virtual void addReactor(GcTransactionReactor* reactor) = 0;
  virtual void removeReactor(GcTransactionReactor* reactor) = 0;

  virtual Gcad::ErrorStatus getObject(GcDbObject*& obj,
                                      GcDbObjectId id,
                                      GcDb::OpenMode mode = GcDb::kForRead,
                                      bool openErasedObj = false) = 0;

  template<class ObjType>
  Gcad::ErrorStatus getObject(ObjType*& pDerived,
                              GcDbObjectId id,
                              GcDb::OpenMode mode = GcDb::kForRead,
                              bool openErasedObject = false)
  {
    GcDbObject* pObj = nullptr;
    Gcad::ErrorStatus es = this->getObject(pObj, id, mode, openErasedObject);
    if (es != Gcad::eOk || pObj == nullptr)
      pDerived = nullptr;
    else
    {
      pDerived = ObjType::cast(pObj);
      if (pDerived == nullptr)
        es = Gcad::eNotThatKindOfClass;
    }
    return es;
  }

  virtual Gcad::ErrorStatus markObjectPageable(GcDbObject* pObject) = 0;
  virtual Gcad::ErrorStatus queueForGraphicsFlush() = 0;
};

class GCDB_PORT GcTransaction : public GcRxObject
{
public:
  GCRX_DECLARE_MEMBERS(GcTransaction);
  virtual Gcad::ErrorStatus getObject(GcDbObject*& obj,
                                      GcDbObjectId objectId,
                                      GcDb::OpenMode mode = GcDb::kForRead,
                                      bool openErasedObject = false) = 0;
  template<class ObjType>
  Gcad::ErrorStatus getObject(ObjType*& pDerived,
                              GcDbObjectId objectId,
                              GcDb::OpenMode mode = GcDb::kForRead,
                              bool openErasedObject = false)
  {
    GcDbObject* pObj = nullptr;
    Gcad::ErrorStatus es = this->getObject(pObj, objectId, mode, openErasedObject);
    if (es != Gcad::eOk || pObj == nullptr)
      pDerived = nullptr;
    else
    {
      pDerived = ObjType::cast(pObj);
      if (pDerived == nullptr)
        es = Gcad::eNotThatKindOfClass;
    }
    return es;
  }
  virtual Gcad::ErrorStatus markObjectPageable(GcDbObject* pObject) = 0;
  virtual int numOpenedObjects() = 0;
  virtual Gcad::ErrorStatus getAllObjects(GcArray<GcDbObject*>& objs) = 0;
};

class GCDB_PORT GcTransactionReactor : public GcRxObject
{
public:
  GCRX_DECLARE_MEMBERS(GcTransactionReactor);
  virtual ~GcTransactionReactor();

  virtual void transactionAboutToStart(int&, GcDbTransactionManager*)
  {
  }
  virtual void transactionStarted(int&, GcDbTransactionManager*)
  {
  }
  virtual void transactionAboutToEnd(int&, GcDbTransactionManager*)
  {
  }
  virtual void transactionEnded(int&, GcDbTransactionManager*)
  {
  }
  virtual void transactionAboutToAbort(int&, GcDbTransactionManager*)
  {
  }
  virtual void transactionAborted(int&, GcDbTransactionManager*)
  {
  }
  virtual void endCalledOnOutermostTransaction(int&, GcDbTransactionManager*)
  {
  }
  virtual void objectIdSwapped(const GcDbObject*, const GcDbObject*, GcDbTransactionManager*)
  {
  }
};

inline GcDbTransactionManager* gcdbTransactionManagerPtr()
{
  return gcdbHostApplicationServices()->workingTransactionManager();
}

#define gcdbTransactionManager gcdbTransactionManagerPtr()

#pragma pack(pop)

#endif