/***************************************************************************
                ftsd ( File TranSfer Daemon ) Header ( SocketControl.h )
                -----------------------------------------
	begin      : 2010/03/09
	copyright  : (C) 2005 SolutionBox Inc.
	author     : Service 1 Team
	email      : svc1@solbox.com
	version    : 1.0

	CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
	Redistribution and use in source and binary forms, with or with out
	modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/

#ifndef __SOCKET_CONTROL_H__
#define __SOCKET_CONTROL_H__

#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>

#include "Protocol.h"
#include "BaseSocket.h"

///< BYTE 타입 정의
#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef unsigned char BYTE;
#endif  // _BYTE_DEFINED


#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE		1024	// SocketControl 에서 사용할 임시버퍼 크기.
#define FILE_DATA_BUFFER_SIZE				16384	// 16 Kbyte, 파일 송수신시 사용할 임시 버퍼의 크기.

class CSocketControl : public CBaseSocket
{
	private:
		
		/// @brief Packet Header 변수
		struct FileTransferPacketHeader m_packetHeader;

		/// @brief m_packetHeader 구조체의 크기를 저장하기 위한 상수
		const int m_nPacketHeaderLen;  

		/// @brief Packet Header 에 저장된 Data 부분의 길이 정보값.
		unsigned int m_nPacketDataLen;

		/// @brief Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
		BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];


	public:

		/// @brief 생성자.
		/// @param socket [in] 처리할 socket descriptor

		CSocketControl();
		CSocketControl( const int & socket );
		
		/// @brief 소멸자.
		~CSocketControl();


		/// @brief 전달받은 Target 으로 Socket 접속을 수행
		/// @param szTarget [in] 접속 대상 Host name 또는 IP
		/// @param nPort	[in] 접속 Port
		/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
		bool ConnectTarget( const std::string& szTarget, int nPort );

		/// @brief Packet 의 Header 정보를 수신하여 각 정보를 전달받은 참조변수로 반환.
		/// @param bRequest [out] Request 요청인지 여부
		/// @param bFromControl [out] Control 로 부터 전달된 Command 인지 여부
		/// @param command [out] Command 정보
		/// @return 1 : Data 수신 성공시
		///         0 : Timeout 발생시
		///        -1 : 접속 종료시
		int GetHeaderInfo( bool& bRequest, bool& bFromControl, char& command );

		/// @brief Packet 의 Header 정보 중 현재 전달받은 Header 의 Result 값을 반환
		/// @param result [out] result 4 Byte 부분의 값을 저장하기 위한 참조변수
		/// @return result 4 Byte 부분 중 첫번째 Byte 값을 반환.
		char GetHeaderResult(void );
		void GetHeaderResult( std::vector<char>& result );

		/// @brief Packet Header 정보를 Log 파일에 Logging 처리
		void PrintHeaderToLog(void);

		/// @brief Transfer Daemon 으로 Local NIC IP 정보 전송
		/// @param bResult [in] szValue 에 저장된 Local IP 정보의 유효여부
		/// @param szValue [in] Local NIC IP 정보
		/// @return 전송 성공시 true, 실패시 false 반환.
		bool SendLocalIpInfo( bool bResult, const std::string& szValue );

		/// @brief Socket 으로 연결된 대상의 Local NIC IP 정보를 요청한 후 해당 정보 수신.
		bool GetLocalIpInfo( std::string& szValue );

		
		
		/// @brief 연결된 socket 으로 파일 수신 요청 패킷을 전송한다.
		bool SendFileReceiveRequest( std::string& szFileName, unsigned long long nFileSize, char commandCode );

		/// @brief File 수신 요청에 대한 응답 패킷을 수신처리하기 위한 함수( TRANSFER_FILE_REPLICATION, TRANSFER_FILE_CACHE 요청에 대한 response 처리).
		/// 본 패킷이 정상인 경우 이 패킷을 수신한 Daemon 은 파일 전송 시작 패킷 및 File의 전송을 바로 시작한다.
		bool GetFileReceiveResponse( char commandCode, bool& bSuccess, std::string& szErrorString );

		/// @brief File 송신 시작(TRANSFER_FILE_START::REQUEST) 요청 패킷.
		bool SendFileStartRequest(void);

		/// @brief File 송신 완료후 해당 파일 정보 요청을 위한 (TRANSFER_FILE_END::REQUEST) 요청 패킷.
		bool SendFileEndRequest(void);

		/// @brief 파일 수신 완료에 따른 응답패킷을 파싱처리.
		bool GetFileEndResult( bool& bSuccess, std::string& szFileFullName, unsigned long long& nFileSize, std::string& szErrorString );


		/// @brief 파일의 수신 요청을 받은 경우 해당 업무를 수행하기 위한 함수
		///< 본 함수는 파일의 수신, 수신 관련 통신 작업을 내부적으로 진행 처리함.
		bool ReceiveFile( const std::string& szStorageRoot, unsigned long long nMaxStorageAvailableSize, char commandCode );


		/// @brief 특정 파일에 대한 Hash 검사 요청을 연결된 Socket 을 통해 전송한다.
		bool SendHashCheckRequest(const std::string& szFileName, unsigned long long nFileSize
				, unsigned int nHashLevel, const std::string& szSourceHash );
		/// @brief 특정 파일에 대한 Hash 검사 요청을 받은 경우 이를 처리한다.
		bool CheckFileHash(void);

		/// @brief 특정 파일에 대한 Hash 검사 결과를 연결된 Socket 으로 전송한다.
		bool SendHashCheckResponse( bool bSuccess, std::string& szErrorString );

		/// @brief Hash 검사 요청에 대한 결과값을 수신한다.
		bool GetHashCheckResult( bool& bSuccess, std::string& szErrorString );

		/// @brief Alive Check 를 위한 패킷 전송 => 해당 패킷의 응답은 필요없으므로 수신시 무시할 것.
		bool SendAliveCheck(void);


		/// @brief Control 로 부터 CONTROL_FILE_REPLICATION 또는 CONTROL_FILE_CACHE Request 요청을 받은 경우 \n
		///<       Packet Data 부분의 상세 정보를 가져온다.
		bool GetFileRequestInfo( std::string& szFileName, unsigned long long& nFileSize, std::string& szTargetTranId, 
				int& nFileHashCheckLevel, bool& bUseInternalIp, std::vector< std::string >& vecTargetFhs);

		/// @brief Control 로 부터 COCONTROL_FILE_CHECK Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
		bool GetRequestCheckFromControl( std::string& szFileName, bool& bHashCheck,  unsigned long long& nHashCheckSize );

		// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
		/// @brief Control 로 부터 CONTROL_FILE_CHECK_TOTO Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
		bool GetRequestCheckTOTOFromControl( std::string& szFileName );
		

		/// @brief Control 로 부터 COCONTROL_FILE_UNLINK Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
		bool GetRequestUnlinkFromControl( std::string& szFileName, unsigned long long& nFileSize, unsigned int& nUnlinkMode );

		// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
		/// @brief Control 로 부터 CONTROL_FILE_STAT Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
		bool GetRequestStatFromControl( std::string & szFileName );



		/// @brief Control 로 요청에 대한 오류 결과 메시지를 전송한다. 
		bool SendErrorMessageToControl( const std::string& szErrorMessage, char commandCode );

		/// @brief Control 로 파일 복제 요청에 대한 성공 처리 결과 메시지를 전송한다. 
		bool SendFileReplicationResult( char commandCode
				, std::map< std::string, std::string>& mapSuccessList, std::map< std::string, std::string>& mapFailList );

		/// @brief Control 로 Check 요청에 대한 성공 처리 결과를 전달한다.
		bool SendCheckResultToControl( char commandCode, const unsigned long long& nFileSize, const std::string& szHashValue );

		/// @brief Control 로 Unlink 요청에 대한 성공 처리 결과를 전달한다... Data 부분은 존재하지 않음.
		bool SendUnlinkResultToControl( char commandCode );

		
		// NEW 2016-05-11 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
		/// @brief 고객사 토토디스크 지원을 위한 기능
		///        Control 로 부터 전달받은 Content 에 대해 Size 정보 및 MD5 Hash, Checksum 정보 등을 추출하여 전달한다.
		bool SendTOTOCheckResultToControl( char commandCode, const unsigned long long& nFileSize
			, const std::string& szResultTotoMd5, const std::string& szResultChecksum, const std::string& szResultDnaCheckKey );

		// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
		/// @brief Control 로 Stat 요청에 대한 성공 처리 결과를 전달한다.
		bool SendStatResultToControl( char commandCode, const long & nFileSize, const long & nAccessTime, const long & nModifyTime, const long & nChangeTime );




	protected:
		
		/// @brief Packet Header 부분의 수신 처리를 위한 함수. Alive Check 요청 패킷은 자동으로 무시처리함.
		/// @param timeout [in] 대기시간.
		/// @retrun ( 해당 Define 은 SocketControl.cpp 참고 )
		///         1 : PACKET_HEADER_RECEIVE_SUCCESS          : 성공시           
		///         0 : PACKET_HEADER_RECEIVE_TIMEOUT          : Timeout 발생시
		///        -1 : PACKET_HEADER_RECEIVE_SOCK_CLOSED      : socket 종료된 경우
		///        -2 : PACKET_HEADER_RECEIVE_INVALID_PROTOCOL : 잘못된 Packet 형식인 경우
		///        -3 : PACKET_HEADER_RECEIVE_READ_ERROR       : 기타 오류
		int GetPacketHeader(int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT);

		/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
		/// @param size [in] read 할 데이터 크기
		/// @param value [out] 읽은 데이터를 저장할 string 변수
		/// @return On success return true, otherwise return false.
		bool GetPacketData( unsigned int& size, std::string& value );

		/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
		/// @param size [in] read 할 데이터 크기
		/// @return On success return true, otherwise return false.
		bool GetPacketData( unsigned int size );

		/// @brief pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
		unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
		/// @brief pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
		unsigned long long GetDataToUInt64( BYTE * pValue );


		/// @brief 전달받은 Directory 정보를 확인하여 존재하지 않을 경우 생성처리.
		bool MakeDirectory( const std::string& szFullPath );

		/// @brief Socket 으로 부터 수신받은 데이터를 파일에 Write 처리한다.
		///< 만약 File Write 처리시 오류가 발생하는 경우 Socket Data 의 정상적인 처리를 위해
		///< Socket 데이터 수신만 처리하고 오류를 반환한다.
		/// @returnFile Write 가 오류 없이 정상적으로 처리된 경우 true, 오류발생시 false 및 오류메시지 반환
		bool ReceiveToFile( FILE * pFile, unsigned long long nFileSize, std::string& errorMessage );

		// Socket 으로 부터 수신받은 데이터를 읽어서.. 버린다.
		// - 기존 물리 파일이 존재하는 경우.. overwrite 처리를 않기로 해서...
		// - socket 으로 부터 수신된 data 는 버린다.
		// return 오류 없이 정상적으로 처리된 경우 true, 오류발생시 false 및 오류메시지 반환
		bool ReceiveToDummy( unsigned long long nFileSize, std::string& errorMessage );
		

		/// @brief File 수신 요청에 대한 응답 패킷 전송( TRANSFER_FILE_REPLICATION, TRANSFER_FILE_CACHE 요청에 대한 response 패킷임.
		/// 해당 패킷이 정상인 경우 이 패킷을 수신한 Daemon 은 파일 전송 시작 패킷 및 File의 전송을 바로 시작한다.
		bool SendFileReceiveResponse( bool bSuccess, std::string& szErrorString, char commandCode );

		/// @brief File 송신 완료(TRANSFER_FILE_END) 패킷에 대한 응답 패킷 전송
		bool SendFileEndResponse( bool bSuccess, std::string& szFileFullName, unsigned long long nFileSize, std::string& szErrorString );


};

#endif /* __SOCKET_CONTROL_H__ */

