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

	begin      : 2013/07/09
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/07/09 - 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 "Insert.h"
#include "DataDefine.h"
#include "Configs.h"
#include "Logger.h"

#define  TIME_STRING_LAN		30

// 
void CInsert::timeToString(time_t stamp, char *buf)
{
	struct tm *_tm;

	_tm = localtime(&stamp);
	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", (1900 + _tm->tm_year),
		(_tm->tm_mon + 1), _tm->tm_mday, _tm->tm_hour,
		_tm->tm_min, _tm->tm_sec);
}

bool CInsert::run(string strsql, session & sql)
{
	bool r = true;
	ostringstream msg;
	try
	{
		sql << strsql;
		if (sql.get_backend_name() == "oracle")
		{
			sql.commit();
		}
	}
	catch (soci_error const &e)
	{
		r = false;
		msg << "Error message : " << e.what();
		msg << "SQL : " << strsql;
		LOGACONSOLE(LERR, msg);
		
	}

	if(r == false )
	{
		bool f = false;
		try
		{
			sql.rollback();			
		}
		catch (soci_error const &e)
		{
			f = true;
			msg << "Error(rollback) message : " << e.what();
			LOGACONSOLE(LERR, msg);					
		}

		if(f)
		{
			try
			{
				sql.reconnect();
				msg << "Success database reconnection.";
				LOGACONSOLE(LWAR, msg);
			}
			catch (soci_error const &e)
			{
				msg << "Error(reconnect) message : " << e.what();
				LOGACONSOLE(LERR, msg);		
			}
		}
	}	

	return r;
}

// Postgresql
bool CInsertPostgresqlAccess::Insert(map <string, string > &svc, map <string, string > &val, session & sql)
{
	LOG(LDEV1, "Insert : %s-%s", USED_TYPE_POSTGRESQL, XML_STAT_ACCESS );
	
	ostringstream sqlstr;

	char szTimeStr[TIME_STRING_LAN] = {0};
	time_t t = atoi(val[XML_STAT_TIME].c_str()) * 300 ;
	timeToString(t, szTimeStr);

	/* side : cs_stat_access */
	sqlstr << "INSERT INTO cs_stat.cs_stat_access "
		<<		"("
		<<		"reg_date, "
		<<		"user_seq, svc_seq, rc_id, "
		<<		"up_success_count, down_success_count, "
		<<		"up_auth_fail_count, down_auth_fail_count, "		
		<<		"up_illegal_req_count, down_illegal_req_count, "
		<<		"up_timeout_count, down_timeout_count, "
		<<		"up_disconnect_count, down_disconnect_count"
		<<		") "
		<< "VALUES "
		<< "(" 
		<< "'" << szTimeStr << "', "
		<< svc[XML_SVC_USER_SEQ] << ", "
		<< svc[XML_SVC_SEQ] << ", "
		<< "'" << svc[XML_SVC_RC] << "',"
		<< val[XML_STAT_ACCESS_UP_SUCCESS_COUNT]			<<  ", "  
		<< val[XML_STAT_ACCESS_DOWN_SUCCESS_COUNT]			<<  ", "  
		<< val[XML_STAT_ACCESS_UP_AUTH_FAIL_COUNT]			<<  ", "  
		<< val[XML_STAT_ACCESS_DOWN_AUTH_FAIL_COUNT]		<<  ", "  
		<< val[XML_STAT_ACCESS_UP_ILLEGAL_REQ_COUNT]		<<  ", "  
		<< val[XML_STAT_ACCESS_DOWN_ILLEGAL_REQ_COUNT]		<<  ", "  
		<< val[XML_STAT_ACCESS_UP_TIMEOUT_COUNT]			<<  ", "  
		<< val[XML_STAT_ACCESS_DOWN_TIMEOUT_COUNT]			<<  ", "  
		<< val[XML_STAT_ACCESS_UP_DISCONNECT_COUNT]			<<  ", "  
		<< val[XML_STAT_ACCESS_DOWN_DISCONNECT_COUNT]		<< ""
		<<  ")";

	return run(sqlstr.str(), sql);
}

bool CInsertPostgresqlStorage::Insert(map <string, string > &svc, map <string, string > &val, session & sql)
{
	LOG(LDEV1, "Insert : %s-%s", USED_TYPE_POSTGRESQL, XML_STAT_STORAGE );
	ostringstream sqlstr;
	
	char szTimeStr[TIME_STRING_LAN] = {0};
	time_t t = atoi(val[XML_STAT_TIME].c_str()) * 300 ;
	timeToString(t, szTimeStr);

	/* side : cs_stat_storage */
	sqlstr << "INSERT INTO cs_stat.cs_stat_storage "
		<<		"("
		<<		"reg_date, "
		<<		"user_seq, svc_seq, rc_id, "
		<<		"stg_size, used_stg_size"		
		<<		") "
		<< "VALUES "
		<< "(" 
		<< "'" << szTimeStr << "', "
		<< svc[XML_SVC_USER_SEQ] << ", "
		<< svc[XML_SVC_SEQ] << ", "
		<< "'" << svc[XML_SVC_RC] << "',"
		<< val[XML_STAT_STORAGE_STG_SIZE]			<<  ", "  
		<< val[XML_STAT_STORAGE_USED_STG_SIZE]		<<  ""  
		<<")";

	return run(sqlstr.str(), sql);
}

bool CInsertPostgresqlNetwork::Insert(map <string, string > &svc, map <string, string > &val, session & sql)
{
	LOG(LDEV1, "Insert : %s-%s", USED_TYPE_POSTGRESQL, XML_STAT_NETWORK );
	ostringstream sqlstr;
	
	char szTimeStr[TIME_STRING_LAN] = {0};
	time_t t = atoi(val[XML_STAT_TIME].c_str()) * 300 ;
	timeToString(t, szTimeStr);

	/* side : cs_stat_network */
	sqlstr << "INSERT INTO cs_stat.cs_stat_network "
		<<		"("
		<<		"reg_date, "
		<<		"user_seq, svc_seq, rc_id, "
		<<		"up_traffic, down_traffic, "
		<<		"up_size, down_size, "
		<<		"up_concurrent_sess, down_concurrent_sess"
		<<		") "
		<< "VALUES "
		<< "("
		<< "'" << szTimeStr << "', "
		<< svc[XML_SVC_USER_SEQ] << ", "
		<< svc[XML_SVC_SEQ] << ", "
		<< "'" << svc[XML_SVC_RC] << "',"
		<< val[XML_STAT_NETWORK_UP_TRAFFIC]				<<  ", "  
		<< val[XML_STAT_NETWORK_DOWN_TRAFFIC]			<<  ", "  
		<< val[XML_STAT_NETWORK_UP_SIZE]				<<  ", "  
		<< val[XML_STAT_NETWORK_DOWN_SIZE]				<<  ", " 
		<< val[XML_STAT_NETWORK_UP_CONCURRENT_SESS]		<<  ", "  
		<< val[XML_STAT_NETWORK_DOWN_CONCURRENT_SESS]	<<  "" 
		<<")";

	return run(sqlstr.str(), sql);
}

bool CInsertPostgresqlTransfer::Insert(map <string, string > &svc, map <string, string > &val, session & sql)
{
	LOG(LDEV1, "Insert : %s-%s", USED_TYPE_POSTGRESQL, XML_STAT_TRANSFER );
	ostringstream sqlstr;
	char szBeginTimeStr[TIME_STRING_LAN] = {0};
	char szEndTimeStr[TIME_STRING_LAN] = {0};

	time_t t1 = atoi(val[XML_STAT_TRANSFER_START_DATE].c_str()) ;
	time_t t2 = atoi(val[XML_STAT_TRANSFER_END_DATE].c_str()) ;
	timeToString(t1, szBeginTimeStr);
	timeToString(t1, szEndTimeStr);
	
	/* side : cs_stat_transfer */
	sqlstr << "INSERT INTO cs_stat.cs_stat_transfer "
		<<		"("
		<<		"reg_date, "
		<<		"user_seq, svc_seq, rc_id, "
		<<		"session_id, "
		<<		"content_name, transfer_size, direction, "
		<<		"start_date, end_date, response_code"
		<< ") "
		<< "VALUES "
		<< "(" 
		<< "NOW(), "
		<< svc[XML_SVC_USER_SEQ] << ", "
		<< svc[XML_SVC_SEQ] << ", "
		<< "'" << svc[XML_SVC_RC] << "',"
		<< "'" << val[XML_STAT_TRANSFER_SESSION_ID]		<<  "', "  
		<< "'" << val[XML_STAT_TRANSFER_CONTENT_NAME]	<<  "', "  
		<< val[XML_STAT_TRANSFER_TRANSFER_SIZE]			<<  ", "  
		<< val[XML_STAT_TRANSFER_DIRECTION]				<<  ", " 
		<< "'" <<	szBeginTimeStr						<<  "', "  
		<< "'" << szEndTimeStr							<<  "', " 
		<< val[XML_STAT_TRANSFER_REPONSE_CODE]			<< ""
		<<  ")";

	return run(sqlstr.str(), sql);
}


// Abstract Factory returning a Insert
CInsert* CInsertFactory::Create(string dbtype, string dtype)
{
	CInsert *r = NULL;

	if(dbtype.find(USED_TYPE_ORACLE) != string::npos)
	{
		// 2014.11.20 : 오라클을 사용하는 곳 없으므로 삭제 처리
		r = NULL;
	}
	else if (dbtype.find(USED_TYPE_POSTGRESQL) != string::npos)
	{
		if( dtype.find(XML_STAT_ACCESS) != string::npos )
		{
			m_dbtype = USED_TYPE_POSTGRESQL;
			m_usedtype = USED_KIND_STAT;
			r = new CInsertPostgresqlAccess;
		}
		else if ( dtype.find(XML_STAT_STORAGE) != string::npos )
		{
			m_dbtype = USED_TYPE_POSTGRESQL;
			m_usedtype = USED_KIND_STAT;
			r = new CInsertPostgresqlStorage;
		}
		else if ( dtype.find(XML_STAT_NETWORK) != string::npos )
		{
			m_dbtype = USED_TYPE_POSTGRESQL;
			m_usedtype = USED_KIND_STAT;
			r = new CInsertPostgresqlNetwork;
		}
		else if ( dtype.find(XML_STAT_TRANSFER) != string::npos )
		{
			m_dbtype = USED_TYPE_POSTGRESQL;
			m_usedtype = USED_KIND_STAT;
			r = new CInsertPostgresqlTransfer;
		}
		else 
		{
			r = NULL;
		}
	}
	else
	{
		r = NULL;
	}

	LOG(LDEV1, "Insert type.[%s::%s::%s]", m_dbtype.c_str(), m_usedtype.c_str(), dtype.c_str());
		
	if(r == NULL)
	{
		LOG(LERR, "Unknown database type.[%s-%s]", dbtype.c_str(), dtype.c_str());
	}

	return r;
}
