/*
#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>
#include "Common.h"
#include "Config.h"
#include "Log.h"
#include "DataStructure.h"
#include "Socket.h"
#include "StringUtil.h"
#include "SystemUtil.h"
*/
#include "RcvHQ.h"

char g_szProcessname[MAX_STRING_SIZE + 1];
char g_szProcessPath[PATH_MAX + 1];
//int g_nChannels;
//struct CHANNEL_MODE g_sChannelModeFlags[GW_CONFIG_CHANNEL_COUNT];
int g_nConnectType;
char g_szFileRecvPath[MAX_STRING_SIZE + 1];
char g_szFileRecvPathTemp[MAX_STRING_SIZE + 1];
int g_bFileMoveYN;
int g_nFileDataSize;
int g_nMaxSeqCount;

struct FILE_TRANSFER_STATE (*g_pFileTransferState)[SOCK_CONF_MAX_CHANNEL_LIMIT];

struct VALUE_STRING_PAIR_INFO g_sWorkTypeInfo[] =
{
    { MSG_FILE_WORK_TYPE_WORK_START_REQ,                "0600",},
    { MSG_FILE_WORK_TYPE_WORK_START_RESP,               "0610",},
    { MSG_FILE_WORK_TYPE_FILE_INFO_SEND,                "0630",},
    { MSG_FILE_WORK_TYPE_FILE_INFO_RESP,                "0640",},
    { MSG_FILE_WORK_TYPE_DATA_SEND,                     "0320",},
    { MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_REQ,           "0620",},
    { MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_RESP,          "0300",},
    { MSG_FILE_WORK_TYPE_MISSED_DATA_SEND,              "0310",},
};

struct VALUE_STRING_PAIR_INFO g_sMsgTypeInfo[] =
{
    { MSG_FILE_MSG_TYPE_NONE,                           "0000",},
    { MSG_FILE_MSG_TYPE_WORK_START,                     "0001",},
    { MSG_FILE_MSG_TYPE_FILE_TRANSFER_NEXT,             "0002",},
    { MSG_FILE_MSG_TYPE_FILE_TRANSFER_END,              "0003",},
    { MSG_FILE_MSG_TYPE_WORK_END,                       "0004",},
};

struct VALUE_STRING_PAIR_INFO g_sFileSendResultInfo[] =
{
    { GW_FILE_SEND_ERR_SUCCESS,                         "0000",},
    { GW_FILE_SEND_ERR_REQUEST_MSG_FORMAT,              "0001",},
    { GW_FILE_SEND_ERR_FILE_ACCESS,                     "0002",},
    { GW_FILE_SEND_ERR_PROTOCOL,                        "0003",},
};
int main(int argc, char *argv[])
{
    
    char szUTF8Temp[MAX_STRING_SIZE + 1];
    char szStringOutput[MAX_STRING_SIZE + 1];
    char szProcessname[PATH_MAX + 1];
    char *pFindPointer;
    //int nPathIndicatorPos;
    int nResult;
//    printf_s("Daemon Start\n");

//#if defined(_WIN32) && defined(UNICODE)
//    SetConsoleOutputCP(CP_UTF8);
//    SetConsoleCP(CP_UTF8);
//    setlocale(LC_ALL, "ko-KR")
//    CONSOLE_FONT_INFOEX info = {0};
//    info.cbSize       = sizeof(info);
//    info.dwFontSize.Y = 16; // leave X as zero
//    info.FontWeight   = FW_NORMAL;
//    wcscpy(info.FaceName, L"굴림체");
//    SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), NULL, &info);
//#endif

    DaemonStart();
//    printf_s("Daemon End\n");
    nResult = SafeStrCopy(szProcessname, sizeof(szProcessname), argv[0]);
    if (nResult != SEC_ERR_SUCCESS)
    {
        printf_s("strcpy_s Error![%d]\n", nResult);
    }
//    printf_s("Input argument : [%s]\n", argv[0]);
    pFindPointer = szProcessname;
    
    nResult = SafeStrrChr(szProcessname, strnlen(szProcessname, sizeof(szProcessname)), PATH_SEPERATOR, &pFindPointer);
#ifdef _WIN32
    ASCIIToUTF8(argv[0], strlen(argv[0]), szUTF8Temp, sizeof(szUTF8Temp));
    snprintf(szStringOutput, sizeof(szStringOutput), "argv[0] : %s\n", szUTF8Temp);
    printf(szStringOutput);
#else
    printf("argv[0] : %s\n", argv[0]);
#endif
    printf("문자열길이 : %64d\n", strnlen(szProcessname, sizeof(szProcessname)));
    printf_s("szProcessname Address : %x\n", szProcessname);
    printf_s("pFindPointer Address : %X\n", (unsigned long)pFindPointer);
    printf_s("szProcess Name : %s\n", szProcessname);
    
//    if (nResult != STR_ERR_SUCCESS)
//    {
//        printf_s("SafeStrrChr Error![%d]\n", nResult);
//        return -1;
//    }

    if (pFindPointer == NULL)
    {
        nResult = SafeStrCopy(g_szProcessname, sizeof(g_szProcessname), szProcessname);
    }
    else
    {
        nResult = SafeStrCopy(g_szProcessname, sizeof(g_szProcessname), pFindPointer + 1);
    }
//    printf_s("szProcess Name : %s\n", szProcessname);
//    printf_s("g_szProcess Name : %s\n", g_szProcessname);
//    printf("Start Get Exec Path\n");
    
    GetExecPath(g_szProcessPath, sizeof(g_szProcessPath) - 1, argv[0]);
    printf_s("g_szProcessPath : %s\n", g_szProcessPath);
    
    
    if (g_szProcessPath == NULL)
    {
        printf_s("Can't get process path[Cann't load config file]!\nExit Program!\n");
        return -1;
    }
    
    printf_s("Start Init Config\n");
    nResult = InitGWConfig();

    if (nResult != GW_ERR_SUCCESS)
    {
        printf_s("Program terminated!!!\n");
        return -1;
    }

    //printf_s("RSIZE_MAX:%d, RSIZE_MAX_STR:%d, RSIZE_MAX_MEM:%d\n", RSIZE_MAX, RSIZE_MAX_STR, RSIZE_MAX_MEM);
    WriteLog(LogType_SystemOut,LogLevel_Info, "Process Started![%s]", g_szProcessname);

    /* Socket 처리 루프 : 종료시 프로그램 종료됨 */
    printf("Start InitSocket\n");

    InitSocket();

    WriteLog(LogType_SystemOut,LogLevel_Info, "Process Stopped![%s]", g_szProcessname);

    return 0;

}

int InitGWConfig()
{
    char szConfigfilename[PATH_MAX + 1];
    char szConfigfilenameTemp[PATH_MAX + 1];
    char szStringTemp[MAX_STRING_SIZE + 1];
    int nChannelNo;
    int nResult;
    int nSocketIndex;

    nResult = 0;
    snprintf(szConfigfilenameTemp, sizeof(szConfigfilenameTemp), "%s%c%s%c", g_szProcessPath, PATH_SEPERATOR, CONF_FILE_PATH, PATH_SEPERATOR);

    realpath(szConfigfilenameTemp, szConfigfilename);

    snprintf(szStringTemp, sizeof(szStringTemp), "%c", PATH_SEPERATOR);
    nResult = SafeStrCat(szConfigfilename, sizeof(szConfigfilename), szStringTemp, 1);
    nResult = SafeStrCat(szConfigfilename, sizeof(szConfigfilename), g_szProcessname, strnlen_s(g_szProcessname, sizeof(g_szProcessname)));
    nResult = SafeStrCat(szConfigfilename, sizeof(szConfigfilename), CONF_FILE_EXT, strnlen_s(CONF_FILE_EXT, sizeof(CONF_FILE_EXT)));

    printf("Process Name : %s\n", g_szProcessname);
    printf("Process Path : %s\n", g_szProcessPath);
    printf("Config Filename : %s\n", szConfigfilename);

    ReadConfigFile(true, szConfigfilename);

    if (InitLogConfig() != LOG_ERR_SUCCESS)
    {
        printf_s("Init Log Config Error\n");
        return GW_ERR_CONFIG;
    }
    
    if (InitSocketConfig() != SOCK_ERR_SUCCESS)
    {
        printf_s("Init Socket Config Error\n");
        return GW_ERR_CONFIG;
    }
    
    if (InitMQConfig() != MQ_ERR_SUCCESS)
    {
        printf_s("Init Message Queue Config Error\n");
        return GW_ERR_CONFIG;
    }

    if (GetConfigValue(GW_FILE_RECV_PATH_KEY, g_szFileRecvPath, sizeof(g_szFileRecvPath)) != CONF_ERR_SUCCESS)
    {
        printf_s("Can't find config key[%s]. Check the config file\n", GW_FILE_RECV_PATH_KEY);
        return GW_ERR_CONFIG;
    }

    if (GetConfigValue(GW_FILE_MOVE_YN_KEY, szStringTemp, sizeof(szStringTemp)) != CONF_ERR_SUCCESS)
    {
        printf_s("Can't find config key[%s]. Check the config file\n", GW_FILE_MOVE_YN_KEY);
        return GW_ERR_CONFIG;
    }
    if (ParsingYESNO(szStringTemp, sizeof(szStringTemp), &g_bFileMoveYN) != CONF_ERR_SUCCESS)
    {
        printf_s("Can't find config key[%s]. Check the config file\n", GW_FILE_MOVE_YN_KEY);
        return GW_ERR_CONFIG;
    }

    if (g_bFileMoveYN == true)
    {
        if (GetConfigValue(GW_FILE_RECV_PATH_TEMP_KEY, g_szFileRecvPathTemp, sizeof(g_szFileRecvPathTemp)) != CONF_ERR_SUCCESS)
        {
            printf_s("Can't find config key[%s]. Check the config file\n", GW_FILE_RECV_PATH_TEMP_KEY);
            return GW_ERR_CONFIG;
        }
    }

    if (GetConfigValue(GW_CONFIG_FILE_DATA_SIZE_KEY, szStringTemp, sizeof(szStringTemp)) != CONF_ERR_SUCCESS)
    {
        printf_s("Can't find config key[%s]. Check the config file\n", GW_CONFIG_FILE_DATA_SIZE_KEY);
        return GW_ERR_CONFIG;
    }
    if (SafeStringToInt(szStringTemp, sizeof(szStringTemp), &g_nFileDataSize) != CONF_ERR_SUCCESS)
    {
        WriteLog(LogType_ErrorOut, LogLevel_Error, "Socket FILE_DATA_SIZE configuration error[ConfigFile:%s]!", szStringTemp);
        return SOCK_ERR_CONFIG;
    }

    if (GetConfigValue(GW_CONFIG_MAX_SEQ_COUNT_KEY, szStringTemp, sizeof(szStringTemp)) != CONF_ERR_SUCCESS)
    {
        printf_s("Can't find config key[%s]. Check the config file\n", GW_CONFIG_MAX_SEQ_COUNT_KEY);
        return GW_ERR_CONFIG;
    }
    if (SafeStringToInt(szStringTemp, sizeof(szStringTemp), &g_nMaxSeqCount) != CONF_ERR_SUCCESS)
    {
        WriteLog(LogType_ErrorOut, LogLevel_Error, "Socket MAX_SEQ_COUNT configuration error[ConfigFile:%s]!", szStringTemp);
        return GW_ERR_CONFIG;
    }


    g_fnProcessMessageSocketData = ProcessMessageSocketData;
    g_fnProcessFileSocketData = ProcessFileSocketData;
    g_fnProcessMessageMQSendData = ProcessMessageMQSendData;
    g_fnProcessMessageMQRespData = ProcessMessageMQRespData;
    g_fnProcessFileMQData = ProcessFileMQData;
    g_fnInitializeFileTransferData = InitFileTransferState;

    SafeMemoryAlloc((void **)&g_pFileTransferState, sizeof(struct FILE_TRANSFER_STATE) * SOCK_CONF_MAX_CHANNEL_LIMIT * g_nMaxConnections);
    for (nSocketIndex = 0; nSocketIndex < g_nMaxConnections; nSocketIndex++)
    {
        InitFileTransferState(nSocketIndex);
    }

    return GW_ERR_SUCCESS;
}

void InitFileTransferState(int nSocketIndex)
{
    int nChannelNo;
    int nResult;

    for (nChannelNo = 0; nChannelNo < SOCK_CONF_MAX_CHANNEL_LIMIT; nChannelNo++)
    {
//        nResult = SafeMemoryAlloc((void **)&g_pFileTransferState[nChannelNo], sizeof(struct FILE_TRANSFER_STATE));
//        if (nResult != STR_ERR_SUCCESS)
//        {
//            WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "SafeMemoryAlloc 함수 오류");
//            return GW_ERR_CONFIG;
//        }
//        SafeMemSet(g_pFileTransferState[nChannelNo], sizeof(struct FILE_TRANSFER_STATE), 0, sizeof(struct FILE_TRANSFER_STATE));
//        nResult = SafeMemoryAlloc((void **)&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pSeqReceived, g_nMaxSeqCount);
//        if (nResult != STR_ERR_SUCCESS)
//        {
//            WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "SafeMemoryAlloc 함수 오류");
//            return GW_ERR_CONFIG;
//        }
        SafeMemSet(&g_pFileTransferState[nSocketIndex][nChannelNo], sizeof(struct FILE_TRANSFER_STATE), 0, sizeof(struct FILE_TRANSFER_STATE));
        nResult = SafeMemoryAlloc((void **)&g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived, g_nMaxSeqCount);
        if (nResult != STR_ERR_SUCCESS)
        {
            WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "SafeMemoryAlloc 함수 오류");
            //return GW_ERR_CONFIG;
        }
    }

}

int ProcessMessageSocketData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo)
{
    struct DOUBLELINKEDLISTNODE *pListNode;
    struct DOUBLELINKEDLISTNODE *pNewNode;
    struct MESSAGE_PACKET sMessagePacket;
    struct MESSAGE_RESPONSE_INFO *pResponseInfo;
    struct MESSAGE_INFO *pMessageInfo;
    int nResult;
    int nCompareResult;
    //amqp_basic_properties_t sProperties;
    char szUUIDString[UUID_STRING_SIZE + 1];
    char szTopic[MAX_STRING_SIZE + 1];
    char szResponseQueuename[MAX_STRING_SIZE + 1];
    char aMessageBody[SOCK_BUFFER_SIZE + 1];
    char szRespCode[SOCK_FRAME_LEN_RESP_CODE + 1];
    int nMessageLength;
    //amqp_rpc_reply_t sAMQPReply;
    //amqp_bytes_t mqExchangename;
    //amqp_bytes_t mqTopic;
    //amqp_bytes_t mqMessageBody;
    int nResponseQueuenameLength;
    uint64_t nDeliveryTag;

    /*
    struct MESSAGE_RESPONSE_INFO
    {
        int nMessageLength;
        char *paMessageData;
        void *pHeaderInfo;
        uuid_t aUUID;
        char szResponseQueuename[MAX_STRING_SIZE + 1];
        int bResponse;
        struct tm sTransferTime;
        int nTransferMilliSecond;
    };
     */
    pListNode = NULL;
    pResponseInfo = NULL;
    pthread_mutex_lock(&pThreadInfo->sChannelRecvMutex[nChannelNo]);
    if (pThreadInfo->sChannelRecvFrameBuffer[nChannelNo].nNodeCount != 0)
    {
        DoubleLinkedListRemoveTailNode(&pThreadInfo->sChannelRecvFrameBuffer[nChannelNo], &pListNode);
    }
    pthread_mutex_unlock(&pThreadInfo->sChannelRecvMutex[nChannelNo]);

    if (pListNode != NULL)
    {

        pMessageInfo = (struct MESSAGE_INFO *)pListNode->pNodeData;
        nResult = ParseMessageHeader(&sMessagePacket, pMessageInfo);
        if (nResult == GW_ERR_SUCCESS)
        {
            // 수신 처리중 전문이 수신된 경우 처리를 어떻게 할 것인지? (Async로 구현하고 sync는 async에서 처리중인 전문이 1개만 가능한 것으로 처리)
            /* sync에서 이미 처리중인 전문이 있는 경우
             *      1. 상대측에서 전송한 것이라면 이미 처리중인 전문 있음 오류등 오류 메시지 전송(socket 측에서 수신된 경우)
             *      2. 내부 SendQueue라면 하나씩만 처리
             *
             * 일단 timeout은 넘어가자 처리하고 기본기능 완료하고 timeout 추가하자
             * 비동기에서 timeout 처리는 어차피 메시지 단위인데 timeout 처리 필요할까?
             * timeout을 Response 시간보다는 연결 끊김 감지를 못하는 경우를 대비해서 일정 통신이 없는 경우 연결 종료를 위한 것으로 처리하자
             * timeout이 너무 짧아도 Thread 재생성을 위한 오버헤드가 생기고 너무 길면 갑자기 동시에 연결이 끊어진 경우 세션 개수 한계로 연결이 되지 않을 수 있다.
             */

            if ((sMessagePacket.sHeader.cOccurType == 'C' && g_eConnectionType == SOCK_CONN_TYPE_SERVER) ||
                (sMessagePacket.sHeader.cOccurType == 'S' && g_eConnectionType == SOCK_CONN_TYPE_CLIENT))
            {
                //pResponseInfo = SafeMemoryAlloc(sizeof(struct MESSAGE_RESPONSE_INFO));
                //SafeMemSet(pResponseInfo, sizeof(struct MESSAGE_RESPONSE_INFO), 0, sizeof(struct MESSAGE_RESPONSE_INFO));
                //pResponseInfo->nMessageLength = pMessageInfo->nMessageLength;
                //pResponseInfo->paMessageData = SafeMemoryAlloc(pMessageInfo->nMessageLength + 1);
                //SafeMemCopy(pResponseInfo->paMessageData, pMessageInfo->nMessageLength + 1, pMessageInfo->paMessageData, pMessageInfo->nMessageLength + 1);
                //pResponseInfo->paMessageData[pResponseInfo->nMessageLength] = '\0';
                //uuid_generate(pResponseInfo->aUUID);
                //uuid_unparse(pResponseInfo->aUUID, szUUIDString);
                //WriteLog(LogType_StandardOut, LogLevel_Info, "Process Socket Recv Message");
                snprintf(szResponseQueuename, sizeof(pResponseInfo->szResponseQueuename), "%s%s.%02d", g_szMQMessageRecvRespQueuename, g_szMQTargetOrganizationCode, pThreadInfo->nSocketIndex);
                snprintf(szTopic, sizeof(szTopic), "%s.%s%s", sMessagePacket.sHeader.szOrganizationCode, sMessagePacket.sHeader.szWorkType, sMessagePacket.sHeader.szMsgType);
                SafeMemCopy(aMessageBody, sizeof(aMessageBody), pMessageInfo->paMessageData + 2, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE);
                aMessageBody[pMessageInfo->nMessageLength - SOCK_PACKET_SIZE] = '\0';
                /*
                sProperties._flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
                               AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_REPLY_TO_FLAG |
                               AMQP_BASIC_CORRELATION_ID_FLAG;
                sProperties.content_type = amqp_cstring_bytes("text/plain");
                sProperties.delivery_mode = 2;
                sProperties.reply_to = amqp_cstring_bytes(szResponseQueuename);
                if (sProperties.reply_to.bytes == NULL)
                {
                  fprintf(stderr, "Out of memory while copying queue name");
                  return 1;
                }
                sProperties.correlation_id = amqp_cstring_bytes(szUUIDString);

                mqExchangename = amqp_cstring_bytes(g_szMQMessageRecvExchangername);
                mqTopic = amqp_cstring_bytes(szTopic);
                mqMessageBody = amqp_cstring_bytes(aMessageBody);
                */
#ifdef _WIN32
                uuid_unparse(&pMessageInfo->aUUID, szUUIDString);
#else
                uuid_unparse(pMessageInfo->aUUID, szUUIDString);
#endif
                WriteCommLog(LogType_CommOut, LogLevel_Info, pThreadInfo->nSocket, nChannelNo, 'R', "%-*.*s,%s", UUID_STRING_SIZE, UUID_STRING_SIZE, szUUIDString, pMessageInfo->paMessageData);
                if (g_bBypassMode)
                {
                    nResult = PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, g_szMQMessageRecvExchangername, szResponseQueuename, szTopic, pMessageInfo, aMessageBody, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE, szUUIDString, sizeof(szUUIDString), true, &pThreadInfo->sChannelRecvResponseBuffer[nChannelNo]);
                }
                else
                {
                    nResult = PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, g_szMQMessageRecvExchangername, szResponseQueuename, szTopic, pMessageInfo, aMessageBody, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE, szUUIDString, sizeof(szUUIDString), false, &pThreadInfo->sChannelRecvResponseBuffer[nChannelNo]);
                }
                if (nResult != MQ_ERR_SUCCESS)
                {
                    WriteLog(LogType_ErrorOut, LogLevel_Info, "MQ publish error[Type:%c,Exc:%s,Topic:%s,UUID:%s,Len:%05d,Data:%s]", 'P', g_szMQMessageRecvExchangername, szTopic, szUUIDString, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE, aMessageBody);
                    SafeFree((void **)&pListNode);
                    //DoubleLinkedListAddNodeToHead(&pThreadInfo->sChannelRecvFrameBuffer[nChannelNo], pMessageInfo, &pListNode);
                    SafeStrCopy(szRespCode, sizeof(szRespCode), MSG_MQERROR_RESP_CODE);
                }
                else
                {
                    WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'P', g_szMQMessageRecvExchangername, szTopic, szUUIDString, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE, "%s", aMessageBody);
                    //nResult = PutMessageToQueue(pThreadInfo->sMQConnectionState, nChannelNo, g_szMQMessageRecvExchangername, szResponseQueuename, szTopic, pMessageInfo, aMessageBody, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE);
                    //nResult = amqp_basic_publish(pThreadInfo->sMQConnectionState, 1, mqExchangename, mqTopic, 0, 0, &sProperties, mqMessageBody);

                    switch (nResult)
                    {
                    case MQ_ERR_SUCCESS:
    //                    if (!g_bBypassMode)
    //                    {
    //                        nMessageLength = sizeof(aMessageBody);
    //                        nResult = MakeMSGFrame(sMessagePacket.sHeader.szOrganizationCode,   sizeof(sMessagePacket.sHeader.szOrganizationCode), sMessagePacket.sHeader.cOccurType
    //                                               , sMessagePacket.sHeader.szWorkType,         sizeof(sMessagePacket.sHeader.szWorkType)
    //                                               , sMessagePacket.sHeader.szMsgType,          sizeof(sMessagePacket.sHeader.szMsgType)
    //                                               , sMessagePacket.sHeader.szSerialNo,         sizeof(sMessagePacket.sHeader.szSerialNo)
    //                                               , sMessagePacket.sHeader.szRequestDTime,     sizeof(sMessagePacket.sHeader.szRequestDTime)
    //                                               , MSG_SUCCESS_RESP_CODE,                     sizeof(MSG_SUCCESS_RESP_CODE)
    //                                               , "",                                        0
    //                                               , aMessageBody,                              &nMessageLength
    //                                               );
    //                        if (nResult != SOCK_ERR_SUCCESS)
    //                        {
    //                            WriteLog(LogType_ErrorOut, LogLevel_Debug, "MakeMSGFrame error[UUID:%s]", szUUIDString);
    //                        }
    //                        else
    //                        {
    //                            nResult = SendPacket(pThreadInfo, nChannelNo, &pResponseInfo->aUUID, aMessageBody, nMessageLength);
    //                            if (nResult != SOCK_ERR_SUCCESS)
    //                            {
    //                                WriteLog(LogType_ErrorOut, LogLevel_Debug, "MakeMSGFrame error[UUID:%s]", szUUIDString);
    //                            }
    //                        }
    //                    }
                        SafeStrCopy(szRespCode, sizeof(szRespCode), MSG_SUCCESS_RESP_CODE);
                        break;
                    default:
                        // 오류 발생시 다시 Head에 추가하는 코드 생성되어 있으나 의미 있을까? 로그 남기고 삭제 하는것이 누적되지 않아 정상동작 할 것으로 판단됨
    //                    pthread_mutex_lock(&pThreadInfo->sChannelRecvMutex[nChannelNo]);
    //                    DoubleLinkedListAddNodeToHead(&pThreadInfo->sChannelRecvFrameBuffer[nChannelNo], pListNode->pNodeData, &pNewNode);
    //                    pthread_mutex_unlock(&pThreadInfo->sChannelRecvMutex[nChannelNo]);
                        SafeFree((void **)&pMessageInfo->paMessageData);
                        SafeFree((void **)&pMessageInfo);
                        pListNode->pNodeData = NULL;
                        SafeFree((void **)&pListNode);
                        SafeStrCopy(szRespCode, sizeof(szRespCode), MSG_MQERROR_RESP_CODE);
                        return GW_ERR_MQ_ERROR;

                        /*
                    AMQP_STATUS_OK on success, amqp_status_enum value on failure. Note that basic.publish is an async method, the return value from this function only indicates that the message data was successfully transmitted to the broker. It does not indicate failures that occur on the broker, such as publishing to a non-existent exchange. Possible error values:
                    AMQP_STATUS_TIMER_FAILURE: system timer facility returned an error the message was not sent.
                    AMQP_STATUS_HEARTBEAT_TIMEOUT: connection timed out waiting for a heartbeat from the broker. The message was not sent.
                    AMQP_STATUS_NO_MEMORY: memory allocation failed. The message was not sent.
                    AMQP_STATUS_TABLE_TOO_BIG: a table in the properties was too large to fit in a single frame. Message was not sent.
                    AMQP_STATUS_CONNECTION_CLOSED: the connection was closed.
                    AMQP_STATUS_SSL_ERROR: a SSL error occurred.
                    AMQP_STATUS_TCP_ERROR: a TCP error occurred. errno or WSAGetLastError() may provide more information
                         */
                    }
                }
                if (!g_bBypassMode)
                {
                    //int MakeMSGFrame(char *pszOrganizationID, int nOrganizationIDLen, char cOccurType,
                    //                 , char *pszWorkType, int nWorkTypeLen
                    //                 , char *pszMsgType, int nMsgTypeLength
                    //                 , char *pszSerialID, int nSerialIDLen
                    //                 , char *pszRequestDTime, int nRequestDTimeLen
                    //                 , char *pszResponseCode, int nResponseCodeLen
                    //                 , char *pData, int nDataLen
                    //                 , char *pszFrameData, int *nFrameDataLen)
                    nMessageLength = sizeof(aMessageBody);
                    nResult = MakeMSGFrame(sMessagePacket.sHeader.szOrganizationCode,   sizeof(sMessagePacket.sHeader.szOrganizationCode), sMessagePacket.sHeader.cOccurType
                                           , sMessagePacket.sHeader.szWorkType,         sizeof(sMessagePacket.sHeader.szWorkType)
                                           , sMessagePacket.sHeader.szMsgType,          sizeof(sMessagePacket.sHeader.szMsgType)
                                           , sMessagePacket.sHeader.szSerialNo,         sizeof(sMessagePacket.sHeader.szSerialNo)
                                           , sMessagePacket.sHeader.szRequestDTime,     sizeof(sMessagePacket.sHeader.szRequestDTime)
                                           , szRespCode,                                sizeof(szRespCode)
                                           , "",                                        0
                                           , aMessageBody,                              &nMessageLength
                                           );
                    //int SendPacket(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, uuid_t *pUUID, const char *aMessageBody, int nMessageBodySize)
                    if (nResult != SOCK_ERR_SUCCESS)
                    {
                        WriteLog(LogType_ErrorOut, LogLevel_Debug, "MakeMSGFrame error[UUID:%s]", szUUIDString);
                    }
                    else
                    {
                        nResult = SendPacket(pThreadInfo, nChannelNo, &pMessageInfo->aUUID, aMessageBody, nMessageLength);
                        if (nResult != SOCK_ERR_SUCCESS)
                        {
                            WriteLog(LogType_ErrorOut, LogLevel_Debug, "MakeMSGFrame error[UUID:%s]", szUUIDString);
                        }
                    }
                }

                // amqp_cstring_bytes함수는 메모리 복사하는것이 아니라 문자열 길이를 저장하고 기존 문자열의 포인트를 저장하는 Wrapper이므로 amqp_bytes_free를 사용하면 안된다.
                //amqp_bytes_free(sProperties.content_type);
                //amqp_bytes_free(sProperties.correlation_id);
                //amqp_bytes_free(mqExchangename);
                //amqp_bytes_free(mqTopic);
                //amqp_bytes_free(mqMessageBody);
                //amqp_bytes_free(sProperties.reply_to);
            }
            else if ((sMessagePacket.sHeader.cOccurType == 'S' && g_eConnectionType == SOCK_CONN_TYPE_SERVER) ||
                      (sMessagePacket.sHeader.cOccurType == 'C' && g_eConnectionType == SOCK_CONN_TYPE_CLIENT))
            {
                //WriteLog(LogType_StandardOut, LogLevel_Info, "Process Socket Response Message");
                //snprintf(szResponseQueuename, sizeof(pResponseInfo->szResponseQueuename), "%s.%02d", g_szMQMessageSendQueuename, pThreadInfo->nSocketIndex);
                snprintf(szTopic, sizeof(szTopic), "%s.%s%s", sMessagePacket.sHeader.szOrganizationCode, sMessagePacket.sHeader.szWorkType, sMessagePacket.sHeader.szMsgType);
                SafeMemCopy(aMessageBody, sizeof(aMessageBody), pMessageInfo->paMessageData + 2, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE);
                aMessageBody[pMessageInfo->nMessageLength - SOCK_PACKET_SIZE] = '\0';
                //int ProcessRecvSocketResponse(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, const char *aMessageBody, int nMessageBodySize, const char *szUUIDString, int nUUIDStringSize)
                nResult = SafeStrCmp(sMessagePacket.sHeader.szRespCode, sizeof(sMessagePacket.sHeader.szRespCode), MSG_SUCCESS_RESP_CODE, &nCompareResult);
                nResult = ProcessRecvSocketResponse(pThreadInfo, nChannelNo, aMessageBody, pMessageInfo->nMessageLength - SOCK_PACKET_SIZE, szUUIDString, sizeof(szUUIDString), nCompareResult == 0);
            }
            else
            {
                // 전문 타입 오류
            }

        }
        else
        {
            /*
             * 통신 프로토콜 설계에 응답 오류에 대한 처리 부분 보완 필요
             * 보완 이후에 추가 수정 진행
             */

        }
        SafeFree((void **)&pMessageInfo->paMessageData);
        SafeFree((void **)&pMessageInfo);
        SafeFree((void **)&pListNode);
    }
    amqp_maybe_release_buffers(pThreadInfo->sPublishMQ.sMQConnectionState);
    //if (amqp_frames_enqueued(pThreadInfo->sConsumeMQ.sMQConnectionState) || amqp_data_in_buffer(pThreadInfo->sConsumeMQ.sMQConnectionState))
    //if (MQReadCheck(pThreadInfo->sConsumeMQ.sMQConnectionState))
/*
    amqp_maybe_release_buffers(pThreadInfo->sConsumeMQ.sMQConnectionState);
    if (amqp_frames_enqueued(pThreadInfo->sConsumeMQ.sMQConnectionState) || amqp_data_in_buffer(pThreadInfo->sConsumeMQ.sMQConnectionState)
        || MQReadCheck(pThreadInfo->sConsumeMQ.sMQConnectionState))
    {
        nResult = GetMessageFromQueue(pThreadInfo->sConsumeMQ.sMQConnectionState, aMessageBody, sizeof(aMessageBody), szUUIDString, sizeof(szUUIDString), szResponseQueuename, sizeof(szResponseQueuename), &pThreadInfo->sConsumeMQ.bMQConnection, &pThreadInfo->sConsumeMQ.bMQChannelOpen, &nDeliveryTag, NULL);
        nMessageLength = strnlen(aMessageBody, sizeof(aMessageBody));
        if (nResult == MQ_ERR_SUCCESS)
        {
            nResponseQueuenameLength = strnlen(szResponseQueuename, sizeof(szResponseQueuename));
            if (nResponseQueuenameLength == 0)
            {
                amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
                WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'C', g_szMQMessageSendExchangername, "", szUUIDString, nMessageLength, "%s", aMessageBody);
                ProcessRecvQueueResponse(pThreadInfo, nChannelNo, aMessageBody, sizeof(aMessageBody), szUUIDString, sizeof(szUUIDString));
            }
            else
            {
                amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
                WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'C', g_szMQMessageSendQueuename, "", szUUIDString, nMessageLength, "%s", aMessageBody);
                SendMessage(pThreadInfo, nChannelNo, aMessageBody, nMessageLength, szUUIDString, sizeof(szUUIDString), szResponseQueuename, sizeof(szResponseQueuename));
            }
        }
        else
        {
            WriteTraceLog(LogType_ErrorOut, LogLevel_Debug, __FILE__, __LINE__, __FUNCTION__, "GetMessageFromQueue Error!");
            amqp_basic_nack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0, 1);
        }
    }
*/
    ProcessSendTimeout(pThreadInfo, nChannelNo);
    ProcessResponseTimeout(pThreadInfo, nChannelNo);
    //free(pListNode->pNodeData);
    //pListNode->pNodeData = NULL;
    //free(pListNode);
    //pListNode = (struct DOUBLELINKEDLISTNODE *)NULL;
    return GW_ERR_SUCCESS;
}

int ParseMessageHeader(struct MESSAGE_PACKET *pPacket, struct MESSAGE_INFO *pData)
{
    /*
    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 MESSAGE_HEADER
    {
        char szOrganizationCode[MSG_LEN_ORGANIZATIONCODE + 1];
        char szOccurType;
        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_REPLY_CODE + 1];
    };

    struct MESSAGE_INFO
    {
        int nMessageLength;
        char *paMessageData;
    };

    TYPE_DIGIT = 0,                   // Character로 표시된 문자형태 "0100" : 단 10진수 형태의 사용만
    TYPE_ALPHA,                       // 영문으로 표시된 문자형태(TODO : 한글 별도로 체크 해야 되는지? isalpha로 체크 되는지 확인 필요)
    TYPE_ALPHA_NUMERIC,               // TYPE_DIGIT || TYPE_ALPHA
    TYPE_HEX,                         // 16진수 문자열 확인
    TYPE_BCD,                         // BCD 바이너리를 만족하는지 확인(BCD 텍스트로 해야할지 고민중)
    TYPE_DATE8,                       // YYYYMMDD
    TYPE_DATE6,                       // YYMMDD
    TYPE_TIME6,                       // HHMMSS
    TYPE_TIME9,                       // HHMMSSFFF
    TYPE_DTIME12,                     // YYMMDDHHMMSS
    TYPE_DTIME14,                     // YYYYMMDDHHMMSS
    TYPE_DTIME17,
    */
    int nIndex;
    int nResult;
    uint16_t nPacketSize;
    char szStringBuffer[MAX_STRING_SIZE + 1];

    nIndex = SOCK_PACKET_LEN_STX;
    SafeMemSet(pPacket, sizeof(struct MESSAGE_PACKET), 0, sizeof(struct MESSAGE_PACKET));
    pPacket->cChannelNo = pData->paMessageData[nIndex];
    nIndex += sizeof(pPacket->cChannelNo);
    nResult = GetCheckedValue(TYPE_HEX, pPacket->szMsgLen, sizeof(pPacket->szMsgLen) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->szMsgLen) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Header Length:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->szMsgLen) - 1;
    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szOrganizationCode, sizeof(pPacket->sHeader.szOrganizationCode) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szOrganizationCode) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Organization Code:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szOrganizationCode) - 1;
    pPacket->sHeader.cOccurType = pData->paMessageData[nIndex];
    nIndex += sizeof(pPacket->sHeader.cOccurType);
    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szWorkType, sizeof(pPacket->sHeader.szWorkType) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szWorkType) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Work Type:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szWorkType) - 1;
    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szMsgType, sizeof(pPacket->sHeader.szMsgType) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szMsgType) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Message Type:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szMsgType) - 1;
    nResult = GetCheckedValue(TYPE_DIGIT, pPacket->sHeader.szSerialNo, sizeof(pPacket->sHeader.szSerialNo) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szSerialNo) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Serial No:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szSerialNo) - 1;
    nResult = GetCheckedValue(TYPE_DIGIT, pPacket->sHeader.szRequestDTime, sizeof(pPacket->sHeader.szRequestDTime) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szRequestDTime) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Request Date & Time:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szRequestDTime) - 1;
    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szRespCode, sizeof(pPacket->sHeader.szRespCode) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szRespCode) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Reply Code:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szRespCode) - 1;
    SafeMemCopy(pPacket->szData, sizeof(pPacket->szData), pData->paMessageData + nIndex, pData->nMessageLength - nIndex - 4 - 1);
    pPacket->szData[pData->nMessageLength - nIndex - 4 - 1] = '\0';
    nIndex += pData->nMessageLength - nIndex - 4 - 1;
    nResult = GetCheckedValue(TYPE_HEX, pPacket->szCRC, sizeof(pPacket->szCRC) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->szCRC) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![CRC:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->szCRC) - 1;
    nIndex += SOCK_PACKET_LEN_ETX;
    if (nIndex != pData->nMessageLength)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv packet size error![Recv Message Size:%d, Parsing Message Size : %d]", pData->nMessageLength, nIndex + 1);
        return GW_ERR_PACKET_SIZE;
    }
    nResult = SafeHexStringToInt(pPacket->szMsgLen, sizeof(pPacket->szMsgLen) - 1, &nPacketSize);
    if ((nIndex - SOCK_PACKET_SIZE - SOCK_PACKET_LEN_MSG_LEN) != nPacketSize)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv Header size error![Header Size:%d, Parsing Size:%d]", nPacketSize, nIndex + 1 - SOCK_PACKET_SIZE);
        return GW_ERR_PACKET_SIZE;
    }
    return GW_ERR_SUCCESS;
}

int ProcessFileSocketData(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo)
{
    struct DOUBLELINKEDLISTNODE *pListNode;
//    struct DOUBLELINKEDLISTNODE *pNewNode;
    struct FILE_PACKET sRecvFilePacket;
//    struct FILE_PACKET sSendFilePacket;
    //struct MESSAGE_RESPONSE_INFO *pResponseInfo;
    struct MESSAGE_INFO *pMessageInfo;
    struct FILE_SEND_REQUEST sFileSendRequest;
    int nResult;
    int nStringCompareResult;
    //amqp_basic_properties_t sProperties;
    char szUUIDString[UUID_STRING_SIZE + 1];
//    char szTopic[MAX_STRING_SIZE + 1];
    char szResponseQueuename[MAX_STRING_SIZE + 1];
    char szRespCode[MSG_LEN_RESP_CODE + 1];
    char szMessageBody[SOCK_BUFFER_SIZE + 1];
    char szDataBuffer[SOCK_BUFFER_SIZE + 1];
    char szRequestDateTime[MSG_LEN_REQUEST_DTIME + 1];
    char szFilename[PATH_MAX + 1];
    int nMessageLength;
    //amqp_rpc_reply_t sAMQPReply;
    //amqp_bytes_t mqExchangename;
    //amqp_bytes_t mqTopic;
    //amqp_bytes_t mqMessageBody;
    int nResponseQueuenameLength;
    uint64_t nDeliveryTag;
    int nOffset;

    //int nWorkType;
    //int nMsgType;

    char szRespWorkType[MSG_LEN_WORK_TYPE + 1];

//    struct timespec sTimeSpec;
//    time_t sNow;

    int nStoredFileSize;
    struct FILE_INFO sRecvFileInfo;
    int nBlockCount;
    int nSeqCount;
    int nSeqNo;
    int nMissedDataCount;

    int nRecvBytes;


    /*
    struct MESSAGE_RESPONSE_INFO
    {
        int nMessageLength;
        char *paMessageData;
        void *pHeaderInfo;
        uuid_t aUUID;
        char szResponseQueuename[MAX_STRING_SIZE + 1];
        int bResponse;
        struct tm sTransferTime;
        int nTransferMilliSecond;
    };
     */
    pListNode = NULL;
    //pResponseInfo = NULL;
    pthread_mutex_lock(&pThreadInfo->sChannelRecvMutex[nChannelNo]);
    if (pThreadInfo->sChannelRecvFrameBuffer[nChannelNo].nNodeCount != 0)
    {
        DoubleLinkedListRemoveTailNode(&pThreadInfo->sChannelRecvFrameBuffer[nChannelNo], &pListNode);
    }
    pthread_mutex_unlock(&pThreadInfo->sChannelRecvMutex[nChannelNo]);

    if (pListNode != NULL)
    {
        pMessageInfo = (struct MESSAGE_INFO *)pListNode->pNodeData;
        nResult = ParseFileHeader(&sRecvFilePacket, pMessageInfo);

//        clock_gettime(CLOCK_REALTIME, &sTimeSpec);
//        sNow = sTimeSpec.tv_sec;
//        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nLastRecvMilliSec = sTimeSpec.tv_nsec / 1.0e6; // nanoseconds to milliseconds
//        localtime_r(&sNow, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sLastRecvTime);

        GetCurrTime(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sLastRecvTime, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nLastRecvMilliSec);

        GetDateTimeString(TYPE_DTIME14, szRequestDateTime, sizeof(szRequestDateTime));

        if (nResult == GW_ERR_SUCCESS)
        {

            // 이미 파일 채널에 파일이 전송중이지만 반대편으로 전송 요청이 수신된 경우 오류 처리
            // 이미 하나의 채널에서 전송중인데 반대편 전송 요청 시도가 처음 전문 이외에 수신 가능한가???
            if (sRecvFilePacket.sHeader.cOccurType != g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection && g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted == true)
            {
                // 이미 시작되었으면서 요청 채널이 다른 경우
                // 전문 구분이 시작인 경우에만 송신중 오류 전송
                // 전문 구분이 시작이 아닌 경우에는 어떻게 할 것인가? ( 시작이 아니면서 채널 정보나 송수신 정보가 다른 것은 프로토콜 오류로 판단하고 프로토콜 오류 전송)
                if (sRecvFilePacket.sHeader.nWorkType == MSG_FILE_WORK_TYPE_WORK_START_REQ)
                {
                    if (sRecvFilePacket.sHeader.nMsgType == MSG_FILE_MSG_TYPE_WORK_START)
                    {
                        //int MappingIntToString(const struct VALUE_STRING_PAIR_INFO *pPairInfo, int nPairInfoCount, int nValue, char *pStringValue, int nStringValue);
                        SendFileResponse(pThreadInfo, nChannelNo, &sRecvFilePacket, RESP_FILE_TRANSFERING);
                        return GW_ERR_SUCCESS;
                    }
                    else // 프로토콜 오류 처리
                    {
                        SendFileResponse(pThreadInfo, nChannelNo, &sRecvFilePacket, RESP_PROTOCOL_ERROR);
                        return GW_ERR_SUCCESS;
                    }
                }
                else // 프로토콜 오류 처리
                {
                    SendFileResponse(pThreadInfo, nChannelNo, &sRecvFilePacket, RESP_PROTOCOL_ERROR);
                    return GW_ERR_SUCCESS;
                }
            }
            //int MappingStringToInt(const char *szStringFlags, int nInputTagStringLength, const struct VALUE_STRING_PAIR_INFO *pPairInfo, int nMaxFlagInfoSize, int *pnValue)
            //nResult = MappingStringToInt(sRecvFilePacket.sHeader.szWorkType, sizeof(sRecvFilePacket.sHeader.szWorkType), g_sWorkTypeInfo, sizeof(g_sWorkTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), &nWorkType);
//            if (nResult != CONF_ERR_SUCCESS)
//            {
//
//            }
//            else
//            {
            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = sRecvFilePacket.sHeader.nWorkType;
            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentMsgType = sRecvFilePacket.sHeader.nMsgType;

            switch (sRecvFilePacket.sHeader.nWorkType)
            {
            case MSG_FILE_WORK_TYPE_WORK_START_REQ:

                switch (sRecvFilePacket.sHeader.nMsgType)
                {
                case MSG_FILE_MSG_TYPE_WORK_START:
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted = true;
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection = sRecvFilePacket.sHeader.cOccurType;
                    break;
                case MSG_FILE_MSG_TYPE_FILE_TRANSFER_NEXT: // 발생 불가(한번에 하나의 파일만 전송 : 발생해도 상관없다. 다음에 파일 시작될 때 신규 파일 처리하면 됨)
                case MSG_FILE_MSG_TYPE_FILE_TRANSFER_END:
                    // 수신된 파일 사이즈를 파일정보 사이즈와 비교하여 정상 여부 확인 필요
                    fclose(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile);
                    break;
                case MSG_FILE_MSG_TYPE_WORK_END:
                    // 상태 변수 초기화 신경써서 할 것
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted = false;
                    break;
                }
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = sRecvFilePacket.sHeader.nWorkType;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentMsgType = sRecvFilePacket.sHeader.nMsgType;

//                int SendFilePacket(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, char *pszOrganizationID, int nOrganizationIDLen,
//                        char cOccurType, int nWorkTypeCode, int nMsgTypeCode, char *pszFilename, int nFilenameLen, int nRespCode, char *pData, uint16_t nDataLen)
//                if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType == MSG_FILE_WORK_TYPE_WORK_START_REQ && g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentMsgType == MSG_FILE_MSG_TYPE_FILE_TRANSFER_END)
//                {
//                    SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode),
//                            sRecvFilePacket.sHeader.cOccurType, MSG_FILE_WORK_TYPE_WORK_START_REQ, MSG_FILE_MSG_TYPE_WORK_END, sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
//                            sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
//                            RESP_NORMAL, NULL, 0);
//                }
//                else
                {
                    SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode),
                            sRecvFilePacket.sHeader.cOccurType, MSG_FILE_WORK_TYPE_WORK_START_RESP, sRecvFilePacket.sHeader.nMsgType, sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
                            sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
                            RESP_NORMAL, NULL, 0);
                }

                nResult = MappingIntToString(g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), RESP_NORMAL, szRespCode, sizeof(szRespCode));
                if (nResult == CONF_ERR_NOT_FOUND)
                {
                    WriteLog(LogType_ErrorOut, LogLevel_Error, "Response code not found : [RESP_NORMAL]");
                }
                else
                {
                    nResult = MappingIntToString(g_sWorkTypeInfo, sizeof(g_sWorkTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), MSG_FILE_WORK_TYPE_WORK_START_RESP, szRespWorkType, sizeof(szRespWorkType));
                    if (nResult == CONF_ERR_NOT_FOUND)
                    {
                        WriteLog(LogType_ErrorOut, LogLevel_Error, "Worktype code not found : [MSG_FILE_WORK_TYPE_WORK_START_RESP]");
                    }

/*
                    int MakeFileFrame(char *pszOrganizationID, int nOrganizationIDLen,
                                      char cOccurType, char *pszWorkType, int nWorkTypeLen, char *pszMsgType, int nMsgTypeLength,
                                      char *pszFilename, int nFilenameLen,
                                      char *pszRequestDTime, int nRequestDTimeLen,
                                      char *pszResponseCode, int nResponseCodeLen, char *pData, uint16_t nDataLen, char *pszFrameData, uint16_t *nFrameDataLen);
*/


                    nMessageLength = sizeof(szMessageBody);
                    nResult = MakeFileFrame(sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode),
                                            sRecvFilePacket.sHeader.cOccurType, szRespWorkType, sizeof(szRespWorkType), sRecvFilePacket.sHeader.szMsgType, sizeof(sRecvFilePacket.sHeader.szMsgType),
                                            sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
                                            sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
                                            szRespCode, sizeof(szRespCode), (char *)NULL, 0, szMessageBody, &nMessageLength);

                    SendPacket(pThreadInfo, nChannelNo, &pMessageInfo->aUUID, szMessageBody, sizeof(szMessageBody));
                }

                break;
            case MSG_FILE_WORK_TYPE_WORK_START_RESP:
//                nResult = MappingStringToInt(sRecvFilePacket.sHeader.szMsgType, sizeof(sRecvFilePacket.sHeader.szMsgType), g_sMsgTypeInfo, sizeof(g_sMsgTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), &nMsgType);
//                if (nResult != CONF_ERR_SUCCESS)
//                {
//                    WriteLog(LogType_StandardOut, LogLevel_Info, "Unknown Message Info[WorkType:%s,MsgType:%s]", sRecvFilePacket.sHeader.szWorkType, sRecvFilePacket.sHeader.szMsgType);
//                    nResult = MappingIntToString(g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), RESP_PROTOCOL_ERROR, szRespCode, sizeof(szRespCode));
//                    if (nResult == CONF_ERR_NOT_FOUND)
//                    {
//                        WriteLog(LogType_ErrorOut, LogLevel_Error, "Response code not found : [RESP_PROTOCOL_ERROR]");
//                    }
//                    else
//                    {
//                        nMessageLength = sizeof(szMessageBody);
//                        nResult = MakeFileFrame(sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode),
//                                                sRecvFilePacket.sHeader.cOccurType, sRecvFilePacket.sHeader.szWorkType, sizeof(sRecvFilePacket.sHeader.szWorkType), sRecvFilePacket.sHeader.szMsgType, sizeof(sRecvFilePacket.sHeader.szMsgType),
//                                                sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
//                                                sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
//                                                szRespCode, sizeof(szRespCode), NULL, 0, szMessageBody, &nMessageLength);
//
//
//                        SendPacket(pThreadInfo, nChannelNo, szMessageBody, sizeof(szMessageBody));
//                    }
//                    break;
//                }
                if (sRecvFilePacket.sHeader.nRespCode != RESP_NORMAL)
                {
                    // 오류 응답 코드에 대한 처리 필요
                    // 발생 가능할까? 단순 시작 종료 전문에 응답 가능한 오류 코드가 무엇일까?
                    // 오히려 시스템 오류 등으로 파일 수신이 불가능 한 경우나 종료가 안되는 경우가 발생 가능할 것으로 판단됨
                    // 오류에 대한 처리 보다 문제가 생겼을 때 Sender쪽으로 전송 결과를 리턴하는 내용이 더 중요함
                    // 수신 파일의 경우 수신 오류 전송

                    //PublishTransferResultMessage(g_pFileTransferState[nChannelNo], false);
#ifdef _WIN32
                    uuid_unparse(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID, szUUIDString);
#else
                    uuid_unparse(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID, szUUIDString);
#endif
                    MakeFileTransferResult(pThreadInfo, nChannelNo, false, "0003", szMessageBody, sizeof(szMessageBody));
                    PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].szResponseQueuename, NULL, szMessageBody, sizeof(szMessageBody), szUUIDString, sizeof(szUUIDString), false, NULL);
                    break;
                }
                switch (sRecvFilePacket.sHeader.nMsgType)
                {
                case MSG_FILE_MSG_TYPE_WORK_START:
//                    snprintf(szFilename, sizeof(szFilename), "%s/%s", g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szDirectory, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename);
//                    SafeStrCopy(szFilename, sizeof(szFilename), g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szDirectory);
//                    SafeStrCat(szFilename, sizeof(szFilename), g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, strnlen_s(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, sizof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename)));

//                    nResult = GetFileSize(szFilename, sizeof(szFilename), &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize);
//                    if (nResult != FILE_ERR_SUCCESS)
//                    {
//
//                    }
//
//                    nResult = fopen_s(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename, "r");
//
//                    if (nResult != 0)
//                    {
//
//                    }

//                    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)
                    snprintf(szFilename, sizeof(szFilename), "%s/%s", g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szDirectory, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename);
                    nResult = MWGetFileSize(szFilename, sizeof(szFilename) ,&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize);
                    if (nResult != FILE_ERR_SUCCESS)
                    {
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize = 0;
                    }


                    snprintf(szMessageBody, sizeof(szMessageBody), "%-*.*s%0*d%0*d",
                             MSG_LEN_FILENAME, MSG_LEN_FILENAME, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename,
                             MSG_LEN_FILESIZE, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize,
                             MSG_LEN_MSGSIZE, g_nFileDataSize);
                    nResult = SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType,
                                             MSG_FILE_WORK_TYPE_FILE_INFO_SEND, MSG_FILE_MSG_TYPE_NONE, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, strnlen(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename)),
                                             szRequestDateTime, sizeof(szRequestDateTime), RESP_NORMAL, szMessageBody, sizeof(szMessageBody));
//                        nResult = MakeFileFrame(sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode),
//                                                sRecvFilePacket.sHeader.cOccurType, szRespWorkType, sizeof(szRespWorkType), sRecvFilePacket.sHeader.szMsgType, sizeof(sRecvFilePacket.sHeader.szMsgType),
//                                                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, strnlen(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename)),
//                                                sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
//                                                szRespCode, sizeof(szRespCode), NULL, 0, szMessageBody, sizeof(szMessageBody));
//
//                        SendPacket(pThreadInfo, nChannelNo, szMessageBody, sizeof(szMessageBody));
                    break;
                    // 수신측이라면 아래 2가지 케이스의 차이가 없다. 송신측이라면 몰라도.
                    // 수신측이라면 630 수신 시 수신되는 데이터로 처리하여야 한다.
                    // 송신 측이라면 전송 전 다음 파일 체크해야 되니 차이가 있다.
                case MSG_FILE_MSG_TYPE_FILE_TRANSFER_NEXT:
                case MSG_FILE_MSG_TYPE_FILE_TRANSFER_END:
                    fclose(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile);
#ifdef _WIN32
                    uuid_unparse(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID, szUUIDString);
#else
                    uuid_unparse(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID, szUUIDString);
#endif
                    MakeFileTransferResult(pThreadInfo, nChannelNo, true, "0000", szMessageBody, sizeof(szMessageBody));
                    PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].szResponseQueuename, NULL, szMessageBody, sizeof(szMessageBody), szUUIDString, sizeof(szUUIDString), false, NULL);
                    //int PutReplyMessageToQueue(amqp_connection_state_t sMQConnectionState, const char *pszCorrelationID, const char *pszResponseQueuename, const char *pData, int nDataLength, int *pbMQConnection, int *pbChannelOpen)
                    //PutReplyMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, szUUIDString, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].szResponseQueuename, szMessageBody, sizeof(szMessageBody), &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen);

                    nResult = SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType,
                                             MSG_FILE_WORK_TYPE_WORK_START_REQ, MSG_FILE_MSG_TYPE_WORK_END, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, strnlen(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename)),
                                             szRequestDateTime, sizeof(szRequestDateTime), RESP_NORMAL, NULL, 0);
                    break;
                case MSG_FILE_MSG_TYPE_WORK_END:
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted = false;
                    break;
                default:
                    WriteLog(LogType_StandardOut, LogLevel_Info, "Unknown Message Info[WorkType:%s,MsgType:%s]", sRecvFilePacket.sHeader.szWorkType, sRecvFilePacket.sHeader.szMsgType);
                    nResult = MappingIntToString(g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), RESP_PROTOCOL_ERROR, szRespCode, sizeof(szRespCode));
                    if (nResult == CONF_ERR_NOT_FOUND)
                    {
                        WriteLog(LogType_ErrorOut, LogLevel_Error, "Response code not found : [RESP_PROTOCOL_ERROR]");
#ifdef _WIN32
                        uuid_unparse(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID, szUUIDString);
#else
                        uuid_unparse(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID, szUUIDString);
#endif
                        MakeFileTransferResult(pThreadInfo, nChannelNo, false, "0003", szMessageBody, sizeof(szMessageBody));
                        PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].szResponseQueuename, NULL, szMessageBody, sizeof(szMessageBody), szUUIDString, sizeof(szUUIDString), false, NULL);
                    }
                    else
                    {
                        //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)

                        SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode),
                                       sRecvFilePacket.sHeader.cOccurType, sRecvFilePacket.sHeader.nWorkType, sRecvFilePacket.sHeader.nMsgType,
                                       sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
                                       sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
                                       RESP_UNKNOWN_WORKTYPE, NULL, 0);
//                        nMessageLength = sizeof(szMessageBody);

//                        nResult = MakeFileFrame(sRecvFilePacket.sHeader.szOrganizationCode, sizeof (sRecvFilePacket.sHeader.szOrganizationCode),
//                                                sRecvFilePacket.sHeader.cOccurType, sRecvFilePacket.sHeader.szWorkType, sizeof(sRecvFilePacket.sHeader.szWorkType), sRecvFilePacket.sHeader.szMsgType, sizeof(sRecvFilePacket.sHeader.szMsgType),
//                                                sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
//                                                sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
//                                                szRespCode, sizeof(szRespCode), NULL, 0, szMessageBody, &nMessageLength);
//
//
//                        SendPacket(pThreadInfo, nChannelNo, szMessageBody, sizeof(szMessageBody));
                    }
                    break;
                }
                // 로직 확인 할 것(작성하다 중단한것 같음)
//                nResult = MappingIntToString(g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), RESP_NORMAL, szRespCode, sizeof(szRespCode));
//                if (nResult == CONF_ERR_NOT_FOUND)
//                {
//                    WriteLog(LogType_ErrorOut, LogLevel_Error, "Response code not found : [RESP_NORMAL]");
//                }
//                else
//                {
//                    nResult = SafeStrCmp(sRecvFilePacket.sHeader.szRespCode, sizeof(sRecvFilePacket.sHeader.szRespCode), szRespCode, &nStringCompareResult);
//                    if (nStringCompareResult == 0 && nResult == SEC_ERR_SUCCESS)
//                    {
//                        if (g_bFileMoveYN)
//                        {
//                            snprintf(szFilename, sizeof(szFilename), "%s/%s", g_szFileRecvPathTemp, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename);
//                        }
//                        else
//                        {
//                            snprintf(szFilename, sizeof(szFilename), "%s/%s", g_szFileRecvPath, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename);
//                        }
//                        nResult = GetFileSize(szFilename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename) ,&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize);
//                        if (nResult != FILE_ERR_SUCCESS)
//                        {
//                            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize = 0;
//                        }
//                    }
//                    else
//                    {
//                        // 응답 오류시 처리방법 프로토콜 확인 후 추가 필요
//                        WriteLog(LogType_StandardOut, LogLevel_Info, "Receive error response code[%s]!", sRecvFilePacket.sHeader.szRespCode);
//                    }
//                }
                break;

            case MSG_FILE_WORK_TYPE_FILE_INFO_SEND:
                // 수신된 파일 정보 파싱
                // 파일 존재 여부 확인(임시 폴더를 사용하는 경우 임시 폴더도 체크)
                // 수신 파일 크기 확인(마지막 블록의 경우 수신되는중에 중단되었을 확률이 높으므로 삭제 한다.)
                //
                SafeMemSet(&sRecvFileInfo, sizeof(sRecvFileInfo), 0, sizeof(sRecvFileInfo));
                nOffset = 0;
                nResult = GetCheckedValue(TYPE_FILENAME, sRecvFileInfo.szFilename, MSG_LEN_FILENAME, sRecvFilePacket.szData);
                nOffset += MSG_LEN_FILENAME;
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_LEN_FILESIZE,sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_LEN_FILESIZE;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &sRecvFileInfo.nFileSize);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_LEN_MSGSIZE,sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_LEN_MSGSIZE;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &sRecvFileInfo.nMsgSize);
                nResult = snprintf(szFilename, sizeof(szFilename), "%s/%s", g_szFileRecvPath, sRecvFileInfo.szFilename);
                nStoredFileSize = 0;
                nResult = MWGetFileSize(szFilename, sizeof(szFilename), &nStoredFileSize);
                strncpy(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, sRecvFileInfo.szFilename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename));


                // 오류일 경우와 아닌경우 거의 중복되게 동작하므로 하나로 처리 가능하게 수정할 것
                if (nResult != FILE_ERR_SUCCESS)
                {
                    nResult = snprintf(szFilename, sizeof(szFilename), "%s/%s", g_szFileRecvPathTemp, sRecvFileInfo.szFilename);
                    nResult = MWGetFileSize(szFilename, sizeof(szFilename), &nStoredFileSize);
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nSeqSize = (sRecvFileInfo.nMsgSize < g_nFileDataSize ? sRecvFileInfo.nMsgSize : g_nFileDataSize) - (SOCK_FRAME_SIZE_FILE + SOCK_PACKET_LEN_MSG_LEN + MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN);
                    CalculateBlockSeqCount(pThreadInfo->nSocketIndex, nChannelNo, nStoredFileSize, &nBlockCount, &nSeqCount);

//                    nResult = fopen_s(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename, "a");
//#ifdef __SECURE_CODING
//                    nResult = fopen_s(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename, "r+");
//                    if (nResult != EOK)
//                    {
//                        strerror_s(szResponseQueuename, sizeof(szResponseQueuename), nResult);
//                        printf("Log file open error[finename:%s, Msg:%s]!\n", szFilename, szResponseQueuename);
//                        return GW_ERR_SUCCESS;
//                    }
//#else
//                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile = fopen(szFilename, "r+");
//                    if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile == NULL)
//                    {
//                        printf("Log file open error[finename:%s, Msg:%s]!\n", szFilename, strerror(errno));
//                        return GW_ERR_SUCCESS;
//                    }
//#endif
                    nResult = FileOpenforContinuousTransfer(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename);
                    if (nResult != FILE_ERR_SUCCESS)
                    {
                        WriteLog(LogType_ErrorOut, LogLevel_Info, "File Open Error[File:%s]", szFilename);
                        return GW_ERR_SUCCESS;
                    }

                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize = sRecvFileInfo.nFileSize;
                    if (nSeqCount > 0)
                    {
                        nSeqCount = 0;
                    }
                    else
                    {
                        nBlockCount--;
                        if (nBlockCount < 0)
                            nBlockCount = 0;
                    }
                    nBlockCount++;
                    nSeqCount++;
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo = nBlockCount;
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo = nSeqCount;
                    CalculateBlockSeqCount(pThreadInfo->nSocketIndex, nChannelNo, sRecvFileInfo.nFileSize, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo);
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo++;
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo++;
                    nResult = WriteEmptyFileBlock(pThreadInfo->nSocketIndex, nChannelNo);
                    if (nResult != GW_ERR_SUCCESS)
                    {
                        // 파일이 비정상일경우 어떻게 처리할 것인지?

                    }
                    snprintf(szMessageBody, sizeof(szMessageBody), "%-*.*s%0*d%0*d", MSG_LEN_FILENAME, MSG_LEN_FILENAME, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, MSG_LEN_FILESIZE, (nBlockCount - 1) * g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nSeqSize * g_nMaxSeqCount, MSG_LEN_MSGSIZE, g_nFileDataSize);
                    SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType, MSG_FILE_WORK_TYPE_FILE_INFO_RESP, MSG_FILE_MSG_TYPE_NONE, sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename),
                                   sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime), RESP_NORMAL, szMessageBody, sizeof(szMessageBody));
                }
                else
                {
                    if (nStoredFileSize == sRecvFileInfo.nFileSize)
                    {
                        snprintf(szMessageBody, sizeof(szMessageBody), "%-*.*s%0*d%0*d", MSG_LEN_FILENAME, MSG_LEN_FILENAME, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, MSG_LEN_FILESIZE, nStoredFileSize, MSG_LEN_MSGSIZE, g_nFileDataSize);
                        SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType, MSG_FILE_WORK_TYPE_FILE_INFO_RESP, MSG_FILE_MSG_TYPE_NONE, sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename),
                                       sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime), RESP_ALREADY_RECV, szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)));
                    }
                    else
                    {
                        // Temp 폴더를 사용하지 않을 경우만 발생 가능함
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nSeqSize = (sRecvFileInfo.nMsgSize < g_nFileDataSize ? sRecvFileInfo.nMsgSize : g_nFileDataSize) - (SOCK_FRAME_SIZE_FILE + SOCK_PACKET_LEN_MSG_LEN + MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN);
                        CalculateBlockSeqCount(pThreadInfo->nSocketIndex, nChannelNo, nStoredFileSize, &nBlockCount, &nSeqCount);
//                        nResult = fopen_s(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename, "a");
//#ifdef __SECURE_CODING
//                        nResult = fopen_s(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename, "w+");
//                        if (nResult != EOK)
//                        {
//                            strerror_s(szResponseQueuename, sizeof(szResponseQueuename), nResult);
//                            printf("Log file open error[finename:%s, Msg:%s]!\n", szFilename, szTraceInfo);
//                            return GW_ERR_SUCCESS;
//                        }
//#else
//                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile = fopen(szFilename, "w+");
//                        if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile == NULL)
//                        {
//                            printf("Log file open error[finename:%s, Msg:%s]!\n", szFilename, strerror(errno));
//                            return GW_ERR_SUCCESS;
//                        }
//#endif
                        nResult = FileOpenforContinuousTransfer(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile, szFilename);
                        if (nResult != FILE_ERR_SUCCESS)
                        {
                            WriteLog(LogType_ErrorOut, LogLevel_Info, "File Open Error[File:%s]", szFilename);
                            return GW_ERR_SUCCESS;
                        }
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize = sRecvFileInfo.nFileSize;
                        if (nSeqCount > 0)
                        {
                            nSeqCount = 0;
                        }
                        else
                        {
                            nBlockCount--;
                            if (nBlockCount < 0)
                                nBlockCount = 0;
                        }
                        nBlockCount++;
                        nSeqCount++;
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo = nBlockCount;
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo = nSeqCount;
                        CalculateBlockSeqCount(pThreadInfo->nSocketIndex, nChannelNo, sRecvFileInfo.nFileSize, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo);
                        nResult = WriteEmptyFileBlock(pThreadInfo->nSocketIndex, nChannelNo);
                        if (nResult != GW_ERR_SUCCESS)
                        {
                            // 파일이 비정상일경우 어떻게 처리할 것인지?

                        }
                        snprintf(szMessageBody, sizeof(szMessageBody), "%-*.*s%0*d%0*d", MSG_LEN_FILENAME, MSG_LEN_FILENAME, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, MSG_LEN_FILESIZE, (nBlockCount - 1) * g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nSeqSize * g_nMaxSeqCount, MSG_LEN_MSGSIZE, g_nFileDataSize);
                        SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType,
                                MSG_FILE_WORK_TYPE_FILE_INFO_RESP, MSG_FILE_MSG_TYPE_NONE, sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename),
                                sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime), RESP_NORMAL, szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)));
                    }
                }
                break;
            case MSG_FILE_WORK_TYPE_FILE_INFO_RESP:
                // 데이터 전송 시작
                SafeMemSet(&sRecvFileInfo, sizeof(sRecvFileInfo), 0, sizeof(sRecvFileInfo));
                nOffset = 0;
                nResult = GetCheckedValue(TYPE_FILENAME, sRecvFileInfo.szFilename, MSG_LEN_FILENAME, sRecvFilePacket.szData);
                nOffset += MSG_LEN_FILENAME;
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_LEN_FILESIZE,sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_LEN_FILESIZE;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &sRecvFileInfo.nFileSize);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_LEN_MSGSIZE,sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_LEN_MSGSIZE;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &sRecvFileInfo.nMsgSize);

                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nSeqSize = (sRecvFileInfo.nMsgSize < g_nFileDataSize ? sRecvFileInfo.nMsgSize : g_nFileDataSize) - (SOCK_FRAME_SIZE_FILE + SOCK_PACKET_LEN_MSG_LEN + MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN);
                CalculateBlockSeqCount(pThreadInfo->nSocketIndex, nChannelNo, sRecvFileInfo.nFileSize, &nBlockCount, &nSeqCount);
                nBlockCount++;
                nSeqCount++;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo = nBlockCount;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo = 1;
                CalculateBlockSeqCount(pThreadInfo->nSocketIndex, nChannelNo, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nFileSize, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo);
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo++;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo++;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = MSG_FILE_WORK_TYPE_DATA_SEND;
                break;
            case MSG_FILE_WORK_TYPE_DATA_SEND:
            case MSG_FILE_WORK_TYPE_MISSED_DATA_SEND:
                // 데이터 수신 시작 시 시퀀스 건너띄고 수신될 경우 없는 시퀀스를 파일에 저장하여 파일 공간을 할당 해 놓는다.
                // 수신된 파일데이터는 메모리에 저장하지 않고 파일에 바로 저장한다.
                // 블록 번호가 기존의 번호와 다른경우 결번 데이터 초기화 하고 작업 시작
                // 결번 데이터와 기존 데이터와 처리는 동일 하다.
//                if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType != MSG_FILE_WORK_TYPE_DATA_SEND && sRecvFilePacket.sHeader.nWorkType == MSG_FILE_WORK_TYPE_DATA_SEND)
//                {
//                    // 파일의 블럭 크기만큼 파일 생성
//                    nResult = WriteEmptyFileBlock(pThreadInfo->nSocketIndex, nChannelNo);
//                    if (nResult != GW_ERR_SUCCESS)
//                    {
//                        // 파일이 비정상일경우 어떻게 처리할 것인지?
//
//                    }
//                    nResult = SafeMemSet(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pSeqReceived, g_nMaxSeqCount, 0, g_nMaxSeqCount);
//                    WriteRawCommLog(LogType_CommOut, LogLevel_Info, pThreadInfo->nSocket, 'M', "MISSED DATA CLEAR");
//                }
                nOffset = 0;
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_BLOCKNO_LEN, sRecvFilePacket.szData);
                nOffset += MSG_DATA_BLOCKNO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nBlockCount);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_SEQNO_LEN, sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_DATA_SEQNO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nSeqCount);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_DATA_LEN, sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_DATA_DATA_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nRecvBytes);
                //nRecvBytes = strnlen(sRecvFilePacket.szData, sizeof(sRecvFilePacket.szData));
                if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo != nBlockCount)
                {
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo = nBlockCount;
                    // 파일의 블럭 크기만큼 파일 생성
                    nResult = WriteEmptyFileBlock(pThreadInfo->nSocketIndex, nChannelNo);
                    if (nResult != GW_ERR_SUCCESS)
                    {
                        // 파일이 비정상일경우 어떻게 처리할 것인지?

                    }
                    nResult = SafeMemSet(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pSeqReceived, g_nMaxSeqCount, '0', g_nMaxSeqCount);
                    WriteRawCommLog(LogType_CommOut, LogLevel_Info, pThreadInfo->nSocket, 'M', "MISSED DATA CLEAR");
                }
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo = nBlockCount;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo = nSeqCount;
                PutFileData(pThreadInfo->nSocketIndex, nChannelNo, nBlockCount, nSeqCount, sRecvFilePacket.szData +  nOffset, nRecvBytes);
                break;
            case MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_REQ:
                // 결번 확인 요청 수신 시 결번 데이터 전송
                nOffset = 0;
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_BLOCKNO_LEN, sRecvFilePacket.szData);
                nOffset += MSG_DATA_BLOCKNO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nBlockCount);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_SEQNO_LEN, sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_DATA_SEQNO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nSeqCount);
                // 수신된 블록과 처리중인 블록 번호가 다른 경우에 대한 오류 처리 추가
                nMissedDataCount = GetMissedDataCount(pThreadInfo->nSocketIndex, nChannelNo);
                nSeqNo = g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo == g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo ? g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo : g_nMaxSeqCount;
                g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pSeqReceived[nSeqNo] = '\0';
                snprintf(szDataBuffer, sizeof(szDataBuffer), "%.04d%.03d%.03d%-*.*s",
                         g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo,  nSeqNo, nMissedDataCount, nSeqCount, nSeqCount, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pSeqReceived);
                SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType,
                        MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_RESP, MSG_FILE_MSG_TYPE_NONE, sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename),
                        sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime), RESP_NORMAL, szDataBuffer, strnlen(szDataBuffer, sizeof(szDataBuffer)));
                break;
            case MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_RESP:
                // 결번 확인 응답 수신 시 결번 여부 확인 후 이상 없을 경우
                // 다음 블록 전송 시작
                nOffset = 0;
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_BLOCKNO_LEN, sRecvFilePacket.szData);
                nOffset += MSG_DATA_BLOCKNO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nBlockCount);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_SEQNO_LEN, sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_DATA_SEQNO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nSeqCount);
                nResult = GetCheckedValue(TYPE_DIGIT, szMessageBody, MSG_DATA_MISSED_DATA_NO_LEN, sRecvFilePacket.szData +  nOffset);
                nOffset += MSG_DATA_MISSED_DATA_NO_LEN;
                nResult = SafeStringToInt(szMessageBody, strnlen(szMessageBody, sizeof(szMessageBody)),  &nMissedDataCount);
                SafeMemCopy(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pSeqReceived, nSeqCount, sRecvFilePacket.szData +  nOffset, nSeqCount);
                // 수신된 블록과 처리중인 블록 번호가 다른 경우에 대한 오류 처리 추가
                if (nMissedDataCount == 0)
                {
                    if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo == g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo)
                    {
                        SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode), sRecvFilePacket.sHeader.cOccurType,
                                MSG_FILE_WORK_TYPE_WORK_START_REQ, MSG_FILE_MSG_TYPE_FILE_TRANSFER_END, sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename),
                                szRequestDateTime, sizeof(szRequestDateTime),  RESP_NORMAL, NULL, 0);
                    }
                    else
                    {
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo++;
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo = 1;
                        sRecvFilePacket.sHeader.nWorkType = MSG_FILE_WORK_TYPE_DATA_SEND;
                        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = MSG_FILE_WORK_TYPE_DATA_SEND;
                    }
                }
                else
                {
                    sRecvFilePacket.sHeader.nWorkType = MSG_FILE_WORK_TYPE_MISSED_DATA_SEND;
                    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = MSG_FILE_WORK_TYPE_MISSED_DATA_SEND;
                }


                break;
            }
            //}

//            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = sRecvFilePacket.sHeader.nWorkType;
//            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentMsgType = sRecvFilePacket.sHeader.nMsgType;

        }
        else
        {
            /*
             * 통신 프로토콜 설계에 응답 오류에 대한 처리 부분 보완 필요
             * 보완 이후에 추가 수정 진행
             */
            switch (nResult)
            {
            case GW_ERR_UNKNOWN_WORK_TYPE:
                nResult = SendFileResponse(pThreadInfo, nChannelNo, &sRecvFilePacket, RESP_UNKNOWN_WORKTYPE);
                break;
            case GW_ERR_UNKNOWN_MSG_TYPE:
            case GW_ERR_UNKNOWN_RESP_CODE:
                nResult = SendFileResponse(pThreadInfo, nChannelNo, &sRecvFilePacket, RESP_PROTOCOL_ERROR);
                break;
            default:
                nResult = SendFileResponse(pThreadInfo, nChannelNo, &sRecvFilePacket, RESP_ETC);
                break;
            }

        }
        SafeFree((void **)&pMessageInfo->paMessageData);
        SafeFree((void **)&pMessageInfo);
        SafeFree((void **)&pListNode);
    }

    if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted == true &&
        ((g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection == 'S' && g_eConnectionType == SOCK_CONN_TYPE_SERVER) ||
        (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection == 'C' && g_eConnectionType == SOCK_CONN_TYPE_CLIENT)) &&
        ((g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType == MSG_FILE_WORK_TYPE_DATA_SEND) ||
         (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType == MSG_FILE_WORK_TYPE_MISSED_DATA_SEND)))
    {
        if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType == MSG_FILE_WORK_TYPE_DATA_SEND)
        {
            nSeqNo = g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo;
        }
        else
        {
            nSeqNo = GetMissedSeqNo(pThreadInfo->nSocketIndex, nChannelNo);
        }

        if (nSeqNo >= 1 && nSeqNo <= (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo < g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo? g_nMaxSeqCount: g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo))
        {
            nRecvBytes = GetFileData(pThreadInfo->nSocketIndex, nChannelNo, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo, nSeqNo, szDataBuffer, sizeof(szDataBuffer));
            // 파일 읽기 사이즈 오류를 처리 하지 않는 이유는 위의 블럭, 시퀀스 번호로 인해 논리적으로는 발생 불가능 하기 때문

            // 수신 데이터 길이를 strnlen(szDataBuffer, sizeof(szDataBuffer)) -> nRecvBytes로 변경함
            SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode),
                    sRecvFilePacket.sHeader.cOccurType, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType, sRecvFilePacket.sHeader.nMsgType, sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
                    sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
                    RESP_NORMAL, szDataBuffer, nRecvBytes);
            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentSeqNo++;
        }
        else
        {
            snprintf(szDataBuffer, sizeof(szDataBuffer), "%0*d%0*d", MSG_DATA_BLOCKNO_LEN, CalculateIntRemainder(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo, 10, MSG_DATA_BLOCKNO_LEN)
                                                                    , MSG_DATA_SEQNO_LEN, CalculateIntRemainder((g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentBlockNo < g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxBlockNo? g_nMaxSeqCount: g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nMaxSeqNo), 10 ,MSG_DATA_SEQNO_LEN));
            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nCurrentWorkType = MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_REQ;
            SendFilePacket(pThreadInfo, nChannelNo, sRecvFilePacket.sHeader.szOrganizationCode, sizeof(sRecvFilePacket.sHeader.szOrganizationCode),
                    sRecvFilePacket.sHeader.cOccurType, MSG_FILE_WORK_TYPE_RECEIVE_CONFIRM_REQ, MSG_FILE_MSG_TYPE_NONE, sRecvFilePacket.sHeader.szFilename, strnlen(sRecvFilePacket.sHeader.szFilename, sizeof(sRecvFilePacket.sHeader.szFilename)),
                    sRecvFilePacket.sHeader.szRequestDTime, strnlen(sRecvFilePacket.sHeader.szRequestDTime, sizeof(sRecvFilePacket.sHeader.szRequestDTime)),
                    RESP_NORMAL, szDataBuffer, 7);
        }
    }
    // 메시지 수신 여부와 상관 없이 전송측인 경우 파일 데이터를 읽어서 전송하는 로직 추가
    // 한번에 하나의 packet만 전송할 것

    amqp_maybe_release_buffers(pThreadInfo->sConsumeMQ.sMQConnectionState);
    amqp_maybe_release_buffers(pThreadInfo->sPublishMQ.sMQConnectionState);
    //if (amqp_frames_enqueued(pThreadInfo->sConsumeMQ.sMQConnectionState) || amqp_data_in_buffer(pThreadInfo->sConsumeMQ.sMQConnectionState))
    //if (MQReadCheck(pThreadInfo->sConsumeMQ.sMQConnectionState))
//    if ((g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted == false) && (amqp_frames_enqueued(pThreadInfo->sConsumeMQ.sMQConnectionState) || amqp_data_in_buffer(pThreadInfo->sConsumeMQ.sMQConnectionState)
//        || MQReadCheck(pThreadInfo->sConsumeMQ.sMQConnectionState)))
//    {
//        nResult = GetMessageFromQueue(pThreadInfo->sConsumeMQ.sMQConnectionState, szMessageBody, sizeof(szMessageBody), szUUIDString, sizeof(szUUIDString), szResponseQueuename, sizeof(szResponseQueuename), &pThreadInfo->sConsumeMQ.bMQConnection, &pThreadInfo->sConsumeMQ.bMQChannelOpen, &nDeliveryTag, NULL);
//        nMessageLength = strnlen(szMessageBody, sizeof(szMessageBody));
//        if (nResult == MQ_ERR_SUCCESS)
//        {
//            nResponseQueuenameLength = strnlen(szResponseQueuename, sizeof(szResponseQueuename));
//            WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'C', g_szMQMessageSendExchangername, "", szUUIDString, nMessageLength, "%s", szMessageBody);
//            nResult = ParseFileSendRequest(szMessageBody, sizeof(szMessageBody), &sFileSendRequest);
//            //amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
//            if (nResult != GW_ERR_SUCCESS)
//            {
//                //int MakeFileTransferResult(int nChannel, int bComplete, char szProcCode, char *pszFrameMessage, int nFrameSize)
//                MakeFileTransferResult(pThreadInfo, nChannelNo, false, "0001", szMessageBody, sizeof(szMessageBody));
//
//                StateClear(nChannelNo);
//                //int PutMessageToQueue(amqp_connection_state_t sMQConnectionState, int *pbMQConnection, int *pbChannelOpen, int nChannelNo, const char *pszExchangename, const char *pszResponseQueuename, const char *pszTopic, struct MESSAGE_INFO *pMessageInfo, const char *pData, int nDataLength, char *szUUIDString, int nUUIDLength, int bMakeResponseInfo, struct DOUBLELINKEDLISTINFO *pListInfo)
//                PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", szResponseQueuename, NULL, szMessageBody, sizeof(szMessageBody), szUUIDString, sizeof(szUUIDString), false, NULL);
//                // 재처리 했을 때 처리 가능한 오류 코드라면 nack를 전송하는 기능 추가
//                // 현재 수신된 정보 기준으로 처리 하였을 경우 재처리 하였을 때 다시 될것 같지는 않음
//                amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
//            }
//            else
//            {
//                nResult = FileSendStart(pThreadInfo, nChannelNo, &sFileSendRequest);
//                if (nResult != GW_ERR_SUCCESS)
//                {
//                    //int MakeFileTransferResult(int nChannel, int bComplete, char szProcCode, char *pszFrameMessage, int nFrameSize)
//                    MakeFileTransferResult(pThreadInfo, nChannelNo, false, "0002", szMessageBody, sizeof(szMessageBody));
//                    StateClear(nChannelNo);
//                    //int PutMessageToQueue(amqp_connection_state_t sMQConnectionState, int *pbMQConnection, int *pbChannelOpen, int nChannelNo, const char *pszExchangename, const char *pszResponseQueuename, const char *pszTopic, struct MESSAGE_INFO *pMessageInfo, const char *pData, int nDataLength, char *szUUIDString, int nUUIDLength, int bMakeResponseInfo, struct DOUBLELINKEDLISTINFO *pListInfo)
//                    PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", szResponseQueuename, NULL, szMessageBody, sizeof(szMessageBody), szUUIDString, sizeof(szUUIDString), false, NULL);
//                    // 재처리 했을 때 처리 가능한 오류 코드라면 nack를 전송하는 기능 추가
//                    // 현재 수신된 정보 기준으로 처리 하였을 경우 재처리 하였을 때 다시 될것 같지는 않음
//                    amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
//                }
//                else
//                {
//                    amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
//                }
//            }
//        }
//        else
//        {
//            WriteTraceLog(LogType_ErrorOut, LogLevel_Debug, __FILE__, __LINE__, __FUNCTION__, "GetMessageFromQueue Error!");
//            amqp_basic_nack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0, 1);
//        }
//    }
    ProcessSendTimeout(pThreadInfo, nChannelNo);
    ProcessResponseTimeout(pThreadInfo, nChannelNo);
    //free(pListNode->pNodeData);
    //pListNode->pNodeData = NULL;
    //free(pListNode);
    //pListNode = (struct DOUBLELINKEDLISTNODE *)NULL;
    return GW_ERR_SUCCESS;
}


int ParseFileHeader(struct FILE_PACKET *pPacket, struct MESSAGE_INFO *pData)
{
    /*
    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 MESSAGE_HEADER
    {
        char szOrganizationCode[MSG_LEN_ORGANIZATIONCODE + 1];
        char szOccurType;
        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_REPLY_CODE + 1];
    };

    struct MESSAGE_INFO
    {
        int nMessageLength;
        char *paMessageData;
    };

    TYPE_DIGIT = 0,                   // Character로 표시된 문자형태 "0100" : 단 10진수 형태의 사용만
    TYPE_ALPHA,                       // 영문으로 표시된 문자형태(TODO : 한글 별도로 체크 해야 되는지? isalpha로 체크 되는지 확인 필요)
    TYPE_ALPHA_NUMERIC,               // TYPE_DIGIT || TYPE_ALPHA
    TYPE_HEX,                         // 16진수 문자열 확인
    TYPE_BCD,                         // BCD 바이너리를 만족하는지 확인(BCD 텍스트로 해야할지 고민중)
    TYPE_DATE8,                       // YYYYMMDD
    TYPE_DATE6,                       // YYMMDD
    TYPE_TIME6,                       // HHMMSS
    TYPE_TIME9,                       // HHMMSSFFF
    TYPE_DTIME12,                     // YYMMDDHHMMSS
    TYPE_DTIME14,                     // YYYYMMDDHHMMSS
    TYPE_DTIME17,
    */
    int nIndex;
    int nResult;
    uint16_t nPacketSize;
    char szStringBuffer[MAX_STRING_SIZE + 1];

    nIndex = SOCK_PACKET_LEN_STX;
    SafeMemSet(pPacket, sizeof(struct MESSAGE_PACKET), 0, sizeof(struct MESSAGE_PACKET));
    pPacket->cChannelNo = pData->paMessageData[nIndex];
    nIndex += sizeof(pPacket->cChannelNo);
    nResult = GetCheckedValue(TYPE_HEX, pPacket->szMsgLen, sizeof(pPacket->szMsgLen) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->szMsgLen) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Header Length:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->szMsgLen) - 1;
    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szOrganizationCode, sizeof(pPacket->sHeader.szOrganizationCode) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szOrganizationCode) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Organization Code:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szOrganizationCode) - 1;
    pPacket->sHeader.cOccurType = pData->paMessageData[nIndex];
    nIndex += sizeof(pPacket->sHeader.cOccurType);
    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szWorkType, sizeof(pPacket->sHeader.szWorkType) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szWorkType) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Work Type:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szWorkType) - 1;

    nResult = MappingStringToInt(pPacket->sHeader.szWorkType, sizeof(pPacket->sHeader.szWorkType), g_sWorkTypeInfo, sizeof(g_sWorkTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), &pPacket->sHeader.nWorkType);
    if (nResult != CONF_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szWorkType) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv unknown work type![Work Type:%s]", szStringBuffer);
        return GW_ERR_UNKNOWN_WORK_TYPE;
    }

    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szMsgType, sizeof(pPacket->sHeader.szMsgType) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szMsgType) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Message Type:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szMsgType) - 1;

    nResult = MappingStringToInt(pPacket->sHeader.szMsgType, sizeof(pPacket->sHeader.szMsgType), g_sMsgTypeInfo, sizeof(g_sMsgTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), &pPacket->sHeader.nMsgType);
    if (nResult != CONF_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szMsgType) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv unknown msg type![MSG Type:%s]", szStringBuffer);
        return GW_ERR_UNKNOWN_WORK_TYPE;
    }


/*
    nResult = GetCheckedValue(TYPE_DIGIT, pPacket->sHeader.szSerialNo, sizeof(pPacket->sHeader.szSerialNo) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szSerialNo) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Serial No:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szSerialNo) - 1;
*/
    nResult = GetCheckedValue(TYPE_FILENAME, pPacket->sHeader.szFilename, sizeof(pPacket->sHeader.szFilename) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szFilename) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Filename:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szFilename) - 1;

    nResult = GetCheckedValue(TYPE_DTIME14, pPacket->sHeader.szRequestDTime, sizeof(pPacket->sHeader.szRequestDTime) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szRequestDTime) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Request Date & Time:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szRequestDTime) - 1;

    nResult = GetCheckedValue(TYPE_ALPHA_NUMERIC, pPacket->sHeader.szRespCode, sizeof(pPacket->sHeader.szRespCode) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szRespCode) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Reply Code:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->sHeader.szRespCode) - 1;

    nResult = MappingStringToInt(pPacket->sHeader.szRespCode, sizeof(pPacket->sHeader.szRespCode), g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), &pPacket->sHeader.nRespCode);
    if (nResult != CONF_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->sHeader.szRespCode) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv unknown reply code![Reply Code:%s]", szStringBuffer);
        return GW_ERR_UNKNOWN_WORK_TYPE;
    }

    SafeMemCopy(pPacket->szData, sizeof(pPacket->szData), pData->paMessageData + nIndex, pData->nMessageLength - nIndex - 4 - 1);
    pPacket->szData[pData->nMessageLength - nIndex - 4 - 1] = '\0';
    nIndex += pData->nMessageLength - nIndex - 4 - 1;
    nResult = GetCheckedValue(TYPE_HEX, pPacket->szCRC, sizeof(pPacket->szCRC) - 1, pData->paMessageData + nIndex);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pData->paMessageData + nIndex, sizeof(pPacket->szCRC) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![CRC:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += sizeof(pPacket->szCRC) - 1;
    nIndex += SOCK_PACKET_LEN_ETX;
    if (nIndex != pData->nMessageLength)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv packet size error![Recv Message Size:%d, Parsing Message Size : %d]", pData->nMessageLength, nIndex + 1);
        return GW_ERR_PACKET_SIZE;
    }
    nResult = SafeHexStringToInt(pPacket->szMsgLen, sizeof(pPacket->szMsgLen) - 1, &nPacketSize);
    if ((nIndex - SOCK_PACKET_SIZE - SOCK_PACKET_LEN_MSG_LEN) != nPacketSize)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv Header size error![Header Size:%d, Parsing Size:%d]", nPacketSize, nIndex + 1 - SOCK_PACKET_SIZE);
        return GW_ERR_PACKET_SIZE;
    }
    return GW_ERR_SUCCESS;
}

int ParseFileSendRequest(char *pMessageBuffer, int nMessageBufferSize, struct FILE_SEND_REQUEST *pFileSendRequest)
{
    int nIndex;
    int nResult;
    char szStringBuffer[MAX_STRING_SIZE + 1];
    char szStringValue[MAX_STRING_SIZE + 1];
    int nValueSize;

    nIndex = 0;

    nResult = GetCheckedValueEndWithSep(TYPE_HEX, szStringValue, MSG_LEN_MSG_LEN, pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, MSG_LEN_MSG_LEN);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Message Length:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }

    nResult = SafeHexStringToInt(szStringValue, MSG_LEN_MSG_LEN, &pFileSendRequest->nMessageSize);
    nIndex += nValueSize;

    nResult = GetCheckedValueEndWithSep(TYPE_ALPHA_NUMERIC, pFileSendRequest->szOrganizationCode, sizeof(pFileSendRequest->szOrganizationCode) - 1, pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, sizeof(pFileSendRequest->szOrganizationCode) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Organization Code:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += nValueSize + 1;

    nResult = GetCheckedValueEndWithSep(TYPE_FILENAME, pFileSendRequest->szFilename, sizeof(pFileSendRequest->szFilename) - 1, pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, sizeof(pFileSendRequest->szFilename) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Filename:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    nIndex += nValueSize + 1;

    nResult = GetCheckedValueEndWithSep(TYPE_FILENAME, pFileSendRequest->szDirectory, sizeof(pFileSendRequest->szDirectory) - 1, pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, sizeof(pFileSendRequest->szDirectory) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Directory:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    //nValueSize = strnlen(pFileSendRequest->szDirectory, sizeof(pFileSendRequest->szDirectory));
    nIndex +=  nValueSize + 1;


    nResult = GetCheckedValueEndWithSep(TYPE_DIGIT, szStringValue, sizeof(szStringValue) - 1, pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, sizeof(pFileSendRequest->szFilename) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Filename:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    //nValueSize = strnlen(szStringValue, sizeof(szStringValue));
    nResult = SafeStringToInt(szStringValue, sizeof(szStringValue), &pFileSendRequest->nFileSize);
    if (nResult != STR_ERR_SUCCESS)
    {

    }
    nIndex += nValueSize + 1;

    nResult = GetCheckedValueEndWithSep(TYPE_DTIME14, pFileSendRequest->szRequestDTime, sizeof(pFileSendRequest->szRequestDTime), pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, sizeof(pFileSendRequest->szRequestDTime) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![Request DateTime:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    //nValueSize = strnlen(pFileSendRequest->szDirectory, sizeof(pFileSendRequest->szDirectory));
    nIndex +=  nValueSize + 1;


    nResult = GetCheckedValueEndWithSep(TYPE_YN, szStringValue, sizeof(szStringValue), pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![MoveFileYN:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    if (szStringValue[0] == 'Y' || szStringValue[0] == 'y')
    {
        pFileSendRequest->bChangeDirectory = true;
    }
    else
    {
        pFileSendRequest->bChangeDirectory = false;
    }
    nIndex +=  nValueSize + 1;

    nResult = GetCheckedValueEndWithSep(TYPE_FILENAME, pFileSendRequest->szTargetDirectory, sizeof(pFileSendRequest->szTargetDirectory) - 1, pMessageBuffer + nIndex, &nValueSize, MSG_SEP);
    if (nResult != STR_ERR_SUCCESS)
    {
        SafeStrNCopy(szStringBuffer, sizeof(szStringBuffer), pMessageBuffer + nIndex, sizeof(pFileSendRequest->szTargetDirectory) - 1);
        WriteLog(LogType_StandardOut, LogLevel_Info, "Recv format error![TargetDirectory:%s]", szStringBuffer);
        return GW_ERR_PACKET_FORMAT;
    }
    //nValueSize = strnlen(pFileSendRequest->szTargetDirectory, sizeof(pFileSendRequest->szTargetDirectory));
    nIndex +=  nValueSize + 1;


    return GW_ERR_SUCCESS;
}

//int (*g_fnProcessMessageMQData)(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 *pnDeliveryTag) = NULL;
//int (*g_fnProcessFileMQData)(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 *pnDeliveryTag) = NULL;

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)
{
    //char szUUIDString[UUID_STRING_SIZE + 1];
    //int nMessageLength;
    if (g_bBypassMode)
    {
        amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
    }
    // nack를 실행하면 ack를 실행 할 수 없다. timeout 형태로 처리가 필요하다.
//    else
//    {
//        amqp_basic_nack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0, 1);
//    }
    WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'C', g_szMQMessageSendQueuename, "", szCorrelationID, nDataLength, "%s", pData);
    QSendMessage(pThreadInfo, nChannelNo, pData, nDataLength, szCorrelationID, nCorrelationIDLength, szResponseQueuename, nReplyQueuenameLength, nDeliveryTag);

    return GW_ERR_SUCCESS;
}

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)
{

    amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
    WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'C', g_szMQMessageSendExchangername, "", szCorrelationID, nDataLength, "%s", pData);
    ProcessRecvQueueResponse(pThreadInfo, nChannelNo, pData, nDataLength, szCorrelationID, nCorrelationIDLength);

    return GW_ERR_SUCCESS;
}

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 nResult;
    struct FILE_SEND_REQUEST sFileSendRequest;

    WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nSocket, 'C', g_szMQMessageSendExchangername, "", szCorrelationID, nDataLength, "%s", pData);
    nResult = ParseFileSendRequest(pData, nDataLength, &sFileSendRequest);
    if (nResult != GW_ERR_SUCCESS)
    {
        //int MakeFileTransferResult(int nChannel, int bComplete, char szProcCode, char *pszFrameMessage, int nFrameSize)
        MakeFileTransferResult(pThreadInfo, nChannelNo, false, "0001", pData, nDataLength);

        StateClear(pThreadInfo->nSocketIndex, nChannelNo);
        //int PutMessageToQueue(amqp_connection_state_t sMQConnectionState, int *pbMQConnection, int *pbChannelOpen, int nChannelNo, const char *pszExchangename, const char *pszResponseQueuename, const char *pszTopic, struct MESSAGE_INFO *pMessageInfo, const char *pData, int nDataLength, char *szUUIDString, int nUUIDLength, int bMakeResponseInfo, struct DOUBLELINKEDLISTINFO *pListInfo)
        PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", szResponseQueuename, NULL, pData, nDataLength, szCorrelationID, nCorrelationIDLength, false, NULL);
        // 재처리 했을 때 처리 가능한 오류 코드라면 nack를 전송하는 기능 추가
        // 현재 수신된 정보 기준으로 처리 하였을 경우 재처리 하였을 때 다시 될것 같지는 않음
        amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
    }
    else
    {
        nResult = FileSendStart(pThreadInfo, nChannelNo, &sFileSendRequest);
        if (nResult != GW_ERR_SUCCESS)
        {
            //int MakeFileTransferResult(int nChannel, int bComplete, char szProcCode, char *pszFrameMessage, int nFrameSize)
            MakeFileTransferResult(pThreadInfo, nChannelNo, false, "0002", pData, nDataLength);
            StateClear(pThreadInfo->nSocketIndex, nChannelNo);
            //int PutMessageToQueue(amqp_connection_state_t sMQConnectionState, int *pbMQConnection, int *pbChannelOpen, int nChannelNo, const char *pszExchangename, const char *pszResponseQueuename, const char *pszTopic, struct MESSAGE_INFO *pMessageInfo, const char *pData, int nDataLength, char *szUUIDString, int nUUIDLength, int bMakeResponseInfo, struct DOUBLELINKEDLISTINFO *pListInfo)
            PutMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, nChannelNo, "", "", szResponseQueuename, NULL, pData, nDataLength, szCorrelationID, nCorrelationIDLength, false, NULL);
            // 재처리 했을 때 처리 가능한 오류 코드라면 nack를 전송하는 기능 추가
            // 현재 수신된 정보 기준으로 처리 하였을 경우 재처리 하였을 때 다시 될것 같지는 않음
            amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
        }
        else
        {
            amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
            SafeStrNCopy(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].szResponseQueuename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].szResponseQueuename),
                    szResponseQueuename, strnlen_s(szResponseQueuename, nReplyQueuenameLength));
#ifdef _WIN32
            uuid_parse(szCorrelationID, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID);
#else
            uuid_parse(szCorrelationID, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].aUUID);
#endif
        }
    }

    return GW_ERR_SUCCESS;
}

int FileSendStart(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, struct FILE_SEND_REQUEST *pFileSendRequest)
{
    char szStringBuffer[MAX_STRING_SIZE + 1];
    struct stat st;
    char szFrameBuffer[SOCK_BUFFER_SIZE + 1];
    char szPacketBuffer[SOCK_BUFFER_SIZE + 1];
    int nResult;

    snprintf(szStringBuffer, sizeof (szStringBuffer) - 1, "%s/%s", pFileSendRequest->szDirectory, pFileSendRequest->szFilename);
    if (access(pFileSendRequest->szDirectory, F_OK | R_OK) != 0)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "Directory access error![Directory:%s]", pFileSendRequest->szDirectory);
        return GW_ERR_DIRECTORY_ACCESS;
    }

    if (access(szStringBuffer, F_OK | R_OK) != 0)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "File access error![File:%s]", szStringBuffer);
        return GW_ERR_FILE_ACCESS;
    }

    if (pFileSendRequest->bChangeDirectory)
    {
        if (access(pFileSendRequest->szTargetDirectory, F_OK | W_OK) != 0 )
        {
            WriteLog(LogType_StandardOut, LogLevel_Info, "File access error![Target Directory:%s]", szStringBuffer);
            return GW_ERR_TARGET_DIRECTORY_ACCESS;
        }
    }
    stat(szStringBuffer, &st);
    if (pFileSendRequest->nFileSize != st.st_size)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "File size not equal[File:%s, RequestSize:%d, FileSize:%d]", szStringBuffer, pFileSendRequest->nFileSize, st.st_size);
        return GW_ERR_FILE_SIZE_NOTEQUAL;
    }

    SafeMemCopy(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest), pFileSendRequest, sizeof(struct FILE_SEND_REQUEST));

    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile = fopen(szStringBuffer, "r+");
    if (g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].pFile == NULL)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "File open error![Filename:%s, Error:%s]", szStringBuffer, strerror(errno));
        return GW_ERR_FILE_ACCESS;
    }
    g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].bFileTransferStarted = true;
    if (g_eConnectionType == SOCK_CONN_TYPE_CLIENT)
    {
        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection = 'C';
    }
    else
    {
        g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection = 'S';
    }


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


*/

    nResult = SendFilePacket(pThreadInfo, nChannelNo, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szOrganizationCode, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szOrganizationCode),
                            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].cTransferDirection, MSG_FILE_WORK_TYPE_WORK_START_REQ, MSG_FILE_MSG_TYPE_WORK_START,
                            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szFilename),
                            g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szRequestDTime, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sRequest.szRequestDTime),
                            RESP_NORMAL, NULL, 0);


    return GW_ERR_SUCCESS;
}

int MakeFileTransferResult(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannel, int bComplete, char *szProcCode, char *pszFrameMessage, int nFrameSize)
{
    char szCurrentDTime[MSG_LEN_REQUEST_DTIME + 1];
    char szDirectory[MSG_LEN_MAX_DIRECTORY_SIZE + 1];

    GetDateTimeString(TYPE_DTIME14, szCurrentDTime, sizeof(szCurrentDTime));
    pszFrameMessage[0]= '\0';

//    snprintf(pszFrameMessage, nFrameSize, "%-*s%c%-*s%c%-*s%c%0*d%c%-*s%c%-*s%c%c%c%c%c%-*s",
//             MSG_LEN_ORGANIZATIONCODE, g_pFileTransferState[nChannel]->cTransferDirection, MSG_SEP,
//             MSG_LEN_FILENAME, g_pFileTransferState[nChannel]->sRequest.szOrganizationCode, MSG_SEP,
//             MSG_LEN_MAX_DIRECTORY_SIZE, g_pFileTransferState[nChannel]->sRequest.szDirectory, MSG_SEP,
//             MSG_LEN_FILESIZE, g_pFileTransferState[nChannel]->nFileSize, MSG_SEP,
//             MSG_LEN_REQUEST_DTIME, g_pFileTransferState[nChannel]->sRequest.szRequestDTime, MSG_SEP,
//             MSG_LEN_END_DTIME, szCurrentDTime, MSG_SEP,
//             g_pFileTransferState[nChannel]->cTransferDirection, MSG_SEP,
//             (bComplete? 'Y' : 'N'), MSG_SEP,
//             MSG_LEN_RESP_CODE, szProcCode);

    if (bComplete == true && g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.bChangeDirectory == true)
    {
        snprintf(szDirectory, sizeof(szDirectory), g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szTargetDirectory, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szTargetDirectory));
    }
    else
    {
        snprintf(szDirectory, sizeof(szDirectory), g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szDirectory, sizeof(g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szDirectory));
    }

    snprintf(pszFrameMessage, nFrameSize, "%-*.*s%c%-*.*s%c%-*.*s%c%0*d%c%-*.*s%c%-*.*s%c%c%c%c%c%-*.*s",
             MSG_LEN_ORGANIZATIONCODE, MSG_LEN_ORGANIZATIONCODE, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szOrganizationCode, MSG_SEP,
             MSG_LEN_FILENAME, MSG_LEN_FILENAME, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szFilename, MSG_SEP,
             MSG_LEN_MAX_DIRECTORY_SIZE, MSG_LEN_MAX_DIRECTORY_SIZE, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szDirectory, MSG_SEP,
             MSG_LEN_FILESIZE, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].nFileSize, MSG_SEP,
             MSG_LEN_REQUEST_DTIME, MSG_LEN_REQUEST_DTIME, g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].sRequest.szRequestDTime, MSG_SEP,
             MSG_LEN_END_DTIME, MSG_LEN_END_DTIME, szCurrentDTime, MSG_SEP,
             g_pFileTransferState[pThreadInfo->nSocketIndex][nChannel].cTransferDirection, MSG_SEP,
             (bComplete? 'Y' : 'N'), MSG_SEP,
             MSG_LEN_RESP_CODE, MSG_LEN_RESP_CODE, szProcCode);

    return GW_ERR_SUCCESS;
}

int SendFileResponse(struct SOCKET_THREAD_INFO *pThreadInfo, int nChannelNo, struct FILE_PACKET *pRecvFilePacket, int nRespCodeID)
{
    struct FILE_PACKET sSendFilePacket;
    char aMessageBody[SOCK_BUFFER_SIZE + 1];
    int nMessageLength;
    char szRespCode[SOCK_FRAME_LEN_RESP_CODE + 1];
    int nRespCodeSize;
    int nResult;

//    nResult = CheckNULL(pRespCode, nRespCodeSize);
//    if (nResult == STR_ERR_NOT_EXIST_NULL)
//    {
//        return GW_ERR_NOT_EXIST_NULL;
//    }
    nResult = MappingIntToString(g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), nRespCodeID, szRespCode, sizeof(szRespCode));
    if (nResult != STR_ERR_SUCCESS)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "Can't find responsecode![CodeID:%d]", nRespCodeID);
        return GW_ERR_UNKNOWN_RESP_CODE;
    }
    nResult = SafeMemCopy(&sSendFilePacket, sizeof(sSendFilePacket), pRecvFilePacket, sizeof(*pRecvFilePacket));

    nResult = SafeStrCopy(sSendFilePacket.sHeader.szRespCode, sizeof(sSendFilePacket.sHeader.szRespCode), szRespCode);

    nRespCodeSize = strnlen(szRespCode, sizeof(szRespCode));
    //    int MakeFileFrame(char *pszOrganizationID, int nOrganizationIDLen,
    //                      char cOccurType, char *pszWorkType, int nWorkTypeLen, char *pszMsgType, int nMsgTypeLength,
    //                      char *pszFilename, int nFilenameLen,
    //                      char *pszRequestDTime, int nRequestDTimeLen,
    //                      char *pszResponseCode, int nResponseCodeLen, char *pData, uint16_t nDataLen, char *pszFrameData, uint16_t *nFrameDataLen)
    nResult = MakeFileFrame(sSendFilePacket.sHeader.szOrganizationCode, sizeof (sSendFilePacket.sHeader.szOrganizationCode),
                            sSendFilePacket.sHeader.cOccurType, sSendFilePacket.sHeader.szWorkType, sizeof(sSendFilePacket.sHeader.szWorkType), sSendFilePacket.sHeader.szMsgType, sizeof(sSendFilePacket.sHeader.szMsgType),
                            sSendFilePacket.sHeader.szFilename, strnlen(sSendFilePacket.sHeader.szFilename, sizeof(sSendFilePacket.sHeader.szFilename)),
                            sSendFilePacket.sHeader.szRequestDTime, strnlen(sSendFilePacket.sHeader.szRequestDTime, sizeof(sSendFilePacket.sHeader.szRequestDTime)),
                            szRespCode, nRespCodeSize, sSendFilePacket.szData, sSendFilePacket.nMsgLen - SOCK_FRAME_SIZE_FILE, aMessageBody, &nMessageLength);

    nResult = GetCurrTime(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sLastSendTime, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nLastSendMilliSec);

    nResult = SendPacket(pThreadInfo, nChannelNo, NULL, aMessageBody, sizeof(aMessageBody));

    if (nResult != SOCK_ERR_SUCCESS)
    {
        WriteLog(LogType_StandardOut, LogLevel_Info, "SendPacket error![%d]", nResult);
        return GW_ERR_UNKNOWN_RESP_CODE;
    }

    return GW_ERR_SUCCESS;
}

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)
{
    char aMessageBody[SOCK_BUFFER_SIZE + 1];
    char szRequestDateTime[SOCK_FRAME_LEN_REQUEST_DTIME + 1];
    char szWorkType[SOCK_FRAME_LEN_WORK_TYPE + 1];
    char szMsgType[SOCK_FRAME_LEN_MSG_TYPE + 1];
    char szRespCode[SOCK_FRAME_LEN_RESP_CODE + 1];
    int nMessageLength;
    int nResult;

    // 오류 처리 추가 필요
    if (pszRequestDTime == NULL)
    {
        nResult = GetDateTimeString(TYPE_DTIME14, szRequestDateTime, sizeof(szRequestDateTime));
//#ifdef _DEBUG
//        printf("LINE:%04d GetDateTimeString Executed!\n", __LINE__);
//#endif
    }
    else
    {
        nResult = SafeStrCopy(szRequestDateTime, sizeof(szRequestDateTime), pszRequestDTime);
        if (nResult != STR_ERR_SUCCESS)
        {

        }
//#ifdef _DEBUG
//        printf("LINE:%04d pszRequestDTime copied to szRequestDateTime!\n", __LINE__);
//#endif
    }

    nResult = MappingIntToString(g_sWorkTypeInfo, sizeof(g_sWorkTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), nWorkTypeCode, szWorkType, sizeof(szWorkType));
    if (nResult != STR_ERR_SUCCESS)
    {

    }
//#ifdef _DEBUG
//        printf("LINE:%04d Get WorkType Code[ID:%04d,Code:%.4s]!\n", __LINE__, nWorkTypeCode, szWorkType);
//#endif
    nResult = MappingIntToString(g_sMsgTypeInfo, sizeof(g_sMsgTypeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), nMsgTypeCode, szMsgType, sizeof(szMsgType));
    if (nResult != STR_ERR_SUCCESS)
    {

    }
//#ifdef _DEBUG
//        printf("LINE:%04d Get MsgType Code[ID:%04d,Code:%.4s]!\n", __LINE__, nMsgTypeCode, szMsgType);
//#endif

    nResult = MappingIntToString(g_sRespCodeInfo, sizeof(g_sRespCodeInfo) / sizeof(struct VALUE_STRING_PAIR_INFO), nRespCode, szRespCode, sizeof(szRespCode));
    if (nResult != STR_ERR_SUCCESS)
    {

    }
//#ifdef _DEBUG
//        printf("LINE:%04d Get Response Code[ID:%04d,Code:%.4s]!\n", __LINE__, nRespCode, szRespCode);
//#endif
//    int MakeFileFrame(char *pszOrganizationID, int nOrganizationIDLen, char cOccurType, char *pszWorkType, int nWorkTypeLen, char *pszMsgType, int nMsgTypeLength,
//                      char *pszFilename, int nFilenameLen,
//                      char *pszRequestDTime, int nRequestDTimeLen,
//                      char *pszResponseCode, int nResponseCodeLen, char *pData, uint16_t nDataLen, char *pszFrameData, uint16_t *nFrameDataLen)
//
    nMessageLength = sizeof(aMessageBody);
    nResult = MakeFileFrame(pszOrganizationID, nOrganizationIDLen, cOccurType, szWorkType, sizeof(szWorkType), szMsgType, sizeof(szMsgType),
                            pszFilename, nFilenameLen,
                            szRequestDateTime, sizeof(szRequestDateTime),
                            szRespCode, sizeof(szRespCode), pData, strnlen(pData, nDataLen), aMessageBody, &nMessageLength);
    if (nResult != SOCK_ERR_SUCCESS)
    {

    }
//#ifdef _DEBUG
//        printf("LINE:%04d MakeFileFrame[%d]]!\n", __LINE__, nResult);
//#endif

    nResult = GetCurrTime(&g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].sLastSendTime, &g_pFileTransferState[pThreadInfo->nSocketIndex][nChannelNo].nLastSendMilliSec);
    if (nResult != STR_ERR_SUCCESS)
    {

    }
//#ifdef _DEBUG
//        printf("LINE:%04d GetCurrentTime[%d]]!\n", __LINE__, nResult);
//#endif

    nResult = SendPacket(pThreadInfo, nChannelNo, NULL, aMessageBody, strnlen(aMessageBody, sizeof(aMessageBody)));
    if (nResult != SOCK_ERR_SUCCESS)
    {

    }
//#ifdef _DEBUG
//        printf("LINE:%04d SendPacket[%d]]!\n", __LINE__, nResult);
//#endif

    return GW_ERR_SUCCESS;
}


//
void CalculateBlockSeqCount(int nSocketIndex, int nChannelNo, int nFileSize, int *pnBlockCount, int *pnSeqCount)
{
    *pnBlockCount = nFileSize / ((g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO) * g_nMaxSeqCount);
    nFileSize -= *pnBlockCount * ((g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO) * g_nMaxSeqCount);
    *pnSeqCount = nFileSize / (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO);
    nFileSize -= *pnSeqCount * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO);
    if (nFileSize > 0)
    {
        *pnSeqCount++;
        if (*pnSeqCount > g_nMaxSeqCount)
        {
            *pnBlockCount++;
            *pnSeqCount -= g_nMaxSeqCount;
        }
    }
    if (*pnSeqCount > 0)
    {
        *pnBlockCount++;
    }
}

int WriteEmptyFileBlock(int nSocketIndex, int nChannelNo)
{
    int nResult;
    long nCurrentFileOffset;
    long nBlockFileOffset;
    int nSeqNo;
    char szMessageBody[SOCK_BUFFER_SIZE + 1];
    int nFileSizeRemainder;


    nBlockFileOffset = (g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentBlockNo - 1) * ((g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - (MSG_DATA_FILE_DATA_INFO)) * g_nMaxSeqCount);
    nFileSizeRemainder = g_pFileTransferState[nSocketIndex][nChannelNo].nFileSize - nBlockFileOffset;
    if (fseek(g_pFileTransferState[nSocketIndex][nChannelNo].pFile, nBlockFileOffset, SEEK_SET) == -1)
    {
        nResult = errno;
        switch (nResult)
        {
        case EBADF:
        case EINVAL:
        default:
            WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "fseek error[%s]!", strerror(nResult));
            return GW_ERR_FILE_ACCESS;
        }
    }
    else
    {
        nCurrentFileOffset = ftell(g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
        if (nCurrentFileOffset != nBlockFileOffset)
        {
            WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "fseek error[Block Start Offset:%ld,File Offset:%ld]!", nBlockFileOffset, nCurrentFileOffset);
            return GW_ERR_FILE_ACCESS;
        }
        //nResult = SafeMemSet(szMessageBody, sizeof(szMessageBody), ' ', sizeof(szMessageBody));
        SafeMemSet(szMessageBody, sizeof(szMessageBody), ' ', sizeof(szMessageBody));
        szMessageBody[g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO] = '\0';
        for (nSeqNo = 0; nSeqNo < (g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentBlockNo == g_pFileTransferState[nSocketIndex][nChannelNo].nMaxBlockNo ? g_pFileTransferState[nSocketIndex][nChannelNo].nMaxSeqNo : g_nMaxSeqCount);nSeqNo++)
        {
            if (nFileSizeRemainder < (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO))
            {
                szMessageBody[nFileSizeRemainder] = '\0';
            }
            fputs(szMessageBody, g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
            nFileSizeRemainder -= (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO);
//            if ((nSeqNo % 10) == 9)
//            {
//                fflush(g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
//            }
        }
        SafeMemSet(g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived, g_nMaxSeqCount, '0', g_nMaxSeqCount);
    }
    return GW_ERR_SUCCESS;
}

int GetMissedSeqNo(int nSocketIndex, int nChannelNo)
{

    int nSeqNo;

    for (nSeqNo = 0; nSeqNo < (g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentBlockNo == g_pFileTransferState[nSocketIndex][nChannelNo].nMaxBlockNo ? g_pFileTransferState[nSocketIndex][nChannelNo].nMaxSeqNo : g_nMaxSeqCount);nSeqNo++)
    {
        if (g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived[nSeqNo] == '0')
        {
            g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived[nSeqNo] = '1';
            return nSeqNo + 1;
        }
    }
    return -1;
}

int GetFileData(int nSocketIndex, int nChannelNo, int nCurrentBlockNo, int nCurrentSeqNo, char *pszDataBuffer, int nDataBufferSize)
{
    int nReadBytes;
    int nSeqOffset;
    char szDataSize[MSG_DATA_DATA_LEN + 1];

    nReadBytes = 0;
    nSeqOffset = (nCurrentBlockNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO) * g_nMaxSeqCount + (nCurrentSeqNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO);
    snprintf(pszDataBuffer, nDataBufferSize, "%0*d%0*d%0*d", MSG_DATA_BLOCKNO_LEN, nCurrentBlockNo, MSG_DATA_SEQNO_LEN, nCurrentSeqNo, MSG_DATA_DATA_LEN, 0);

    if (fseek(g_pFileTransferState[nSocketIndex][nChannelNo].pFile, nSeqOffset, SEEK_SET) == 0)
    {
        if (ftell(g_pFileTransferState[nSocketIndex][nChannelNo].pFile) != (nCurrentBlockNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize  - MSG_DATA_FILE_DATA_INFO) * g_nMaxSeqCount + (nCurrentSeqNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize  - MSG_DATA_FILE_DATA_INFO))
        {
            return 0;
        }
        nReadBytes = fread(pszDataBuffer + MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN + MSG_DATA_DATA_LEN, 1, g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - (MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN + MSG_DATA_DATA_LEN), g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
    }
    snprintf(szDataSize, sizeof(szDataSize), "%0*d", MSG_DATA_DATA_LEN, nReadBytes);
    memcpy(pszDataBuffer + MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN, szDataSize, MSG_DATA_DATA_LEN);
    return nReadBytes + MSG_DATA_BLOCKNO_LEN + MSG_DATA_SEQNO_LEN + MSG_DATA_DATA_LEN;
}

int PutFileData(int nSocketIndex, int nChannelNo, int nCurrentBlockNo, int nCurrentSeqNo, const char *pszDataBuffer, int nDataBufferSize)
{
    int nWriteBytes;
    int nOffset;
    nWriteBytes = 0;


    nOffset = (nCurrentBlockNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO) * g_nMaxSeqCount + (nCurrentSeqNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO);
    if (fseek(g_pFileTransferState[nSocketIndex][nChannelNo].pFile, nOffset, SEEK_SET) != -1)
    {
        if (ftell(g_pFileTransferState[nSocketIndex][nChannelNo].pFile) != (nCurrentBlockNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO) * g_nMaxSeqCount + (nCurrentSeqNo - 1) * (g_pFileTransferState[nSocketIndex][nChannelNo].nSeqSize - MSG_DATA_FILE_DATA_INFO))
        {
            return 0;
        }
        nWriteBytes = fwrite(pszDataBuffer, 1, nDataBufferSize, g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
        if (nWriteBytes != nDataBufferSize)
        {
            // 발생 가능할지? 발생한 경우 어떻게 처리 할지? - 거의 파일에 Write가 되지 않는 문제라고 예상됨
            // 가능성 1. Disk Full, 2. 운영체제의 File Write 캐시 full
            WriteTraceLog(LogType_ErrorOut, LogLevel_Trace, __FILE__, __LINE__, __FUNCTION__, "Can't write to file[Filename:%s, BlockNo:%d, SeqNo:%d]", g_pFileTransferState[nSocketIndex][nChannelNo].sRequest.szFilename, g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentBlockNo, g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentSeqNo);
            g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived[nCurrentSeqNo - 1] = '0';
        }
        else
        {
            g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentBlockNo = nCurrentBlockNo;
            g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentSeqNo = nCurrentSeqNo;
            g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived[nCurrentSeqNo - 1] = '1';
        }
//        fflush(g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
        return nWriteBytes;
    }
    return 0;
}

int GetMissedDataCount(int nSocketIndex, int nChannelNo)
{
    int nSeqNo;
    int nSeqNoCount;
    int nMissedDataCount;

    nSeqNoCount = (g_pFileTransferState[nSocketIndex][nChannelNo].nCurrentBlockNo == g_pFileTransferState[nSocketIndex][nChannelNo].nMaxBlockNo ? g_pFileTransferState[nSocketIndex][nChannelNo].nMaxSeqNo : g_nMaxSeqCount);
    nMissedDataCount = 0;

    for (nSeqNo = 0; nSeqNo < nSeqNoCount; nSeqNo++)
    {
        if (g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived[nSeqNo] == '0')
        {
            nMissedDataCount++;
        }
    }
    return nMissedDataCount;

}

void StateClear(int nSocketIndex, int nChannelNo)
{
    char *pSeqReceived;
    if (g_pFileTransferState[nSocketIndex][nChannelNo].pFile != NULL)
    {
        fclose(g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
        SafeFree((void **)&g_pFileTransferState[nSocketIndex][nChannelNo].pFile);
    }
    pSeqReceived = g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived;
    SafeMemSet(&g_pFileTransferState[nSocketIndex][nChannelNo], sizeof(struct FILE_TRANSFER_STATE), 0, sizeof(struct FILE_TRANSFER_STATE));
    g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived = pSeqReceived;
    SafeMemSet(g_pFileTransferState[nSocketIndex][nChannelNo].pSeqReceived, g_nMaxSeqCount, 0, g_nMaxSeqCount);
    g_pFileTransferState[nSocketIndex][nChannelNo].bFileTransferStarted = false;
}

