/***************************************************************************
                   Config Class (Config.cpp)
                -----------------------------------------

	begin      : 2013/05/28
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/05/28 - 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 "Configs.h"
#include "Config.h"

CMyConfig *CMyConfig::m_pInstance = NULL;

void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty /*= false*/)
{
	const string strEmpty("");
	string::size_type cutAt;

	while( (cutAt = str.find_first_of(delim)) != str.npos )
	{
		if(cutAt > 0)
		{
			results.push_back(str.substr(0,cutAt));
		}
		else
		{
			if(bUseEmpty && cutAt == 0)
				results.push_back(strEmpty);
		}
		str = str.substr(cutAt+1);
	}
	if(str.length() > 0)
	{
		results.push_back(str);
	}
}

CCommonConfig::CCommonConfig( string szFilename, string szProgramName )
	: m_szConfigFile(szFilename), m_szProgramName(szProgramName), m_nLogLevel(0)
{
}

CCommonConfig::~CCommonConfig()
{
}

bool CCommonConfig::LoadConf()
{
#ifdef _DEBUG
	cout << "CCommonConfig::LoadConf() =>" << endl;
#endif // _DEBUG
	string szValue;

	// Config 처리를 위한 객체 생성
	Config conf;

	// Config File open
	if( conf.Open( m_szConfigFile ) == false )
	{
		m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
		return false;
	}

	// log path
	if( conf.GetConfig( "COMMON", "DEFAULT_LOG_DIR", szValue ) )
	{
		m_szAppLogRoot = szValue;
	}

	// log level
	if( conf.GetConfig( "COMMON", "LOG_LEVEL", szValue ) )
	{
		m_nLogLevel = atoi( szValue.c_str() );
	}

#ifdef _DEBUG
	PrintValue();
#endif // _DEBUG

	return true;
}

bool CCommonConfig::CheckValue()
{
	if(m_szAppLogRoot.empty())
	{
		m_szErrMessage  = "Config info get failed. [" + m_szProgramName + " or COMMON]->DEFAULT_LOG_DIR";
		return false;
	}

	if( m_nLogLevel <= 0)
	{
		m_szErrMessage  = "Config info get failed. [" + m_szProgramName + " or COMMON]->LOG_LEVEL";
		return false;
	}

	return true;	
}

void CCommonConfig::PrintValue()
{
	cout << "Log   Value : " << m_szAppLogRoot << "," << m_nLogLevel << endl;
}

CMyConfig::CMyConfig( string szFilename, string szProgramName)
	: CCommonConfig(szFilename, szProgramName)
	, m_TcpListenPort(0), m_WorkProcessCnt(0), m_WorkThreadCnt(1000)
{
}

CMyConfig::~CMyConfig()
{
}

bool CMyConfig::LoadConf()
{
	if( CCommonConfig::LoadConf() == false)
		return false;
#ifdef _DEBUG
	cout << "CMyConfig::LoadConf() =>" << endl;
#endif // _DEBUG
	string szValue;

	// Config 처리를 위한 객체 생성
	Config conf;

	// Config File open
	if( conf.Open( m_szConfigFile ) == false )
	{
		m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
		return false;
	}

	// Config File open
	if( conf.GetConfig( m_szProgramName, "DEFAULT_LOG_DIR", szValue ) )
	{
		m_szAppLogRoot = szValue;
	}

	// log level
	if( conf.GetConfig( m_szProgramName, "LOG_LEVEL", szValue ) )
	{
		m_nLogLevel = atoi( szValue.c_str() );
	}
	
	// TCP Listen Port
	if(conf.GetConfig( m_szProgramName, "TCP_LISTEN_PORT", szValue ))
	{
		m_TcpListenPort = atoi( szValue.c_str() );
	}

	// Work Process Count
	if(conf.GetConfig( m_szProgramName, "WORK_PROCESS_CNT", szValue ))
	{
		m_WorkProcessCnt = atoi( szValue.c_str() );
	}

	// Work Thread Pool Count
	if(conf.GetConfig( m_szProgramName, "WORK_THREAD_POOL", szValue ))
	{
		m_WorkThreadCnt = atoi( szValue.c_str() );
	}

	// Used DataBase Type
	//string k = "=";
	//conf.SetDelimiter()

	if(conf.GetConfig(m_szProgramName, "USED_DATABASE_TYPE", m_usedDBTypeVec))
	{		
	}

	// Database info
	for (vector<string>::iterator it = m_usedDBTypeVec.begin() ; it != m_usedDBTypeVec.end(); ++it)
	{
		vector< string >  vec;
		string t;
		t.append(*it);
		t.append("_DB_INFO");
#ifdef _DEBUG
		cout << " "<<t ;
#endif // _DEBUG
		conf.GetConfig(m_szProgramName, t, vec);
#ifdef _DEBUG
		cout << ",size(" << vec.size() << ")" << endl ;
#endif // _DEBUG
		map<string, CDataBaseInfo> infos;
		for (vector<string>::iterator it2 = vec.begin() ; it2 != vec.end(); ++it2)
		{
#ifdef _DEBUG
			cout << "  " << *it2 << endl ;
#endif // _DEBUG

			vector< string >  vec2;
			StringSplit(*it2, "|", vec2, true);

			if( vec2.size() < 3 )
			{
				cerr << "Configuration file is wrong." << endl ;
				continue;
			}
			CDataBaseInfo info; 
			info.m_poolcnt = atoi(vec2[1].c_str());
			info.m_connstr = vec2[2];

			pair< map<string, CDataBaseInfo>::iterator, bool > r;

			r = infos.insert(make_pair(vec2[0], info));
			if(r.second == false)
			{
				cerr << "Configuration file is error. ["<< t << "] is duplicated.(" 
					<< vec2[0] << ")" << endl ;
				return false;
			}
		}

		if(infos.size())
			m_DBInfoMap.insert(make_pair(*it, infos));
	}

#ifdef _DEBUG
	PrintValue();
#endif // _DEBUG
	return true;
}

bool CMyConfig::CheckValue()
{
	if( CCommonConfig::CheckValue() )
	{
		if( m_TcpListenPort <= 0)
		{
			m_szErrMessage  = "Config info get failed. [" + m_szProgramName + "]->TCP_LISTEN_PORT";
			return false;
		}

		if( m_WorkProcessCnt <= 0)
		{
			m_szErrMessage  = "Config info get failed. [" + m_szProgramName + "]->WORK_PROCESS_CNT";
			return false;
		}

		if( m_WorkThreadCnt <= 0)
		{
			// 해당 값은 gts.conf에 숨기기 위해서 값이 없을 시 무시
			//m_szErrMessage  = "Config info get failed. [" + m_szProgramName + "]->WORK_THREAD_POOL ";
			//return false;
		}

		if(m_usedDBTypeVec.size() <= 0)
		{
			m_szErrMessage  = "Config info get failed. [" + m_szProgramName + "]->USED_DATABASE_TYPE";
			return false;
		}

		for (vector<string>::iterator it = m_usedDBTypeVec.begin() ; it != m_usedDBTypeVec.end(); ++it)
		{
			map<string, map<string, CDataBaseInfo> >::iterator mitFind;
			mitFind = m_DBInfoMap.find(*it);
			if(mitFind == m_DBInfoMap.end() || mitFind->second.size() <= 0)
			{
				m_szErrMessage  = "Config info get failed. [" + m_szProgramName + "]->"+ *it + "_DB_INFO";
				return false;
			}
		}		

		return true;
	}
	else 
	{
		return false;
	}

	return true;
}

bool CMyConfig::FindUsedDBType(string &k)
{
	// find 
	vector<string>::iterator i = 
		find(m_usedDBTypeVec.begin(), m_usedDBTypeVec.end(), k);

	if (i!= m_usedDBTypeVec.end()) 
	{
		// found it
		return true;
	} 
	else 
	{
		// doesn't exist
		return false;		
	}

	return true;
}

void CMyConfig::PrintValue()
{
	CCommonConfig::PrintValue();

	cout << "TCP Listen Port :" << m_TcpListenPort << endl;
	cout << "Work Process Count :" << m_WorkProcessCnt << endl;
	cout << "Work Thread Count :" << m_WorkThreadCnt << endl;
	cout << "Used Database Type : size(" << m_usedDBTypeVec.size() << ")" << endl;
	for (vector<string>::iterator it = m_usedDBTypeVec.begin() ; it != m_usedDBTypeVec.end(); ++it)
	{
		cout << " " << *it << endl;
	}

	cout << "Database info : size(" << m_DBInfoMap.size() << ")" << endl;
	for (map<string, map<string, CDataBaseInfo> >::iterator iter = m_DBInfoMap.begin() ; iter != m_DBInfoMap.end(); ++iter)
	{
		cout << " " << iter->first << endl;
		for( map<string, CDataBaseInfo>::iterator iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2)
		{
			cout << "  " << iter2->first << ","<< iter2->second.m_poolcnt << "," << iter2->second.m_connstr << endl;
		}
	}
}

void CMyConfig::SetFailLogPath(string & path)
{
	m_FailLogPath = path;

	// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
	string cmd = "mkdir -p " + path;
	system( cmd.c_str() );
}

bool CMyConfig::Init( string szProgramName, string szFilename )
{
	if( CMyConfig::m_pInstance == NULL )
	{
		CMyConfig::m_pInstance = new CMyConfig(szFilename, szProgramName);
	}

	return true;
}

void CMyConfig::Exit()
{
	if( CMyConfig::m_pInstance != NULL )
	{
		delete CMyConfig::m_pInstance;
		CMyConfig::m_pInstance = NULL;
	}
}

CMyConfig* CMyConfig::GetInstance()
{
	return CMyConfig::m_pInstance;
}
