/***************************************************************************
                   DB Manager Class (DBManager.cpp)
                -----------------------------------------

	begin      : 2013/06/04
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/06/04 - 1st dadamin
	email      : dev1@solbox.com
	version    : 3.2.0

	CopyRight(C) 2005 Solbox Inc. All Rights reserved.
	Redistribution and use in source and binary forms, with or with out
	modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "cc_statd.h"
#include "DBManager.h"
#include "Configs.h"
#include "Logger.h"

static string toLowerCaseSTD(string str)
{
	string ret;
	ret.resize(str.size());
	transform(str.begin(), str.end(), ret.begin(), ::tolower);
	return ret;
}

// class CDBPools
CDBPools::CDBPools()
	: m_size(0), m_dbtype(""), m_comstr(""), m_pool(NULL)
{
}

CDBPools::~CDBPools()
{
}

bool CDBPools::Create(string dbtype, int size, string comstr)
{
	ostringstream msg;
	try
	{
		m_size = size;
		m_comstr = comstr;
		m_dbtype = dbtype;
		m_pool = new connection_pool(m_size);
		if(m_pool == NULL)
		{
			msg << "Memory allocation failed.";
			LOGACONSOLE(LERR, msg);
			return false;
		}

		for (size_t i = 0; i != m_size; ++i)
		{
			session & sql = m_pool->at(i);
			//sql.open(toLowerCaseSTD(m_dbtype), comstr);
			// 2014.11.24 SOCI static library 사용 하기 위한 방법
			if(m_dbtype == "POSTGRESQL" )
			{
				sql.open(*soci::factory_postgresql(), comstr);
			}
			else
			{
				msg << "The type is not supported.";
				msg << "[" <<  dbtype << "]";
				LOGACONSOLE(LERR, msg);
				return false;
			}

		}
	}
	catch (soci_error const &e)
	{
		if(m_pool)
		{
			delete m_pool;
			m_pool = NULL;
		}
		msg << "Failed to create the database connection pool. ";
		msg << "[" <<  dbtype << "," <<  comstr <<"]";
		LOGACONSOLE(LERR, msg);
		msg << "Database Error message : " << e.what();
		LOGACONSOLE(LERR, msg);
		return false;
	}
	return true;
}

void CDBPools::Finalized()
{
	_LOG(LDEV1, "DB Pool Stop.");
	ostringstream msg;
	try
	{
		if(m_pool)
		{
			delete m_pool;
			m_pool = NULL;
		}
	}
	catch (soci_error const &e)
	{
		msg << "Error message : " << e.what();
		LOGACONSOLE(LERR, msg);
	}
}

bool CDBPools::GetDB(size_t & pos, int timeout /*= DB_POO_TIMEOUT */)
{
	ostringstream msg;
	try
	{
		if(m_pool->try_lease(pos, timeout) == false)
		{
			msg << "Acquired DB Pool timeout.";
			LOGACONSOLE(LERR, msg);
			return false;
		}
	}
	catch (soci_error const &e)
	{
		msg << "Error message : " << e.what();
		LOGACONSOLE(LERR, msg);
		return false;
	}	

	return true;
}

void CDBPools::ReleaseDB(size_t pos)
{
	ostringstream msg;
	try
	{
		m_pool->give_back(pos);
	}
	catch (soci_error const &e)
	{
		msg << "Error message : " << e.what();
		LOGACONSOLE(LERR, msg);
	}
}

// class CDBManager
CDBManager::CDBManager()
	: m_dbCnt(0)
{
}

CDBManager::~CDBManager()
{
}

bool CDBManager::CreatePool(string sDBtype, string sUsed, CDataBaseInfo& info)
{
	++m_dbCnt;
	_LOG(LDBG, "PID[%d] DB Pool type = %s, used = %s, info = %s:%d",
			getpid(), sDBtype.c_str(), sUsed.c_str(), 
			info.m_connstr.c_str(), info.m_poolcnt);

	map<string, CDBPools> m;
	pair<map<string, CDBPools>::iterator,bool> ret;
	pair< map<string, map<string, CDBPools > >::iterator,bool> r;

	r = m_manager.insert(make_pair(sDBtype, m));
	
	bool re = true;
	ret = r.first->second.insert(make_pair(sUsed, CDBPools()));
	if(ret.second == false)
	{
		re = false;
		LOG(LERR, "Failed to create the map [%s] dupliaion.", sUsed.c_str());
	}
	else
	{
		re = ret.first->second.Create(sDBtype, info.m_poolcnt, info.m_connstr);
	}
	
	return re;
}

void CDBManager::Finalized()
{
	_LOG(LDEV1, "DB Manager Finalized.");
	map<string, map<string, CDBPools> >::iterator m;

	m = m_manager.begin();
	while(m != m_manager.end())
	{
		map<string, CDBPools>::iterator it = m->second.begin();

		while( it != m->second.end())
		{
			it->second.Finalized();
			it ++;
		}
		m->second.clear();
		m ++;
	}

	m_manager.clear();
}

CDBPools * CDBManager::GetDBPool(string sDBtype, string sUsed)
{
	CDBPools *r = NULL;

	map<string, map<string, CDBPools> >::iterator find ;

	find = m_manager.find(sDBtype);

	if(find != m_manager.end())
	{
		map<string, CDBPools>::iterator f;
		f = find->second.find(sUsed);
		if(f != find->second.end() )
		{
			r = &f->second;
		}
	}

	return r;
}
