#ifndef __TOLLGW_H__
#define __TOLLGW_H__

/*
#include <stddef.h>
#include <libsafec/safe_str_lib.h>
#include <libsafec/safe_mem_lib.h>
#include <linux/limits.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
*/

#ifdef __cplusplus
#ifndef BEGIN_DECLS
#define BEGIN_DECLS extern "C" {
#endif
#ifndef END_DECLS
#define END_DECLS }
#endif
#else
#ifndef BEGIN_DECLS
#define BEGIN_DECLS
#endif
#ifndef END_DECLS
#define END_DECLS
#endif
#endif

BEGIN_DECLS

#ifdef _WIN32
#include <wchar.h>
#endif

//#include <crtdefs.h>
#include <stddef.h>
#include <limits.h>
#include <stdint.h>


#include "Common.h"
#include "Log.h"
#include "Socket.h"
#include "SystemUtil.h"
#include "MessageQueue.h"
#include "DataStructure.h"
#include "ThreadUtil.h"
#include "StringUtil.h"
#include "FileUtil.h"
#include "SecureCodingUtil.h"



#define GW_ERR_SUCCESS                          0
#define GW_ERR_CONFIG                           -1
#define GW_ERR_INIT                             -2
#define GW_ERR_PACKET_SIZE                      -3
#define GW_ERR_PACKET_FORMAT                    -4
#define GW_ERR_MQ_ERROR                         -5
#define GW_ERR_DIRECTORY_ACCESS                 -6
#define GW_ERR_FILE_ACCESS                      -7
#define GW_ERR_FILE_SIZE_NOTEQUAL               -8
#define GW_ERR_TARGET_DIRECTORY_ACCESS          -9
#define GW_ERR_NOT_EXIST_NULL                   -10
#define GW_ERR_UNKNOWN_WORK_TYPE                -11
#define GW_ERR_UNKNOWN_MSG_TYPE                 -12
#define GW_ERR_UNKNOWN_RESP_CODE                -13



// 설정 파일 키값 정의
#define GW_CONFIG_CONNECT_TYPE                  "CONNECT_TYPE"
#define GW_CONFIG_IP                            "IP"
#define GW_CONFIG_PORT                          "PORT"
#define GW_CONFIG_CHANNEL_NUM                   "CHANNELS"
#define GW_CONFIG_CHANNEL1_MODE                 "CHANNEL1_MODE"
#define GW_CONFIG_CHANNEL2_MODE                 "CHANNEL2_MODE"
#define GW_CONFIG_CHANNEL3_MODE                 "CHANNEL3_MODE"
#define GW_CONFIG_CHANNEL4_MODE                 "CHANNEL4_MODE"
#define GW_CONFIG_CHANNEL5_MODE                 "CHANNEL5_MODE"

#define GW_CONFIG_CONNECT_TYPE_SERVER           "SERVER"
#define GW_CONFIG_CONNECT_TYPE_CLIENT           "CLIENT"

#define GW_CONFIG_MESSAGE_SEND_EXCHANGER_NAME   "MESSAGE_SEND_EXCHANGER_NAME"
#define GW_CONFIG_MESSAGE_RECV_EXCHANGER_NAME   "MESSAGE_RECV_EXCHANGER_NAME"
#define GW_CONFIG_FILE_SEND_EXCHANGER_NAME      "FILE_SEND_EXCHANGER_NAME"
#define GW_CONFIG_FILE_RECV_EXCHANGER_NAME      "FILE_RECV_EXCHANGER_NAME"


#define GW_CONFIG_CHANNEL_STR_HEALTH            "HEALTH"
#define GW_CONFIG_CHANNEL_STR_MESSAGE_SEND      "MESSAGE_SEND"
#define GW_CONFIG_CHANNEL_STR_MESSAGE_RECV      "MESSAGE_RECV"
#define GW_CONFIG_CHANNEL_STR_FILE_SEND         "FILE_SEND"
#define GW_CONFIG_CHANNEL_STR_FILE_RECV         "FILE_RECV"

#define GW_CONFIG_FILE_DATA_SIZE_KEY            "FILE_DATA_SIZE"

#define GW_CONFIG_MAX_SEQ_COUNT_KEY             "MAX_SEQ_COUNT"

#define MSG_SEP                                 ':'

#define MSG_LEN_MSG_LEN                         4
#define MSG_LEN_ORGANIZATIONCODE                6
#define MSG_LEN_OCCUR_TYPE                      1
#define MSG_LEN_WORK_TYPE                       4
#define MSG_LEN_MSG_TYPE                        4
#define MSG_LEN_FILENAME                        16
#define MSG_LEN_REQUEST_DTIME                   14
#define MSG_LEN_END_DTIME                       14
#define MSG_LEN_RESP_CODE                       4

#define MSG_DATA_BLOCKNO_LEN                    4
#define MSG_DATA_SEQNO_LEN                      3
#define MSG_DATA_DATA_LEN                       4
#define MSG_DATA_MISSED_DATA_NO_LEN             3
#define MSG_DATA_FILE_DATA_INFO                 (MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN + MSG_DATA_DATA_LEN)

// 파일 정보(WorkType 630, 640에서 사용하는 정보)의 각 데이터 길이
//#define MSG_LEN_FILENAME                        16
#define MSG_LEN_FILESIZE                        12
#define MSG_LEN_MSGSIZE                         4

#define MSG_LEN_SERIAL_NO                       8

#define MSG_LEN_CRC                             4

#define MSG_LEN_MAX_DIRECTORY_SIZE              512

//#define MSG_LEN_FILESIZE                        12

#define MSG_LEN_MAX_SEQUENCE                    100


//#define MSG_FILE_WORK_TYPE_WORK_START_REQ              "0600"
//#define MSG_FILE_WORK_TYPE_WORK_START_RESP             "0610"
//#define MSG_FILE_WORK_TYPE_FILE_INFO_SEND              "0630"
//#define MSG_FILE_WORK_TYPE_FILE_INFO_RESP              "0640"
//#define MSG_FILE_WORK_TYPE_DATA_SEND                   "0320"
//#define MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_REQ         "0620"
//#define MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_RESP        "0300"
//#define MSG_FILE_WORK_TYPE_MISSED_DATA_SEND            "0310"
//
//#define MSG_FILE_MSG_TYPE_WORK_NORMAL               "0000"
//#define MSG_FILE_MSG_TYPE_WORK_START                "0001"
//#define MSG_FILE_MSG_TYPE_FILE_TRANSFER_NEXT        "0002"
//#define MSG_FILE_MSG_TYPE_FILE_TRANSFER_END         "0003"
//#define MSG_FILE_MSG_TYPE_WORK_END                  "0004"


#define MSG_REQ_RESP_CODE                       "0000"

#define MSG_SUCCESS_RESP_CODE                   "0000"
#define MSG_MQERROR_RESP_CODE                   "0003"

//#define GW_FILETRANS_RESP_NORMAL                "0000"
//#define GW_FILETRANS_REQ_MESSAGE_FORMAT         "0001"
//#define GW_FILETRANS_FILE_ACCESS                "0002"
//#define GW_FILETRANS_PROTOCOL                   "0003"

enum MSG_FILE_WORK_TYPE
{
    MSG_FILE_WORK_TYPE_WORK_START_REQ                  = 600,
    MSG_FILE_WORK_TYPE_WORK_START_RESP                 = 610,
    MSG_FILE_WORK_TYPE_FILE_INFO_SEND                  = 630,
    MSG_FILE_WORK_TYPE_FILE_INFO_RESP                  = 640,
    MSG_FILE_WORK_TYPE_DATA_SEND                       = 320,
    MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_REQ             = 620,
    MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_RESP            = 300,
    MSG_FILE_WORK_TYPE_MISSED_DATA_SEND                = 310,
};

enum MSG_FILE_MSG_TYPE
{
    MSG_FILE_MSG_TYPE_NONE                           = 0,
    MSG_FILE_MSG_TYPE_WORK_START                     = 1,
    MSG_FILE_MSG_TYPE_FILE_TRANSFER_NEXT             = 2,
    MSG_FILE_MSG_TYPE_FILE_TRANSFER_END              = 3,
    MSG_FILE_MSG_TYPE_WORK_END                       = 4,
};

enum CONNECT_TYPES
{
    CONNECT_TYPE_SERVER                         = 1,
    CONNECT_TYPE_CLIENT,
};

enum CHANNEL_MODE_FLAGS
{
    GW_CONFIG_CHANNEL_HEALTH_FLAG               = 0x01,
    GW_CONFIG_CHANNEL_MESSAGE_SEND_FLAG         = 0x02,
    GW_CONFIG_CHANNEL_MESSAGE_RECV_FLAG         = 0x04,
    GW_CONFIG_CHANNEL_FILE_SEND_FLAG            = 0x08,
    GW_CONFIG_CHANNEL_FILE_RECV_FLAG            = 0x10,
};    

enum CHANNEL_MODES
{
    GW_CONFIG_CHANNEL_HEALTH                    = 0,
    GW_CONFIG_CHANNEL_MESSAGE_SEND,
    GW_CONFIG_CHANNEL_MESSAGE_RECV,
    GW_CONFIG_CHANNEL_FILE_SEND,
    GW_CONFIG_CHANNEL_FILE_RECV,
    GW_CONFIG_CHANNEL_COUNT
};

enum FILE_SEND_RESULT
{
    GW_FILE_SEND_ERR_SUCCESS = 0,
    GW_FILE_SEND_ERR_REQUEST_MSG_FORMAT,
    GW_FILE_SEND_ERR_FILE_ACCESS,
    GW_FILE_SEND_ERR_PROTOCOL,
};

#define GW_FILE_RECV_PATH_KEY                   "FILE_RECV_PATH"
#define GW_FILE_RECV_PATH_TEMP_KEY              "FILE_RECV_PATH_TEMP"
#define GW_FILE_MOVE_YN_KEY                     "FILE_MOVE_YN"

struct CHANNEL_MODE
{
    int nChannelModeFlags;
};
/*
#define MSG_LEN_ORGANIZATIONCODE                    6
#define MSG_LEN_OCCUR_TYPE                          1
#define MSG_LEN_WORK_TYPE                           4
#define MSG_LEN_MSG_TYPE                            4
#define MSG_LEN_FILENAME                            16
#define MSG_LEN_REQUEST_DTIME                       14
#define MSG_LEN_REPLY_CODE                          4
*/
struct MESSAGE_HEADER
{
    char szOrganizationCode[MSG_LEN_ORGANIZATIONCODE + 1];
    char cOccurType;
    char szWorkType[MSG_LEN_WORK_TYPE + 1];
    char szMsgType[MSG_LEN_MSG_TYPE + 1];
    char szSerialNo[MSG_LEN_SERIAL_NO + 1];
    char szRequestDTime[MSG_LEN_REQUEST_DTIME + 1];
    char szRespCode[MSG_LEN_RESP_CODE + 1];
};

struct MESSAGE_PACKET
{
    char cChannelNo;
    char szMsgLen[MSG_LEN_MSG_LEN + 1];
    struct MESSAGE_HEADER sHeader;
    char szData[MAX_STRING_SIZE + 1];
    char szCRC[MSG_LEN_CRC + 1];
};

struct FILE_HEADER
{
    char szOrganizationCode[MSG_LEN_ORGANIZATIONCODE + 1];
    char cOccurType;
    char szWorkType[MSG_LEN_WORK_TYPE + 1];
    int nWorkType;
    char szMsgType[MSG_LEN_MSG_TYPE + 1];
    int nMsgType;
    char szFilename[MSG_LEN_FILENAME + 1];
    char szRequestDTime[MSG_LEN_REQUEST_DTIME + 1];
    char szRespCode[MSG_LEN_RESP_CODE + 1];
    int nRespCode;
};

struct FILE_PACKET
{
    char cChannelNo;
    char szMsgLen[MSG_LEN_MSG_LEN + 1];
    int nMsgLen;
    struct FILE_HEADER sHeader;
    char szData[MAX_FILE_SEND_SIZE + 1];
    char szCRC[MSG_LEN_CRC + 1];
};

struct FILE_SEND_REQUEST
{
    uint16_t nMessageSize;
    char szOrganizationCode[MSG_LEN_ORGANIZATIONCODE + 1];
    char szFilename[MSG_LEN_FILENAME + 1];
    char szDirectory[SOCK_MAX_DIRECTORY_SIZE + 1];
    int nFileSize;
    char szRequestDTime[MSG_LEN_REQUEST_DTIME + 1];
    int bChangeDirectory;
    char szTargetDirectory[SOCK_MAX_DIRECTORY_SIZE + 1];
};

struct FILE_TRANSFER_STATE
{

    int bFileTransferStarted;
    char cTransferDirection;

    int nCurrentWorkType;
    int nCurrentMsgType;

    struct tm sLastRecvTime;
    struct tm sLastSendTime;
    int nLastRecvMilliSec;
    int nLastSendMilliSec;

    struct FILE_SEND_REQUEST sRequest;

    int nCurrentBlockNo;
    int nCurrentSeqNo;
    int nMaxBlockNo;
    int nMaxSeqNo;
    char *pSeqReceived;
    char szResponseQueuename[MAX_STRING_SIZE + 1];
    uuid_t aUUID;
    int nFileSize;
    int nSeqSize;

    FILE *pFile;
};


struct FILE_PROC_RESPONSE
{
    char szOrganizationCode[MSG_LEN_ORGANIZATIONCODE + 1];
    char szFilename[MSG_LEN_FILENAME + 1];
    char szDirectory[SOCK_MAX_DIRECTORY_SIZE + 1];
    long nFileSize;
    char szRequestDTime[MSG_LEN_REQUEST_DTIME + 1];
    char szEndDTime[MSG_LEN_REQUEST_DTIME + 1];
    char cTransferDirection;
    int bProcComplete;
};


//#define MSG_LEN_FILENAME                        16
//#define MSG_LEN_FILESIZE                        12
//#define MSG_LEN_MSGSIZE                         4

struct FILE_INFO
{
    char szFilename[MSG_LEN_FILENAME + 1];
    int nFileSize;
    int nMsgSize;
};


extern char g_szProcessname[MAX_STRING_SIZE + 1];
extern char g_szProcessPath[PATH_MAX + 1];
extern struct FILE_TRANSFER_STATE (*g_pFileTransferState)[SOCK_CONF_MAX_CHANNEL_LIMIT];

extern char g_szFileRecvPath[MAX_STRING_SIZE + 1];
extern char g_szFileRecvPathTemp[MAX_STRING_SIZE + 1];
extern int g_bFileMoveYN;

//extern int g_nChannels;
//extern struct CHANNEL_MODE g_sChannelModeFlags[GW_CONFIG_CHANNEL_COUNT];
//extern int g_nConnectType;
//extern char g_szMESSAGE_SEND_EXCHANGER_NAME[MAX_STRING_SIZE + 1];
//extern char g_szMESSAGE_RECV_EXCHANGER_NAME[MAX_STRING_SIZE + 1];
//extern char g_szFILE_SEND_EXCHANGER_NAME[MAX_STRING_SIZE + 1];
//extern char g_szFILE_RECV_EXCHANGER_NAME[MAX_STRING_SIZE + 1];

int InitGWConfig();
void InitFileTransferState(int nSocketIndex);
int ProcessMessageSocketData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo);
int ParseMessageHeader(struct MESSAGE_PACKET *pPacket, struct MESSAGE_INFO *pData);
int ProcessFileSocketData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo);
int ParseFileHeader(struct FILE_PACKET *pPacket, struct MESSAGE_INFO *pData);
int ParseFileSendRequest(char *pMessageBuffer, int nMessageBufferSize, struct FILE_SEND_REQUEST *pFileSendRequest);
int ProcessMessageMQSendData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, char *pData, int nDataLength, char *szCorrelationID, int nCorrelationIDLength, char *szResponseQueuename, int nReplyQueuenameLength, int *bMQConnection, int *bChannelOpen, uint64_t nDeliveryTag);
int ProcessMessageMQRespData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, char *pData, int nDataLength, char *szCorrelationID, int nCorrelationIDLength, char *szResponseQueuename, int nReplyQueuenameLength, int *bMQConnection, int *bChannelOpen, uint64_t nDeliveryTag);
int ProcessFileMQData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, char *pData, int nDataLength, char *szCorrelationID, int nCorrelationIDLength, char *szResponseQueuename, int nReplyQueuenameLength, int *bMQConnection, int *bChannelOpen, uint64_t nDeliveryTag);
int FileSendStart(struct SOCKET_THREAD_INFO *pThreadinfo, int nChannelNo, struct FILE_SEND_REQUEST *pFileSendRequest);
int MakeFileTransferResult(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannel, int bComplete, char *szProcCode, char *pszFrameMessage, int nFrameSize);
int SendFileResponse(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, struct FILE_PACKET *pRecvFilePacket, int nRespCodeID);
int SendFilePacket(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, char *pszOrganizationID, int nOrganizationIDLen, char cOccurType, int nWorkTypeCode, int nMsgTypeCode, char *pszFilename, int nFilenameLen, char *pszRequestDTime, int nRequestDTimeLen, int nRespCode, char *pData, uint16_t nDataLen);
void CalculateBlockSeqCount(int nSocketIndex, int nChannelNo, int nFileSize, int *pnBlockCount, int *pnSeqCount);
int WriteEmptyFileBlock(int nSocketIndex, int nChannelNo);
int GetMissedSeqNo(int nSocketIndex, int nChannelNo);
int GetFileData(int nSocketIndex, int nChannelNo, int nCurrentBlockNo, int nCurrentSeqNo, char *pszDataBuffer, int nDataBufferSize);
int PutFileData(int nSocketIndex, int nChannelNo, int nCurrentBlockNo, int nCurrentSeqNo, const char *pszDataBuffer, int nDataBufferSize);
int GetMissedDataCount(int nSocketIndex, int nChannelNo);
void StateClear(int nSocketIndex, int nChannelNo);


END_DECLS

#endif
