/***************************************************************************
               rc_syncd - rc_syncd 간의 통신 처리 담당 class
                -----------------------------------------
	begin      : 2014/09/05
	copyright  : (C) 2005 Solbox Inc.
	author     : Storage Dev Team
	email      : storage.sd@solbox.com
	version    : 3.4

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

#ifndef __PROCESS_SOCKET_CONTROL_H__
#define __PROCESS_SOCKET_CONTROL_H__


#include "BaseSocket.h"
#include "RcSyncdProtocol.h"

#include "RcSyncdRequestData.h"

#include <string>


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


#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE		1024	// Socket 관련 data 송수신시 사용할 임시버퍼 크기.
#define FILE_DATA_BUFFER_SIZE				16384	// 16 Kbyte, 파일 송수신시 사용할 임시 버퍼의 크기.

class CProcessSocketControl : public CBaseSocket
{
	public:

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

		CProcessSocketControl();
		CProcessSocketControl( const int & socket );
		
		// 소멸자.
		~CProcessSocketControl();


		/////// 각 업무 Flow 모듈 제공용 Interface 함수 ///////////////////
				
		// 전달받은 Target 으로 Socket 접속을 수행
		// @param szTarget [in] 접속 대상 Host name 또는 IP
		// @param nPort	[in] 접속 Port
		// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
		bool ConnectTarget( const std::string& szTarget, int nPort );
				
		// Alive Check 를 위한 패킷 전송 => 해당 패킷에 대한 응답은 필요없으므로 수신시 무시할 것.
		// @return 전송 성공시 true, 실패시 false 반환.
		bool SendAliveCheck(void);		
		
		// [Master] Client 에게 Sync 요청에 대한 결과 정보 전송 처리
		// @param bSuccess       [in] 성공 여부
		// @param strMessage     [in] Client 로 전달할 메시지
		// @return 전송 성공시 true, 전송 실패시 false 
		bool SendResultSyncToClient( bool bSuccess, std::string& strMessage );

		// [Master] Slave rc_syncd 로 content 목록 요청.
		// @param [IN] data slave rc_syncd 로 전송할 data 객체
		// @return 전송 성공시 true, 전송 실패시 false 
		bool SendRequestContentListToSlave( CReqSlaveData& data );

		// [Master] Slave rc_syncd 에서 전송한 content 목록 정보 처리 결과를 수신하기 위한 함수.
		// @param nTimeout        [in]  함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )
		//                              지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
		// @param bSuccess        [out] 성공 여부
		//                              실패(false) 인 경우.. strErrorMessage 변수에 오류 내역이 저장됨		
		// @param strSaveFileName [in]  성공(bSuccess==true) 인 경우... 수신된 Data 를 저장하기 위한 파일명 (Full 경로)
		// @param strErrorMessage [out] 실패(bSuccess==false) 인 경우... 수신된 오류 메시지를 저장하기 위한 변수
		// @return
		//         -1  : slave rc_syncd 와 통신이 끊어진 경우.
		//          0  : slave rc_syncd 로 부터 응답을 아직 수신하지 못한 경우.. 		
		//               => AliveCheck 등의 작업 후 다시 응답 대기하면 된다.
		//          1  : 정상 응답을 수신한 경우
		//          2  : 수신된 응답이 다른 요청에 대한 응답인 경우.. 
		//               => 무시 처리하고 계속 응답을 대기하면 된다.
		int RecvResultContentListFromSlave( int nTimeout, bool& bSuccess, std::string& strSaveFileName, std::string& strErrorMessage );
		

		// [Master] Slave rc_syncd 에 sync 작업 수행을 요청한 후 그 결과를 수신.
		// - 본 함수는 data 와 파일을 원격 rc_syncd 에 전달하여 원격 rc_syncd 가 SYNC MODE 로 동작하도록 한다.
		//   그리고.. 원격 rc_syncd 의 execute 전까지의 처리 결과를 수신하여 [out] 항목에 그 결과를 저장처리한다.
		// data       [in]  sync mode 수행을 위해 전달해야하는 data 객체.
		// fd         [in]  sync 수행 대상 content 정보를 저장한 파일에 대한 descriptor
		// nFileSize  [in]  sync 파일 크기		
		// strMessage [out] 원격지의 sync mode 수행 관련 수신된 메시지( 정상, 실패 모두 가능)
		// return
		//       true  : sync 수행 요청이 정상적으로 전달되었고... 원격지 rc_syncd 가 정상 동작한 경우..
		//       false : 그외 모든 오류 사항.
		bool SendRequestExecuteSyncToSlave( CReqSyncData& data, int fd, unsigned long long nFileSize, std::string& strMessage );
		

		// [Slave] Master rc_syncd 로 추출된 Content 정보 목록을 전달한다.
		// @param [IN] fd 전송할 file descripter
		// @param [IN] nFileSize 전송할 file size
		// @return 전송 성공시 true, 전송 실패시 false 
		bool SendResultContentListToMaster( int fd, unsigned long long nFileSize );

		// [Slave] Content 정보 목록 추출 실패시 Master rc_syncd 로 관련 오류 내역을 전달한다.
		// @param strMessage [IN] master rc_syncd 로 전달할 메시지
		// @return 전송 성공시 true, 전송 실패시 false 
		bool SendErrorContentListToMaster( std::string& strMessage );


		// [Sync] Master 에게 Sync Execute 요청에 대한 응답을 전송 처리
		// @param bSuccess       [in] 성공 여부
		// @param strMessage     [in] 전달할 메시지
		// @return 전송 성공시 true, 전송 실패시 false 
		bool SendResultExecuteSyncToMaster( bool bSuccess, std::string& strMessage );
		

		/////// 통신 관련 Client Thread 내부용 Interface 함수 ///////////////////

		// Client 로 부터 수신된 Sync 요청 Data body 수신 처리.
		// @param request [out] 수신된 정보를 저장하기 위한 객체
		// @return 수신 성공시 true, 그 외 false		
		bool RecvBodySyncFromClient( CReqMasterData& request );

		// Master rc_syncd 에서 전송한 Content 목록 요청의 Data body 수신 처리.
		bool RecvBodyContentListFromMaster( CReqSlaveData& request );

		// Master rc_syncd 에서 전송한 sync 실행 요청 관련 data body 수신 처리.
		// - 파일 관련 부분은 수신하지 않고.. 아래 함수(RecvFileExecuteSyncFromMaster)를 통해 따로 수신 처리해야 함.
		// @param request [in] 수신된 CReqSyncData 정보를 저장하기위한 객체
		// @return 성공시 true, 실패시 false
		bool RecvBodyExecuteSyncFromMaster( CReqSyncData& request );
		
		// Master rc_syncd 에서 전송한 sync 실행 요청 관련 sync file 관련 부분을 수신 처리.
		// @param strSaveFileName [in] 저장 파일명
		// @param strErrorMessage [out] return 값이 false 일 경우. 오류 메시지 저장.
		bool RecvFileExecuteSyncFromMaster( std::string& strSaveFileName, std::string& strErrorMessage );

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

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

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



	private:
		
		// Packet Header 변수
		struct RcSyncdPacketHeader m_packetHeader;

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

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

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

	protected:
		
		// Packet Header 부분의 수신 처리를 위한 함수.
		// @param timeout [in] 대기시간.
		// @retrun 
		//         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);

		// 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 );

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

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

		// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
		unsigned long long GetDataToUInt64( BYTE * pValue );
		
		// 전달받은 Directory 정보를 확인하여 존재하지 않을 경우 생성처리.
		bool MakeDirectory( const std::string& szFullPath );

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

		// Packet 정보 중 String 정보를 전송하기 위한 함수.
		bool SendString( const std::string& strData );
		
};

#endif /* __PROCESS_SOCKET_CONTROL_H__ */

