/*
 *========================================================================
 *
 *   시스템명 : 요금징수 시스템
 *   파 일 명 : ft_main.c
 *   작 성 자 : 조보용 (baarong@neighbor21.co.kr)
 *   작 성 일 : 2012.10.10
 *   수 정 일 :
 *   설    명 : File & DB Table간 변환 Main
 *
 *========================================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <arpa/inet.h>

#include "chg_struc.h"
#include "file_lb.h"
#include "dir_path.h"
#include "debug_def.h"
#include "path_def.h"
#include "lb_func_list.h"
#include "func_list.h"
#include "MessageProcessor.h"

static   int  sockfd = -1; /* socket for AF_UNIX,SOCK_DGRAM */
static   char buf[512];    /* request data                  */
static   int  size;        /* length of request data        */

struct   sockaddr_un   sock_svr;   /* socket for me               */

void   SIG_term();             /* signal handler               */

int    file_tbl_chng();
#if 0
int    init_sock();
int    chk_event();
#else
void *WorkThread(void *pData);
char g_szProcessname[MAX_STRING_SIZE + 1];
char g_szProcessPath[PATH_MAX + 1];
#endif
/*
 *========================================================================
 *
 *   함 수 명 : main()
 *   작 성 자 : 조보용
 *   작 성 일 : 2018.12.10
 *   수 정 일 :
 *   설    명 : 운영단말처리 DAEMON PROCESS(kmpsvr) MAIN
 *
 *========================================================================
*/
int main(int argc, char *argv[])
{
    char szProcessname[PATH_MAX + 1];
    char *pFindPointer;
    //int nPathIndicatorPos;
    int nResult;

    //DaemonStart();
    nResult = SafeStrCopy(szProcessname, sizeof(szProcessname), argv[0]);
    if (nResult != SEC_ERR_SUCCESS)
    {
        printf_s("strcpy_s Error![%d]\n", nResult);
    }
    pFindPointer = szProcessname;
    nResult = SafeStrrChr(szProcessname, strnlen_s(szProcessname, sizeof(szProcessname)), '/', &pFindPointer);

    printf_s("문자열길이 : %d\n", strnlen_s(szProcessname, sizeof(szProcessname)));
    printf_s("szProcessname Address : %x\n", szProcessname);
    printf_s("pFindPointer Address : %x\n", pFindPointer);
    printf_s("szProcess Name : %s\n", szProcessname);

    if (pFindPointer == NULL)
    {
        nResult = SafeStrCopy(g_szProcessname, sizeof(g_szProcessname), szProcessname);
    }
    else
    {
        nResult = SafeStrCopy(g_szProcessname, sizeof(g_szProcessname), pFindPointer + 1);
    }

    GetExecPath(g_szProcessPath, sizeof(g_szProcessPath) - 1, argv[0]);
    printf_s("g_szProcess Name : %s\n", g_szProcessname);
    if (g_szProcessPath == NULL)
    {
        printf_s("Can't get process path[Cann't load config file]!\nExit Program!");
        return -1;
    }

    //lane_stat_info_read();
    nResult = InitMessageProcessConfig();

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

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

    /* Socket 처리 루프 : 종료시 프로그램 종료됨 */
    nResult = InitThread(WorkThread);
    while(true)
    {
        sleep(5);
    }

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

    return 0;
}

int InitMessageProcessConfig()
{
    char szConfigfilename[PATH_MAX + 1];
    char szConfigfilenameTemp[PATH_MAX + 1];

    snprintf(szConfigfilenameTemp, sizeof(szConfigfilenameTemp), "%s/%s/", g_szProcessPath, CONF_FILE_PATH);

    realpath(szConfigfilenameTemp, szConfigfilename);

    SafeStrCat(szConfigfilename, sizeof(szConfigfilename), "/", 1);
    SafeStrCat(szConfigfilename, sizeof(szConfigfilename), g_szProcessname, strnlen_s(g_szProcessname, sizeof(g_szProcessname)));
    SafeStrCat(szConfigfilename, sizeof(szConfigfilename), CONF_FILE_EXT, strnlen_s(CONF_FILE_EXT, sizeof(CONF_FILE_EXT)));

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

    ReadConfigFile(true, szConfigfilename);

    if (InitLogConfig() != LOG_ERR_SUCCESS)
    {
        return MP_ERR_CONFIG;
    }


    if (InitProcessorMQConfig() != MQ_ERR_SUCCESS)
    {
        return MP_ERR_CONFIG;
    }

    if (InitThreadConfig() != THREAD_ERR_SUCCESS)
    {
        return MP_ERR_CONFIG;
    }

    return MP_ERR_SUCCESS;
}

void *WorkThread(void *pData)
{
    struct THREAD_INFO *pThreadInfo;
    amqp_rpc_reply_t sRPCReply;
    char szMessageBuffer[MAX_STRING_SIZE + 1];
    char tmp_buffer[MAX_STRING_SIZE + 1];
    int nResult;
    int *pnThreadExitCode;
    char szCorrelationID[MAX_STRING_SIZE + 1];
    char szReplyQueuename[MAX_STRING_SIZE + 1];
    char szExchangername[MAX_STRING_SIZE + 1];
    int nMessageLength;
    uint64_t nDeliveryTag;

    pThreadInfo = (struct THREAD_INFO *)pData;
    pnThreadExitCode = NULL;
    nResult = SafeMemoryAlloc((void **)&pnThreadExitCode, sizeof(int));
    //pnThreadExitCode = SafeAlloc(pnThreadExitCode, sizeof(int));
    *pnThreadExitCode = 0;
    while (pThreadInfo->bThreadLoop)
    {
        if (pThreadInfo->sPublishMQ.bMQConnection == false || pThreadInfo->sPublishMQ.bMQChannelOpen == false
            || pThreadInfo->sConsumeMQ.bMQConnection == false || pThreadInfo->sConsumeMQ.bMQChannelOpen == false)
        {
            if (ConnectProcessorMQ(pThreadInfo, true) != MQ_ERR_SUCCESS)
            {
                WriteLog(LogType_StandardOut, LogLevel_Debug, "[Thread:%02d]ConnectProcessMQ is failed!", pThreadInfo->nThreadIndex);
                continue;
            }
            WriteLog(LogType_StandardOut, LogLevel_Debug, "[Thread:%02d]ConnectProcessMQ is succeeded!!", pThreadInfo->nThreadIndex);
        }
        //amqp_maybe_release_buffers(pThreadInfo->sMQConnectionState);
        nResult = GetMessageFromQueue(pThreadInfo->sConsumeMQ.sMQConnectionState, szExchangername, sizeof(szExchangername), szMessageBuffer, sizeof(szMessageBuffer), szCorrelationID, sizeof(szCorrelationID), szReplyQueuename, sizeof(szReplyQueuename), &pThreadInfo->sConsumeMQ.bMQConnection, &pThreadInfo->sConsumeMQ.bMQChannelOpen, &nDeliveryTag, NULL);
        nMessageLength = strnlen_s(szMessageBuffer, sizeof(szMessageBuffer));
printf_s("111111\n");
        if (nResult == MQ_ERR_SUCCESS)
        {
            printf_s("Message Received : %s\n", szMessageBuffer);
            //WriteRawCommLog(LogType_CommOut, LogLevel_Info, pThreadInfo->nThreadIndex, 'C', "%s", szMessageBuffer);
            WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nThreadIndex, 'C', g_szMQMessageRecvQueuename, "", szCorrelationID, nMessageLength, "%s", szMessageBuffer);
            WriteLog(LogType_StandardOut, LogLevel_Info, "[Thread:%02d]MQ Data Consume[Data:%s]!", pThreadInfo->nThreadIndex, szMessageBuffer);
            nResult = file_tbl_chng(szMessageBuffer+4);
printf_s("DB 처리 결과[%d]\n", nResult);
            memcpy(tmp_buffer, szMessageBuffer, sizeof(tmp_buffer));
            //작업구분코드 변경
            sprintf(szMessageBuffer+15, "%.4s", "0020");
            sprintf(szMessageBuffer+19, "%s", tmp_buffer+19);
            //응답코드 입력
            sprintf(szMessageBuffer+41, "%04d", nResult);

printf_s("응답 전송 [%s]\n", szMessageBuffer);
            //nResult = PutAckMessageToQueue(pThreadInfo->sMQConnectionState, szCorrelationID, szReplyQueuename, szMessageBuffer, strnlen_s(szMessageBuffer, sizeof(szMessageBuffer)), &pThreadInfo->bMQConnection, &pThreadInfo->bChannelOpen);
            amqp_basic_ack(pThreadInfo->sConsumeMQ.sMQConnectionState, 1, nDeliveryTag, 0);
            nResult = PutReplyMessageToQueue(pThreadInfo->sPublishMQ.sMQConnectionState, szCorrelationID, szReplyQueuename, szMessageBuffer, strnlen_s(szMessageBuffer, sizeof(szMessageBuffer)), &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen);
            WriteQueueLog(LogType_MQOut, LogLevel_Info, pThreadInfo->nThreadIndex, 'P', "", szReplyQueuename, szCorrelationID, nMessageLength, "%s", szMessageBuffer);
            WriteLog(LogType_StandardOut, LogLevel_Info, "[Thread:%02d]Response Publish[Queue:%s,UUID:%s,Data:%s]!", pThreadInfo->nThreadIndex, szReplyQueuename, szCorrelationID, szMessageBuffer);
        }
        else
        {
            WriteLog(LogType_StandardOut, LogLevel_Debug, "[Thread:%02d]MQ Data Consume Error!", pThreadInfo->nThreadIndex);
        }
    }
    CloseMQ(pThreadInfo->nThreadIndex, pThreadInfo->sPublishMQ.sMQConnectionState, &pThreadInfo->sPublishMQ.bMQConnection, &pThreadInfo->sPublishMQ.bMQChannelOpen, &pThreadInfo->sPublishMQ.sMQMutex);
    CloseMQ(pThreadInfo->nThreadIndex, pThreadInfo->sConsumeMQ.sMQConnectionState, &pThreadInfo->sConsumeMQ.bMQConnection, &pThreadInfo->sConsumeMQ.bMQChannelOpen, &pThreadInfo->sConsumeMQ.sMQMutex);

    return pnThreadExitCode;
}
#if 0
/*******************************************************************************
** 1. 모 듈 명 :  main
** 2. 모듈기능 :  File & DB Table간 변환 Main
** 3. 입    력 :
**
** 4. 입 출 력 :
**
** 5. 출    력 :
**
** 6. Fuction Return:
**
** 7. 변경이력 :
**------------------------------------------------------------------------------
** Version  Date        Comment
** 1.00     2012/07/23  - TCS VERSION(C/S 환경)
*******************************************************************************/
int main()
{
    struct  chg_struc   *pcs;
    int ret_event, status;
    int ret, ii;

    lb_user_chg(); /* user ID를 바꿔준다. */
                  /* root유저 일때만 dbe유저로 변경가능 -> chmod 4755와 같이 사용*/

    signal(SIGHUP, SIG_IGN);
    signal(SIGTERM, SIG_term);

    init_sock();
    //2019.06.27 InitDoubleLinkedList Main 선언
    InitThread_Before();

    sighold(SIGTERM);

    for (ii=0;;ii++)
    {
        if (getppid() <= 1) break;

//        oracle_connect();

        if (sockfd < 0) init_sock();

        sigrelse(SIGTERM);
        ret_event = chk_event();
        sighold(SIGTERM);

        waitpid(-1, &status, WNOHANG);

        if (ret_event <= 0) continue;

        size = read(sockfd, buf, sizeof(buf));
        if (size < (int)sizeof(struct chg_struc))
        {
            if (size < 0)
            {
                close(sockfd);
                sockfd = -1;
            }
            continue;
        }

        connect_db();

        pcs = (struct chg_struc *)buf;
        ret = file_tbl_chng(pcs);

        if (ret < 0)
        {
            proc_log( "main file_tbl_chng [%d]\n", ret );
            lb_rehndlog(pcs);
        }
        disconnect_db();

//        oracle_disconnect();
    }
    return 0;
}

/*=============================================================================
 * NAME   : chk_event()
 * DESC   : 연결된 SOCKET으로 부터 요청 EVENT CHECK.
=============================================================================*/
int chk_event()
{
    fd_set   read_list;
    struct   timeval   timeval;
    int   ret_event;

    if (sockfd < 0)
    {
        sleep(5);
        return (0);
    }

    timeval.tv_sec = 5;
    timeval.tv_usec = 0;

    FD_ZERO(&read_list);
    FD_SET(sockfd, &read_list);
    ret_event = select(sockfd+1, &read_list, NULL, NULL, &timeval);

    return (ret_event);
}

/*=============================================================================
 * NAME   : init_sock()
 * DESC   : Initialize socket interface to receive request data.
=============================================================================*/
int init_sock()
{
    char   u_path[128];
    int   optval;

    sprintf(u_path, "%s/%s/%s", DIR_TCS, DIR_SPOOL, PROC_OLTP);
    unlink(u_path);

    if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
    {
        printf("socket 생성 실패\n");
        return (0);
    }

    memset(&sock_svr, 0, sizeof(sock_svr));
    sock_svr.sun_family = AF_UNIX;
    strcpy(sock_svr.sun_path, u_path);

    if (bind(sockfd, (struct sockaddr *)&sock_svr, sizeof(sock_svr)) < 0)
    {
        perror("bind error");
        close(sockfd);
        sockfd = -1;
        return (-1);
    }

    optval = (1024*256);
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&optval, sizeof(int));
    fcntl(sockfd, F_SETFL, O_NONBLOCK);

    return (0);
}

/*=============================================================================
 * NAME : SIG_term()
 * DESC : signal handler (SIGTERM)
=============================================================================*/
void SIG_term()
{
	disconnect_db();
//    oracle_disconnect();   /* Disconnect Oracle */
    exit(0);
}
#endif