#include "StdAfx.h"
#include "WxAdoPool.h"
#include "Global.h"

//////////////////////////////////////////////////////////////////////////
CWxAdoPool::CWxAdoPool()
{
	m_nRef = 0;
	m_nObjRef = 0;

	m_nMaxCount = 0;
	m_nMinCount = 0;

	m_bNeedExit = FALSE;
	m_bNeedStop = FALSE;
	m_bNeedConnection = FALSE;
}

CWxAdoPool::~CWxAdoPool()
{
	m_strDBType.Empty();
	m_strDBAccount.Empty();
	m_strDBName.Empty();
	m_strDBSource.Empty();
	m_strPassWord.Empty();
	DestroyAllDBConnections();
}

DWORD CWxAdoPool::InitializePool(IN LPCTSTR lpDBType, IN LPCTSTR lpDBSource, IN CONST DWORD &dwDBPort, IN LPCTSTR lpDBAccount, IN LPCTSTR lpPassWord, IN LPCTSTR lpDBName, IN CONST INT &nMinConn /* = 1 */, IN CONST INT &nMaxConn /* = 5 */)
{
	if ( !lpDBSource || lpDBSource[0] == _T('\0') || !lpDBName || lpDBName[0] == _T('\0') )
	{
		return 0;
	}

	m_strDBType = lpDBType;
	m_strDBSource = lpDBSource;
	m_dwDBPort = dwDBPort;
	m_strDBAccount = lpDBAccount;
	m_strPassWord = lpPassWord;
	m_strDBName = lpDBName;

	m_nMinCount = nMinConn;
	m_nMaxCount = nMaxConn;

	return IntiAllConnections();
}

void CWxAdoPool::ReleasePool()
{
	DestroyAllDBConnections();
}

INT CWxAdoPool::IntiAllConnections()
{
	DestroyAllDBConnections();

#if USE_ODBC
	// 开始按照最小数量开始创建;
	int nCount = 0;
	CDatabase *pDatabase = NULL;
	for (int i = 0; i < m_nMinCount; i++)
	{
		pDatabase = InitAConnection();
		if ( pDatabase )
		{
			nCount++;
			m_listIdleConnections._push_back(pDatabase);
			InterlockedIncrement(&m_nObjRef);	//增加引用计数;
			pDatabase = NULL;
		}
	}
#else
	int nCount = 0;
	pAdoObj pDatabase = NULL;
	for ( int i = 0; i < m_nMinCount; i++)
	{
		pDatabase = InitAConnection();
		if (pDatabase)
		{
			nCount++;
			m_listIdleConnections._push_back(pDatabase);
			InterlockedIncrement(&m_nObjRef);
			pDatabase = NULL;
		}
	}
#endif

	return nCount;
}

void CWxAdoPool::DestroyAllDBConnections()
{
	m_bNeedExit = TRUE;
	// 首先等待m_listBusyConnections.size() == 0;
	while(1)
	{
		if ( m_listBusyConnections.size() == 0 )
			break;
		Sleep(1000);
	}
	
	pAdoObj pObj = NULL;
	AdoConnList::iterator itIdle = m_listIdleConnections.begin();
	while (itIdle != m_listIdleConnections.end())
	{
		pObj = *itIdle;
		if (NULL != pObj)
		{
 			//if (pObj->pConnection)
 			//{
 			//	pObj->pConnection->Close();
 			//	pObj->pConnection->Release();
 			//}
 
 			//if (pObj->pCommand)
 			//{
 			//	pObj->pCommand->Release();
 			//}
 
 			//if (pObj->pRecordSet)
 			//	pObj->pRecordSet.Release();
#ifdef _DEBUG
			OutputDebugString(_T("删除连接池对象\n"));
#endif
			delete pObj;
			pObj = NULL;
		}
		itIdle = m_listIdleConnections.erase(itIdle);
	}
	
	m_bNeedExit = FALSE;
}

pAdoObj CWxAdoPool::GetAConnection( IN CONST DWORD &dwTimeOut /* = 1000 */ )
{
	if ( m_bNeedExit )// 停止获取;
		return NULL;

	// 1.首先到池中查找有无空闲对象;
	BOOL bGetIdl = FALSE;
	DWORD dwTime = GetTickCount();
	pAdoObj pConnection = NULL;
	do 
	{
		if ( m_listIdleConnections._size() > 0){
			//AutoThreadSection aSection(&m_critSection);
			pConnection = m_listIdleConnections._pop_front_();
			if (pConnection)
			{
				m_listBusyConnections._push_back(pConnection);
				bGetIdl = TRUE;
			}
		}
		else 
		{
			if (m_nObjRef < m_nMaxCount)
			{
				//AutoThreadSection aSection(&m_critSection);
				pConnection = InitAConnection();
				if (pConnection){
					//bGetIdl = TRUE;
					m_listBusyConnections._push_back(pConnection);
					InterlockedIncrement(&m_nObjRef);	//增加引用计数;
					Global::WriteTextLog(_T("创建连接对象：共有 %d 个"), m_nObjRef);
					break;
				}
			}
		}

		if ( !bGetIdl )	{
			// 未找到,小憩一会,防止CPU爆满;
			Sleep(0);
			// 超时,则结束返回NULL;
			if ( (GetTickCount() - dwTime) >= dwTimeOut){
				Global::WriteTextLog(_T("获取连接对象超时"));
				break;
			}
		}
	} while ( !bGetIdl );
	
	return pConnection;
}

void CWxAdoPool::RestoreAConnection(IN pAdoObj pObj)
{
	if (pObj != NULL ){
		m_listBusyConnections._remove(pObj);
		if (pObj->pConnection->GetState() != adStateClosed)
			m_listIdleConnections._push_back(pObj);
		else
			delete pObj;
	}
}

pAdoObj CWxAdoPool::InitAConnection()
{
	if ( m_nObjRef == m_nMaxCount )
		return NULL;

	pAdoObj pObj = new AdoObj;
	pObj->pConnection.CreateInstance(__uuidof(Connection));

	TCHAR szConnString[MAX_PATH] = {0};
	if (m_dwDBPort != 0)
	{
		if ( m_strDBType.CompareNoCase(_T("mssql")) == 0 )
		{
			if ( m_strDBAccount.IsEmpty() )
				_stprintf_s(szConnString, MAX_PATH, DB_SW_CONN_WITH_PORT, m_strDBSource, m_dwDBPort,m_strDBName);
			else
				_stprintf_s(szConnString, MAX_PATH, DB_SS_CONN_WITH_PORT,m_strDBSource, m_dwDBPort, m_strDBName, m_strDBAccount, m_strPassWord);
		}
		else if (m_strDBType.CompareNoCase(_T("mysql")) == 0)
		{
			_stprintf_s(szConnString, MAX_PATH, _T("DRIVER=MariaDB ODBC 3.0 Driver;SERVER=%s;PORT=%d;DATABASE=%s;UID=%s;PWD=%s;"), m_strDBSource, m_dwDBPort, m_strDBName, m_strDBAccount, m_strPassWord);
		}
		else if (m_strDBType.CompareNoCase(_T("psql")) == 0)
		{
		}
		else if (m_strDBType.CompareNoCase(_T("sqlite3")) == 0)
		{
		}
	}
	else
	{
		if ( m_strDBType.CompareNoCase(_T("mssql")) == 0 )
		{
			if ( m_strDBAccount.IsEmpty() )
				_stprintf_s(szConnString, MAX_PATH, DB_SW_CONN_WITHOUT_PORT, m_strDBSource, m_strDBName);
			else
				_stprintf_s(szConnString, MAX_PATH, DB_SS_CONN_WITHOUT_PORT, m_strDBSource, m_strDBName, m_strDBAccount, m_strPassWord);
		}
		else if (m_strDBType.CompareNoCase(_T("mysql")) == 0)
		{
			_stprintf_s(szConnString, MAX_PATH, _T("DRIVER=MariaDB ODBC 3.0 Driver;SERVER=%s;PORT=3306;DATABASE=%s;UID=%s;PWD=%s;"), m_strDBSource, m_strDBName, m_strDBAccount, m_strPassWord);
		}
		else if (m_strDBType.CompareNoCase(_T("psql")) == 0)
		{
		}
		else if (m_strDBType.CompareNoCase(_T("sqlite3")) == 0)
		{
		}
	}

	try
	{
		HRESULT hr = pObj->pConnection->Open(_bstr_t(szConnString), "", "", adModeUnknown);

		if (FAILED(hr))
		{
			if (pObj)
				delete pObj;
			pObj = NULL;
			return NULL;
		}

		pObj->pCommand.CreateInstance(__uuidof(Command));
		// 将库连接赋于它;
		pObj->pCommand->ActiveConnection = pObj->pConnection;
	}
	catch (_com_error &e)
	{
		_bstr_t bstrSource(e.Source());
		_bstr_t bstrDescription(e.Description());
		if (pObj)
			delete pObj;
		pObj = NULL;
		Global::WriteTextLog(_T("SQL连接串：%08lx,%s,%s,%s"), e.Error(), e.ErrorMessage(), (TCHAR*)bstrSource, (TCHAR*)bstrDescription);
	}

	return pObj;
}

void CWxAdoPool::CloseAConnection(pAdoObj &pDataBase)
{
	m_listIdleConnections._remove(pDataBase);
	InterlockedDecrement(&m_nObjRef);	// 减少计数;
	if ( pDataBase )
		delete pDataBase;

	pDataBase = NULL;
}

void CWxAdoPool::CloseBusyConnection(IN pAdoObj &pDataBase)
{
	m_listBusyConnections._remove(pDataBase);
	InterlockedDecrement(&m_nObjRef);	// 减少计数;
	if ( pDataBase )
		pDataBase->pConnection->Close();
}