#include "ContentSelect.h"

#include "Logger.h"

#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>


CContentSelect::CContentSelect()
{
	// thread id 정보 추출
	m_lThreadId = syscall( SYS_gettid );

}

CContentSelect::~CContentSelect()
{
	// rcdb 와 의 연결을 명시적으로 해제
	m_rcdb.PgCloseDB();
}


bool CContentSelect::Start()
{
	// RCDB 접속 정보 load
	m_rcdbInfo.Load();

	// RCDB 와 연결을 시도한다.
	if( m_rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort, m_rcdbInfo.m_strRcdbName
		, m_rcdbInfo.m_strRcdbAcct, m_rcdbInfo.m_strRcdbAcctPw ) == NULL )
	{
		// 연결 실패시...
		_LOG( LERR, "[ContentSelect %d %ld] RCDB connection failed. [%s:%u]"
			, getpid(), m_lThreadId, m_rcdbInfo.m_strRcdbIp.c_str(), m_rcdbInfo.m_nRcdbPort );

		return false;
	}
	else
	{
		// RCDB 연결 정상 처리된 경우...
		_LOG( LDBG, "[ContentSelect %d %ld] RCDB connection ok. [%s:%u]"
			, getpid(), m_lThreadId
			, m_rcdbInfo.m_strRcdbIp.c_str(), m_rcdbInfo.m_nRcdbPort );

	}

	return true;
}

void CContentSelect::Exit()
{
	// rcdb 와 의 연결을 명시적으로 해제
	m_rcdb.PgCloseDB();
}

bool CContentSelect::GetHostSizeFilename( const std::string & szServiceSeq, const bool & bUriIgnoreCase
	, const std::string & szUri
	, std::string & szErrorMessage, std::vector<struct HostSizeFilenameInfo> & vecResult )
{
	// RCDB 는 이미 연결된 상태
	char szQuery[8192];
	int nResult = 0;

	if( bUriIgnoreCase == true )
	{
		// 대소문자 무시 서비스인 경우
		snprintf( szQuery, 8192 - 1
			, "SELECT host_name, filename_hash, get_content_length "
			  "FROM t_meta_%s "
			  "WHERE resource_type = 0 AND deleted_yn = 'N' AND is_cache != 'Y' "
			  " AND uri = lower('%s') "
			  "ORDER BY is_cache ASC ;"				// 원본부터 우선 조회되도록 sort.
			, szServiceSeq.c_str(), szUri.c_str() );

	}
	else
	{
		// 대소문자 구분 서비스인 경우
		snprintf( szQuery, 8192 - 1
			, "SELECT host_name, filename_hash, get_content_length "
			  "FROM t_meta_%s "
			  "WHERE resource_type = 0 AND deleted_yn = 'N' AND is_cache != 'Y' "
			  " AND uri = '%s' "
			  "ORDER BY is_cache ASC ;"				// 원본부터 우선 조회되도록 sort.
			, szServiceSeq.c_str(), szUri.c_str() );
	}

	// Query 실행
	m_rcdb.PgDoExec( szQuery );

	nResult = m_rcdb.PgResult( DataBase::NOT_CLEAR );
	if( nResult < 0 )
	{
		// query 수행 실패시
		szErrorMessage = "db error.";

		_LOG( LERR, "[ContentSelect %d %ld] content select exec error. [%d][%s][%s]"
			, getpid(), m_lThreadId
			, nResult, m_rcdb.GetErrorMessage().c_str(), szQuery );

		// 다음 Query 수행을 위해 조회 결과 set 을 clear 처리
		m_rcdb.PgClear();
		return false;
	}

	// 결과 Row 수 확인
	nResult = m_rcdb.GetNoTuples();
	_LOG( LDBG, "[ContentSelect %d %ld] rcdb content select result[%d %s]"
		, getpid(), m_lThreadId
		, nResult, szQuery );

	if( nResult < 0 )
	{
		// query 수행 실패시
		szErrorMessage = "db select error.";

		_LOG( LERR, "[ContentSelect %d %ld] content select tuple error. [%d %s %s]"
			, getpid(), m_lThreadId
			, nResult, szUri.c_str(), m_rcdb.GetErrorMessage().c_str() );

		// 다음 Query 수행을 위해 조회 결과 set 을 clear 처리
		m_rcdb.PgClear();
		return false;
	}
	else if( nResult == 0 )
	{
		szErrorMessage = "content not found from db.";

		// 해당 Content 가  없는 경우.. 
		_LOG( LWAR, "[ContentSelect %d %ld] content not found from db. [%s]"
			, getpid(), m_lThreadId
			, szUri.c_str() );

		// 다음 Query 수행을 위해 조회 결과 set 을 clear 처리
		m_rcdb.PgClear();
		return false;
	}
	else
	{
		struct HostSizeFilenameInfo data;
		vecResult.clear();
		
		// 조회 결과를 output 변수에 저장 처리
		for( int i = 0; i < nResult; i++ )
		{
			// 0: host_name
			// 1: filename_hash
			// 2: get_content_length

			data.uContentLength = atoll( m_rcdb.GetValue( i, 2 ) );
			data.szHost = m_rcdb.GetValue( i, 0 );
			data.szFilename = m_rcdb.GetValue( i, 1 );
		
			_LOG( LINF, "[ContentSelect %d %ld] content select [%s]: [%s %llu %s]"
				, getpid(), m_lThreadId
				, szUri.c_str(), data.szHost.c_str(), data.uContentLength, data.szFilename.c_str() );

			vecResult.push_back( data );
		}
	}

	// 다음 Query 수행을 위해 조회 결과 set 을 clear 처리
	m_rcdb.PgClear();

	return true;
}


