#pragma once

#include "Dbmain.h"
//#include "McDbSymbolTable.h"

// -------------------------------------------------------------------------
// Summary:
// 		控件中，打开实体的智能指针基类，该类是一个模板，对象的类型可以当着模板的参传入
// -------------------------------------------------------------------------
template<class T_OBJECT>
class McDbObjectPointerBase
{
public:
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// -------------------------------------------------------------------------
    McDbObjectPointerBase();

	// -------------------------------------------------------------------------
	// Summary:
	// 		析构函数
	// -------------------------------------------------------------------------
    virtual ~McDbObjectPointerBase();

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回打开的对象常量指针
	// -------------------------------------------------------------------------
    const T_OBJECT *  object() const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回打开的对象指针
	// -------------------------------------------------------------------------
    T_OBJECT *        object();


	operator  T_OBJECT* () const;

	operator const T_OBJECT* () const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		重载->运行符，返回对象常量指针
	// -------------------------------------------------------------------------
    const T_OBJECT *  operator->() const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		重载->运行符，返回对象指针
	// -------------------------------------------------------------------------
    T_OBJECT *        operator->();

	// -------------------------------------------------------------------------
	// Summary:
	// 		智能指针的打开状态,如果打开成功，该函数Mcad::eOk
	// -------------------------------------------------------------------------
    Mcad::ErrorStatus openStatus() const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		把智能指针与一个对象指针关联，让智能指针管理该对象
	// Parameters:
	// 		pObjToAcquire - 被关联的对象指针
	// Returns:
	// 		如果成功返回Mcad::eOk
	// -------------------------------------------------------------------------
    Mcad::ErrorStatus acquire(T_OBJECT *& pObjToAcquire);

	// -------------------------------------------------------------------------
	// Summary:
	// 		智能指针释放对象指针的关联
	// Parameters:
	// 		pReleasedObj - 释放后的对象指针
	// Returns:
	// 		如果成功返回Mcad::eOk
	// -------------------------------------------------------------------------
    Mcad::ErrorStatus release(T_OBJECT *& pReleasedObj);

	// -------------------------------------------------------------------------
	// Summary:
	// 		new一个对象指针
	// -------------------------------------------------------------------------
    Mcad::ErrorStatus create();

	//:Ignore
	
protected:
    McDbObjectPointerBase(McDbObjectId   objId,
                          McDb::OpenMode mode,
                          bool           openErased);


    T_OBJECT *        m_ptr;
    Mcad::ErrorStatus m_status;

private:
    // Copy and assignment prohibited.
    McDbObjectPointerBase(McDbObjectPointerBase & pObject);
    McDbObjectPointerBase& operator=(McDbObjectPointerBase & pObject);

    Mcad::ErrorStatus closeInternal();
	//:End Ignore
};

// -------------------------------------------------------------------------
// Summary:
// 		打开对象，并自动管理打开关闭实体的智能指针，该类是一个模板，对象的类型可以当着模板的参传入
// Remarks:
//		系统要求用户在操作对象时，必须先打开，操作完成后必须关闭对象，该类是个智能指针器(使用模板实现)，它能自动打开对象，并且对象析构时自动关闭对象，使用方便安全，很多地方都需要使用
// 		例如:下面的代码是读方式打开一个直线对象：
// 		<code>
// 			McDbObjectPointer<McDbLine> spLine(objId,AcDb::kForWrite);
// 			if(spLine.openStatus() != Acad::eOk)
// 			{
// 				acutPrintf(_T("\n 打开失败"));
// 				return;
// 			}
// 		</code>
// -------------------------------------------------------------------------
template<class T_OBJECT>
class McDbObjectPointer : public McDbObjectPointerBase<T_OBJECT>
{
public:
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// -------------------------------------------------------------------------
    McDbObjectPointer();

	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// Parameters:
	// 		objId		-		对象的ID
	//		mode		-		对象的打开方式
	//		openErased	-		删除后的对象是否也打开
	// Remarks:
	// 		在构造函数里自动打开对象,在析构函数里自动关闭对象
	// -------------------------------------------------------------------------
    McDbObjectPointer(McDbObjectId   objId,
                      McDb::OpenMode mode,
                      bool           openErased = false);

	
private:
    //:Ignore
    McDbObjectPointer(McDbObjectPointer & pObject);
    McDbObjectPointer& operator=(McDbObjectPointer & pObject);
	//:End Ignore
};

// -------------------------------------------------------------------------
// Summary:
// 		McDbEntity智能指针
// -------------------------------------------------------------------------
typedef McDbObjectPointer<McDbEntity>     McDbEntityPointer;

// --------- Inline definitions ---------
template<class T_OBJECT> inline
McDbObjectPointerBase<T_OBJECT>::McDbObjectPointerBase()
    : m_ptr(NULL),
      m_status(Mcad::eNullObjectPointer)
{
}

template<class T_OBJECT> inline
McDbObjectPointerBase<T_OBJECT>::McDbObjectPointerBase(
    McDbObjectId   objId,
    McDb::OpenMode mode,
    bool           openErased)
    : m_ptr(NULL),
	m_status(Mx::mcdbOpenObject(m_ptr, objId, mode, openErased))
{
}



template<class T_OBJECT> inline
McDbObjectPointerBase<T_OBJECT>::~McDbObjectPointerBase()
{
    if (m_ptr != NULL) {
		MXASSERT(m_status == Mcad::eOk);
        Mcad::ErrorStatus closeStatus = closeInternal();
		MXASSERT(closeStatus == Mcad::eOk);
    }
}

template<class T_OBJECT> inline const T_OBJECT *
McDbObjectPointerBase<T_OBJECT>::object() const
{
	MXASSERT(m_status == Mcad::eOk);
	MXASSERT(m_ptr != NULL);
    return m_ptr;
}

// This function does not modify the object, but we may not make
// it const.  Doing so will overload it with the const operator->()
// function above, which is not allowed (we're overloading on
// const-ness).
template<class T_OBJECT> inline T_OBJECT *
McDbObjectPointerBase<T_OBJECT>::object()
{
	MXASSERT(m_status == Mcad::eOk);
	MXASSERT(m_ptr != NULL);
    return m_ptr;
}

template<class T_OBJECT> inline McDbObjectPointerBase<T_OBJECT>::operator T_OBJECT* () const
{
	MXASSERT(m_status == Mcad::eOk);
	MXASSERT(m_ptr != NULL);
	return m_ptr;
}

template<class T_OBJECT> inline McDbObjectPointerBase<T_OBJECT>::operator const T_OBJECT* () const
{
	MXASSERT(m_status == Mcad::eOk);
	MXASSERT(m_ptr != NULL);
	return m_ptr;
}



template<class T_OBJECT> inline const T_OBJECT *
McDbObjectPointerBase<T_OBJECT>::operator->() const
{
    return object();
}

template<class T_OBJECT> inline T_OBJECT *
McDbObjectPointerBase<T_OBJECT>::operator->()
{
    return object();
}

template<class T_OBJECT> inline Mcad::ErrorStatus
McDbObjectPointerBase<T_OBJECT>::openStatus() const
{
    return m_status;
}

template<class T_OBJECT> inline Mcad::ErrorStatus
McDbObjectPointerBase<T_OBJECT>::acquire(T_OBJECT *& pObjToAcquire)
{
    if (pObjToAcquire == NULL)
        return Mcad::eNullObjectPointer;
    if (m_ptr != NULL) {
		MXASSERT(m_status == Mcad::eOk);
        Mcad::ErrorStatus closeStatus = closeInternal();
        if (closeStatus != Mcad::eOk)
            return closeStatus;
    }
    m_ptr = pObjToAcquire;
    m_status = Mcad::eOk;
    pObjToAcquire = NULL;
    return Mcad::eOk;
}

template<class T_OBJECT> inline Mcad::ErrorStatus
McDbObjectPointerBase<T_OBJECT>::release(T_OBJECT *& pReleasedObj)
{
    if (m_ptr == NULL)
        return Mcad::eNullObjectPointer;
	MXASSERT(m_status == Mcad::eOk);
    pReleasedObj = m_ptr;
    m_ptr    = NULL;
    m_status = Mcad::eNullObjectPointer;
    return Mcad::eOk;
}

template<class T_OBJECT> inline Mcad::ErrorStatus
McDbObjectPointerBase<T_OBJECT>::create()
{
    T_OBJECT * pObject = new T_OBJECT;
    if (pObject == NULL)
        return Mcad::eNullObjectPointer;
    if (m_ptr != NULL) {
		MXASSERT(m_status == Mcad::eOk);
        Mcad::ErrorStatus closeStatus = closeInternal();
        if (closeStatus != Mcad::eOk) {
            delete pObject;
            return closeStatus;
        }
    }
    m_ptr = pObject;
    m_status = Mcad::eOk;
    return Mcad::eOk;
}

template<class T_OBJECT> inline Mcad::ErrorStatus
McDbObjectPointerBase<T_OBJECT>::closeInternal()
{
    if (m_ptr == NULL)
        return Mcad::eOk;
    if (m_ptr->objectId().isNull()) {
        delete m_ptr;
        return Mcad::eOk;
    }
    return m_ptr->close();
}

template<class T_OBJECT> inline
McDbObjectPointer<T_OBJECT>::McDbObjectPointer()
    : McDbObjectPointerBase<T_OBJECT>()
{
}

template<class T_OBJECT> inline
McDbObjectPointer<T_OBJECT>::McDbObjectPointer(
    McDbObjectId   objId,
    McDb::OpenMode mode,
    bool           openErased)
    : McDbObjectPointerBase<T_OBJECT>(objId, mode, openErased)
{
}



// -------------------------------------------------------------------------
// Summary:
// 		符号表智能指针
// Remarks:
// 		自动打开数据库的符号表对象，在析构时关闭对象
// 		例如:下面是打开当前数据库的块表代码：
// 		<code>
// 			McDbSymbolTablePointer<McDbBlockTable> spBlkTable(acdbCurDwg(),McDb::kForRead);
// 			if(spBlkTable.openStatus() == Mcad::eOk)
// 			{
// 				// 打开成功，做后面的操作...
// 			}
// 		</code>
// -------------------------------------------------------------------------
template<class T_OBJECT>
class McDbSymbolTablePointer : public McDbObjectPointerBase<T_OBJECT>
{
public:
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// -------------------------------------------------------------------------
    McDbSymbolTablePointer();
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// Parameters:
	// 		objId	-	符号表对象id
	//		mode	-	打开方式
	// -------------------------------------------------------------------------
    McDbSymbolTablePointer(McDbObjectId objId, McDb::OpenMode mode);

	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// Parameters:
	// 		pDb	-	被打开的符表所在的数据库
	//		mode	-	打开方式
	// -------------------------------------------------------------------------
    McDbSymbolTablePointer(McDbDatabase * pDb, McDb::OpenMode mode);

	//:Ignore

private:
    // Copy and assignment prohibited.
    McDbSymbolTablePointer(McDbSymbolTablePointer & pObject);
    McDbSymbolTablePointer& operator=(McDbSymbolTablePointer & pObject);

    // Restrict T_OBJECT to McDbSymbolTable and derived classes.
    //typename T_OBJECT::RecordType T2;
	//:End Ignore
};

class McDbRegAppTable;
class McDbDimStyleTable;
class McDbViewportTable;


// -------------------------------------------------------------------------
// Summary:
// 		块表智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbBlockTable>     McDbBlockTablePointer;

// -------------------------------------------------------------------------
// Summary:
// 		层表智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbLayerTable>     McDbLayerTablePointer;

// -------------------------------------------------------------------------
// Summary:
// 		线型表智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbLinetypeTable>  McDbLinetypeTablePointer;

// -------------------------------------------------------------------------
// Summary:
// 		文字样式智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbTextStyleTable>  McDbTextStyleTablePointer;

// -------------------------------------------------------------------------
// Summary:
// 		应用程序名表智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbRegAppTable>  McDbRegAppTablePointer;

// -------------------------------------------------------------------------
// Summary:
// 		标注风格表智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbDimStyleTable> McDbDimStyleTablePointer;


// -------------------------------------------------------------------------
// Summary:
// 		视口表智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTablePointer<McDbViewportTable> McDbViewportTablePointer;


// -------------------------------------------------------------------------
// Summary:
// 		符号表记录智能指针
// Remarks:
// 		自动打开数据库的符号表记录对象，在析构时关闭对象
// 		例如:打开当前数据库的模型空间的块表记录代码
// 		<code>
// 			McDbSymbolTableRecordPointer<McDbBlockTableRecord> spBlkRec(MCDB_MODEL_SPACE,
// 																		acdbCurDwg(),McDb::kForRead);
// 			if(spBlkRec.openStatus() != Mcad::eOk)
// 			{
// 				// 打开失败
// 				return;
// 			}
// 		</code>
// -------------------------------------------------------------------------
template<class T_OBJECT>
class McDbSymbolTableRecordPointer : public McDbObjectPointerBase<T_OBJECT>
{
public:
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// -------------------------------------------------------------------------
    McDbSymbolTableRecordPointer();

	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// Parameters:
	// 		objId		-	符号表对象id
	//		mode		-	打开方式
	//		openErased	-	是否打开删除的对象
	// -------------------------------------------------------------------------
    McDbSymbolTableRecordPointer(McDbObjectId   objId,
                                 McDb::OpenMode mode,
                                 bool           openErased = false);
	
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// Parameters:
	//		Name		-		符号表记录名称
	//		pDb		 	- 		数据库对象指针
	//		mode        -		对象的打开方式
	//		openErased  - 		删除后的对象是否也打开
	// -------------------------------------------------------------------------
    McDbSymbolTableRecordPointer(LPCMSTR   name,
                                 McDbDatabase * pDb,
                                 McDb::OpenMode mode,
                                 bool           openErased = false);

	//:Ignore

private:
    // Copy and assignment prohibited.
    McDbSymbolTableRecordPointer(McDbSymbolTableRecordPointer & pObject);
    McDbSymbolTableRecordPointer&
                       operator=(McDbSymbolTableRecordPointer & pObject);

    // Restrict T_OBJECT to McDbSymbolTableRecord and derived classes.
    //typename T_OBJECT::TableType T2;
	//:End Ignore
};

class McDbRegAppTableRecord;

class McDbDimStyleTableRecord;

class McDbViewportTableRecord;

// -------------------------------------------------------------------------
// Summary:
// 		块表记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbBlockTableRecord>
                                     McDbBlockTableRecordPointer;

// -------------------------------------------------------------------------
// Summary:
// 		层表记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbLayerTableRecord>
McDbLayerTableRecordPointer;

// -------------------------------------------------------------------------
// Summary:
// 		线型表记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbLinetypeTableRecord>
McDbLinetypeTableRecordPointer;

// -------------------------------------------------------------------------
// Summary:
// 		文字风格表记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbTextStyleTableRecord>
McDbTextStyleTableRecordPointer;

// -------------------------------------------------------------------------
// Summary:
// 		应用程序名表记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbRegAppTableRecord>
McDbRegAppTableRecordPointer;

// -------------------------------------------------------------------------
// Summary:
// 		标注风格记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbDimStyleTableRecord>
McDbDimStyleTableRecordPointer;


// -------------------------------------------------------------------------
// Summary:
// 		视口表记录智能指针
// -------------------------------------------------------------------------
typedef McDbSymbolTableRecordPointer<McDbViewportTableRecord>
McDbViewportTableRecordPointer;

template<class T_OBJECT> inline
McDbSymbolTablePointer<T_OBJECT>::McDbSymbolTablePointer()
    : McDbObjectPointerBase<T_OBJECT>()
{
}

template<class T_OBJECT> inline
McDbSymbolTablePointer<T_OBJECT>::McDbSymbolTablePointer(
    McDbObjectId   objId,
    McDb::OpenMode mode)
    : McDbObjectPointerBase<T_OBJECT>(objId, mode, Mdesk::kFalse)
{
}

template<class T_OBJECT> inline
McDbSymbolTablePointer<T_OBJECT>::McDbSymbolTablePointer(
    McDbDatabase * pDb,
    McDb::OpenMode mode)
    : McDbObjectPointerBase<T_OBJECT>()
{
	 McDbObjectPointerBase<T_OBJECT>::m_status = (pDb == NULL) ? Mcad::eNullObjectPointer
                             : pDb->getSymbolTable(McDbObjectPointerBase<T_OBJECT>::m_ptr, mode);
}

template<class T_OBJECT> inline
McDbSymbolTableRecordPointer<T_OBJECT>
    ::McDbSymbolTableRecordPointer()
    : McDbObjectPointerBase<T_OBJECT>()
{
}

template<class T_OBJECT> inline
McDbSymbolTableRecordPointer<T_OBJECT>
    ::McDbSymbolTableRecordPointer(
    McDbObjectId   objId,
    McDb::OpenMode mode,
    bool           openErased)
    : McDbObjectPointerBase<T_OBJECT>(objId, mode, openErased)
{
}

template<class T_OBJECT> inline
McDbSymbolTableRecordPointer<T_OBJECT>
    ::McDbSymbolTableRecordPointer(
		LPCMSTR   name,
    McDbDatabase * pDb,
    McDb::OpenMode mode,
    bool           openErased)
    : McDbObjectPointerBase<T_OBJECT>()
{
    if (name == NULL)
    	McDbObjectPointerBase<T_OBJECT>::m_status = Mcad::eInvalidInput;
    else {
        McDbSymbolTablePointer< typename T_OBJECT::TableType>
            pTable(pDb, McDb::kForRead);
        McDbObjectPointerBase<T_OBJECT>::m_status = pTable.openStatus();
        if (McDbObjectPointerBase<T_OBJECT>::m_status == Mcad::eOk)
        	McDbObjectPointerBase<T_OBJECT>::m_status = pTable->getAt(name, McDbObjectPointerBase<T_OBJECT>::m_ptr, mode, openErased);
    }
}
