#include "MsgQueuePopThread.h"
#include "DaemonConfigs.h"

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

using namespace std;

#define DEFAULT_QUERY_BUFFER_SIZE           1024
#define QUERY_LIMIT_COUNT    2000
#define UPDATE_TERM 180
#define CONTENT_QUEUE_SLEEP		100000	// 0.1sec

CMsgQueuePopThread::CMsgQueuePopThread()
	:m_threadHandle(0), m_pTransfer(NULL)
{
}

CMsgQueuePopThread::~CMsgQueuePopThread()
{

}

bool CMsgQueuePopThread::ThreadInit(const sig_atomic_t *sighandle, std::vector<CIPCMsgQueue> &vecContentQueue, CTransferStatDataList *pTransfer /* = NULL */)
{
	m_sighandle = sighandle;
	m_vecContentQueue = vecContentQueue;

	m_pTransfer = pTransfer;
	return true;
}

bool CMsgQueuePopThread::ThreadInit(const sig_atomic_t *sighandle, CIPCMsgQueue &cContentQueue, CTransferStatDataList *pTransfer /* = NULL */)
{
	m_sighandle = sighandle;
	m_vecContentQueue.push_back(cContentQueue);

	m_pTransfer = pTransfer;
	return true;
}

void CMsgQueuePopThread::Pop()
{
	int nResult = 0;

	for( vector<CIPCMsgQueue>::size_type i = 0; i < m_vecContentQueue.size(); ++i )
	{
		// 2016.03.19 dadamin
		// 잘못된 메모리 참조 오류 발생
		struct Transfer_stat ipcmsg = {0};
		CTransferStatData data;
	
		nResult = m_vecContentQueue[i].Pop(&ipcmsg, sizeof(struct Transfer_stat), IPC_NOWAIT, 0);
		data.SetTransferStatData(ipcmsg);

		switch(nResult)
		{
			// 큐가 생성 되지 않은 경우
			case -2 : 
				{
					LOG(LERR, "A message queue could not be created.");
					continue;
				}
			// 큐가 유효하지 않은 경우
			case -1: 
				{
					LOG(LERR, "Message queue pop fail. [%s(%d)].", strerror(errno), errno);
					continue;
				}
			// Queue에 가져올 데이터가 없는경우
			case 0:
				{
					LOG(LDEV, "Message queue no have data.");
					continue;
				}
			default:
				{
					if (nResult > 0)
					{
						// GET 요청에 대한 정보이면 CTransferStatDataListList에 등록한다.
						if ((data.GetDirection() == 0) && (data.GetFilenameHash().size() > 0))
						{
							if (m_pTransfer) m_pTransfer->Push(data);
						}
						--i;
					}
				}
		}
	}
}

///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CMsgQueuePopThread::Execute()
{
	// CTransferStatDataListinstance 생성을 체크 한다.
	if( m_pTransfer == NULL )
	{
		LOG( LERR, "failed to push to download list because the instance of CTransferStatDataListList is NULL." );
		return;
	}

	while (*m_sighandle == 0)
	{
		
		/// 연결 된 Qeue에서 5개의 메시지 큐에서 데이터를 하나씩 pop한 리스트를 가지고 온다.
		Pop();

		///  큐가 비어 있는 상태이기 때문에 대기한다.
		if (*m_sighandle == 0)
		{
			//usleep( CONTENT_QUEUE_SLEEP );	
			struct timespec sleep;
			sleep.tv_sec = 0;
			//sleep.tv_nsec = CONTENT_QUEUE_SLEEP * 1000 ;   // 0.1 sec
			sleep.tv_nsec = 100000000;   // 0.1 sec
			nanosleep(&sleep, NULL);
		}
	}
	
	LOG(LINF, "Thread end...");
}

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

	return 0;
}

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

