#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>

#include "CacheGeneratorThread.h"
#include "DaemonConfigs.h"
#include "SocketControl.h"


using namespace std;

#define SEND_REPLICATION_INTERVAL       10 // sec
#define OK_ALL_PASSED                   0x1000


CCacheGeneratorThread::CCacheGeneratorThread()
{
	// 멤버 변수 초기화
	m_threadHandle = 0;
}

CCacheGeneratorThread::~CCacheGeneratorThread()
{

}

bool CCacheGeneratorThread::ThreadInit(const sig_atomic_t *sighandle) 
{
	m_sighandle = sighandle;

	// rc_rmcd로 접근 함
	m_szHost = CDeamonConfig::GetInstance()->GetRctsServer();
	m_nPort = CDeamonConfig::GetInstance()->GetHotContentPort();

	return true;
}

uint64_t CCacheGeneratorThread::GetFileSize(std::string szFileName)
{
	off_t totalSize = 0;

	// 파일 크기 검사.
	FILE * pFile = fopen( szFileName.c_str(), "r+" );
	if( pFile == NULL )
	{
		//source file open fail.
		return totalSize;
	}
	else
	{
		fseeko( pFile, 0, SEEK_END );
		totalSize = ftello( pFile );
		rewind( pFile );
		fclose( pFile );	// 열려진 descriptor close
	}
	return totalSize;
}

bool CCacheGeneratorThread::Request()
{
	CSocketControl objSocket;
	int nCount = 0;
	// GMS 장비와 TCP 연결.
	if( objSocket.ConnectTarget( m_szHost, m_nPort ) == false )
	{
		LOG( LERR, "CacheGeneratorThread: RCTS connection fail.[%s][%d]", m_szHost.c_str(), m_nPort );
		
		objSocket.Close();
		return false;
	}

	nCount = 0;
	while(nCount < 30)
	{
        // 1. Data가 존재 하는가?
    	if( m_cacheReqList.GetSize() <= 0 )
    	{
    	    LOG(LDBG, "ReplicationReqQueue queue is no have data.");
	
			// 카운트 증가 후 1초 딜레이...
    	    nCount++;
			sleep(1);
    	    continue;
        }
		nCount = 0;

		// pop
        // 2. DataPop()
		struct replication_info objReplicaInfo = m_cacheReqList.Pop();

		// get rcid
		std::string szRCID = CDeamonConfig::GetInstance()->GetRCID();

		// get hostname
		char szHostname[HOSTNAME_LEN_FOR_RMCD];
        if( gethostname( szHostname, HOSTNAME_LEN_FOR_RMCD ) != 0 )
        {
            LOG(LWAR, "gethostname() failed." );
        	continue;
        }

		// get filesize
		uint64_t nFileSize = GetFileSize(objReplicaInfo.szFileName_hash);
        if(  nFileSize <= 0 )
        {
			LOG(LWAR, "get file size error[%s]", objReplicaInfo.szFileName_hash.c_str() );
			continue;
        }

		// internal cache 요청
		if ( objSocket.SendIntenalCache(szRCID
									, objReplicaInfo.szFileName_hash
									, szHostname
									, objReplicaInfo.nServiceID
									, nFileSize
									, objReplicaInfo.szFDCount) == false )
		{
			// SendIntenalCache() 함수 내부에서 로깅처리 됨.
			break;
		}
	}

	objSocket.Close();

	return true;
}

///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CCacheGeneratorThread::Execute()
{	
	while (*m_sighandle == 0)
	{
        // ReplicationReqQueue List에서 값을 가져오기 전에 개수를 확인한다.
    	if( m_cacheReqList.GetSize() <= 0 )
    	{
    	    LOG( LDEV, "ReplicationReqQueue queue is empty.");
    	    sleep( SEND_REPLICATION_INTERVAL );
    	    continue;
        }
        // 아래 함수에서 return false 가 되더라도 무시한다.
        if( Request() == false ){;}
        
        sleep( SEND_REPLICATION_INTERVAL );
	}
	

	LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
}

void* CCacheGeneratorThread::EntryPoint(void* arg)
{
    CCacheGeneratorThread* pObject = reinterpret_cast<CCacheGeneratorThread *>(arg);
	pthread_detach( pthread_self() );
    
	pObject->Execute();
	
	// Thread 종료시 m_threadHandle 값을 초기화 처리.
	// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
	pObject->m_threadHandle = 0;

	return 0;
}

bool CCacheGeneratorThread::Start()
{
	int nRet = ::pthread_create(&m_threadHandle, 0, CCacheGeneratorThread::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;
}

