
#include "PreserveUpdater.h"

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <list>

using namespace std;

#define DB_INFORMATION_UPDATE_INTERVAL      300 // sec
//#define DB_INFORMATION_UPDATE_INTERVAL      1 // sec
#define DEFAULT_QUERY_BUFFER_SIZE           1024
#define DEFAULT_PRESERVE_DAY           3

CPreserveUpdater::CPreserveUpdater( )
{
	    m_pPgSQL = NULL;
}

CPreserveUpdater::~CPreserveUpdater()
{
	DbClose();
    pthread_cancel(m_threadHandle);
}

/// @brief DB 연결 함수.
bool CPreserveUpdater::DbConnect()
{
    if( m_pPgSQL != NULL )
    {
        DbClose();
    }
    m_pPgSQL = new DataBase;
	if( m_pPgSQL == NULL )
	{
		LOG(LERR, "Creating new Database has failed.");
		return false;
	}
	if( m_pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
	{
		LOG(LERR, "Connecting to Database has failed.");
		DbClose();
		return false;
	}
    return true;
}

/// @breif DB close 함수.
void CPreserveUpdater::DbClose()
{
	if( m_pPgSQL != NULL )
	{
		delete m_pPgSQL;
        m_pPgSQL = NULL;
	}
}

bool CPreserveUpdater::ThreadInit()
{
    FUNC_BEGIN();
    DataBase * pPgSQL = new DataBase;
	if (pPgSQL == NULL)
	{
		LOG(LERR, "Creating new Database has failed.");
		return false;
	}
    
	m_szHost = CProcessStatus::GetInstance()->GetRcdbIp();
	m_nPort = CProcessStatus::GetInstance()->GetRcdbPort(); 
	m_szDBName = CProcessStatus::GetInstance()->GetRcdbName(); 
	m_szAcct = CProcessStatus::GetInstance()->GetRcdbAcct(); 
	m_szPasswd = CProcessStatus::GetInstance()->GetRcdbAcctPw();
	
	// 최초 초기화 시에는 DB연결 정보들이 제대로 되는것인지에 대한 
	// 확인만 처리 한다.
    if (pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
	{
		LOG(LERR, "Connecting to Database has failed.");
		if (pPgSQL != NULL) 
		{
			delete pPgSQL;
			pPgSQL = NULL;
		}
		return false;
	}
	
	if (pPgSQL != NULL) 
	{
		delete pPgSQL;
		pPgSQL = NULL;
	}
    
	FUNC_END();
	return true;
}

bool CPreserveUpdater::PreserveUpdate()
{
	FUNC_BEGIN();
	std::list<CPreserve> listPreserve;
	
	if( m_pPgSQL == NULL )
	{
		LOG(LWAR, "Not initialized.");
		return false;
	}
	
	// Query 문장 저장을 위한 버퍼 생성
	char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
	int nResult = 0;
    
	snprintf(szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
			"SELECT sp_svc_tran_id, del_file_keep_time "
			"FROM t_sms_sp_svc_product; "
			);
    
    LOG( LDEV, "Preserve Query : [%s]", szQuery );
    
	// Query 실행 
	m_pPgSQL->PgDoExec(szQuery);
	nResult = m_pPgSQL->PgResult( DataBase::NOT_CLEAR );
	
	if( nResult < 0 )
	{
		// RCDB t_sms_sp_svc_product 테이블상에 preserv_day 컬럼이 존재하지 않는 경우
		// Replication 처리를 당장 수행할 필요가 없으므로 루프 대기처리후 다음에 다시 조회처리.		
		if( m_pPgSQL != NULL )
		{
			LOG(LWAR, "RCDB t_sms_sp_svc_product, del_file_keep_time column get failed.[%d][%s]", nResult, m_pPgSQL->GetErrorMessage().c_str() );
            
			m_pPgSQL->PgClear();
            DbClose();
		}
		
		return false;
	}
    
	nResult = m_pPgSQL->GetNoTuples();
    
	// 조회된 정보를 listPreserve 에 저장처리.
	for( int i =0 ; i< nResult; i++ )
	{
		CPreserve objPreserve;
		
	    LOG( LDBG, "sp_svc_tran_id [%d], preserve_day[%d] ", atoi( m_pPgSQL->GetValue(i,0)), atoi( m_pPgSQL->GetValue(i,1))  );
	    objPreserve.m_szServiceID = m_pPgSQL->GetValue(i,0);
	    objPreserve.m_nPreserveDay = atoi( m_pPgSQL->GetValue(i,1) );
	    if( objPreserve.m_nPreserveDay <= 0 )
		{
	    	objPreserve.m_nPreserveDay = DEFAULT_PRESERVE_DAY;
	    }
	    
	    listPreserve.push_back(objPreserve);
	}
	
	// ProcessStatus 객체에 값을 넣어 준다.
	CProcessStatus::GetInstance()->SetPreserveList(listPreserve);
	
	// Query Result set Clear.
	m_pPgSQL->PgClear();
	
	FUNC_END();
	return true;
}

///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CPreserveUpdater::Execute()
{
	FUNC_BEGIN();
	// 아래 함수에서 return false 가 되더라도 무시한다.
	// 본 쓰레드 내에서 계속 재시도 할 수 있도록 한다.
	// Notify : 해당 함수에서 로깅처리됨
	
	
	while(1)
	{
	// 아래 함수에서 return false 가 되면 기존 세션에대해 정리한 후
	// DB Connection을 다시 요청한다.
		if ( DbConnect() == false){;}
		if( PreserveUpdate() == false )
		{
			// 한 번더 정리한 후 
			DbClose();
			sleep( 1 );
			continue;
		}
		DbClose();
		sleep( DB_INFORMATION_UPDATE_INTERVAL );
	}
	
	// 쓰레드 종료 될 때 DB 세션 정리 한다.
	DbClose();
	
	LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
	FUNC_END();
}

void* CPreserveUpdater::EntryPoint(void* arg)
{
    CPreserveUpdater* pObject = reinterpret_cast<CPreserveUpdater *>(arg);
	pthread_detach( pthread_self() );
    
	pthread_testcancel();
	pObject->Execute();
	pthread_testcancel();
	
	FUNC_END();
	return 0;
}

bool CPreserveUpdater::Start()
{
	int nRet = ::pthread_create(&m_threadHandle, 0, CPreserveUpdater::EntryPoint, this);

	if( nRet )
	{
		LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
		return false;
	}
    LOG(LDBG, "Thread create succeed");
	sleep(0);
	return true;
}
