#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>

#include "Logger.h"
#include "FtsdSocketControl.h"



#define LOG_PATH				"/user/service/logs"	// Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.

#define TRANSFER_LISTEN_PORT	14001					// ftsd 의 Listen Port



int main()
{
	///////////// 1. 기본 정보 설정 ///////////////////
	
	// Source 장비 Host Name
	//std::string szSourceHostName		= "bd-16-fhs001.ktsh.co.kr";	
	//std::string szSourceHostName		= "nh-61-fhs018.x-cdn.com";	
	std::string szSourceHostName		= "nh-61-fhs005.x-cdn.com";	
	
	
	// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
	//std::string szFileName    = "/stg/node0/348/d31e2f9043ac62d273c1fd87008a6c86";
	//std::string szFileName    = "/stg/node0/10m_1";
	//std::string szFileName    = "/stg/node0/600/2139178cdcacb3ba2a2ca9533bee7fbf";
	//std::string szFileName    = "/stg/node2/600/616964e59ed7ee956470f88c271cbe68";
	//std::string szFileName    = "/stg/node0/594/fdd9a1f5b32f062622254fb7c5b4c537";
	std::string szFileName    = "/stg/node0/594/f962ec80bb5e3257e95925305f6a7296";

	// Hash 정보 추출 여부
	bool bHashCheck = true;

	// Hash 추출 size ( 0 : 전체... 숫자값 : 앞부분부터 지정된 위치의 까지 MByte 단위임 )
	//unsigned long long nHashCheckSize = 10;
	unsigned long long nHashCheckSize = 0;



	//////////////   결과값을 저장할 변수 //////////////////
	// File Size
	unsigned long long nFileSize = 0;

	// Hash 추출값
	std::string szHashValue;
	
	// 오류 메시지
	std::string szErrorMessage;


	////////////// Sample 코드 //////////////

	// Log 처리용 객체 생성 및 초기화.
	if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
	{
		std::cout << "[error] Logger object created failed.." << std::endl;
		return 0;
	}

	// Start logging
	_LOG( LINF, "ftsd check sample Start: Source[%s]", szFileName.c_str());


	// ftsd 와  통신을 처리할 Socket Control 객체 생성 및 접속
	CFtsdSocketControl ftsdSocket;
	if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
	{
		// Source ftsd 으로 접속 실패시
		_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
		return EXIT_FAILURE;
	}

	// ftsd 로 파일에 대한 Check 요청 전달
	// SendFileCheckRequest() 함수는 FtsdSocketControl.h 파일 참조.
	if( ftsdSocket.SendFileCheckRequest( szFileName, bHashCheck, nHashCheckSize ) == false )
	{
		// Source ftsd 로 전송 실패시
		_LOG( LERR, "Check Request send fail.[%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
		return EXIT_FAILURE;
	}


	// 요청에 대한 응답 대기
	int nTimeout = 5; // 응답 대기 시간 ( sec )
	int nResult = 0;

	
	bool bResultSuccess;									// 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
	

	// 루프를 돌면서 요청에 대한 응답을 대기
	while(1)
	{

		// nTimeout 에 지정된 시간동안 응답대기 시도
		// GetFileCheckResult() 함수는 SocketControl.h 파일 참고.
		nResult = ftsdSocket.GetFileCheckResult( nTimeout, bResultSuccess, szErrorMessage, nFileSize, szHashValue );

		if( nResult == -1 )
		{
			// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
			// 해당 내역 로깅 및 루프 종료
			_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
			break;

		}
		else if( nResult == 0 )
		{
			// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로

			if( ftsdSocket.SendAliveCheck() == false )
			{
				// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
				_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
				break;
			}

			// 정상적인 경우 다시 응답대기.
			continue;

		}
		else if( nResult == 1 )
		{
			// 요청에 대한 처리결과 정보가 수신된 경우.
			// 해당 정보 로깅처리.

			if( bResultSuccess == true )
			{
				// 요청에 대한 처리가 정상적으로 처리된 경우

				//_LOG( LINF, "[%s] Result SUCCESS [%llu][%s]", szFileName.c_str(), nFileSize, szHashValue.c_str());
				
				_LOG( LINF, "Result size [%llu]",  nFileSize );
				_LOG( LINF, "Result Hash [%s]", szHashValue.c_str());

			}
			else
			{
				// 오류 발생시 
				_LOG( LINF, "[%s][%s] Result ERROR [%s]", szFileName.c_str(), szSourceHostName.c_str(), szErrorMessage.c_str() );

			}			

			break;	// 응답을 받았으니 응답 대기 루프 종료
		}
		else
		{
			// Replication 요청에 대한 응답패킷이 아닌 경우.
			// 해당 패킷은 무시하고 다시 Loop 로 
			continue;
		}
	}


	// End logging
	_LOG( LINF, "ftsd check sample process End [%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
	_LOG( LINF, "-------------------------------------------------------------------------------" );

	CLogger::Exit();

	return EXIT_SUCCESS;
}
