/*
*========================================================================
*
*   SYSTEM   : AZN_PLAZA_LANE BACKGROUND
*   FILE     : tagbl.c
*   Progrmer : JBY (baarong@neighbor21.co.kr)
*   Date     : 2018.09.05
*   Modified :
*   Remark   :
 *
 *========================================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "lo_ctrl.h"     /* 차로와 통신을 위한 LOW -LEVEL CONTROL DEFINITION */
#include "dir_path.h"
#include "file_lb.h"
#include "func_list.h"
#include "snd_rcv_knd.h"
#include "tagbl_struc.h"
#include "file_lb.h"
#include "lb_func_list.h"

FILE    *debug;
char    debug_d[128];
char    debug_f[128];

#define _LINE_TEST_       1  /* 회선테스트 적용           */
#define _LINE_TEST_SEC   60  /* 회선테스트 SEC      */
int     line_check_flag = 0; /* 1 Setting시 회선차단 */

#define _LCL_ADDR_CHK    1  /* ADDRESS CHECK 적용     */
char    lcl_addr[15+1];

#define SAVE_BUFFER_CNT  4

int     conn_sock;                          /* SOCK Descriptor        */
u_char  r_buffer[4096];                     /* SOCK recv buffer       */
u_char  s_buffer[4096];                     /* SOCK send buffer       */
u_char  rs_buffer[4096 * SAVE_BUFFER_CNT];  /* SOCK recv save buffer  */
int     r_length;                           /* SOCK length to be read */
int     s_length;                           /* SOCK send length       */
int     rs_length=0;                        /* SOCK recv save length  */

struct  oracon *oracon; /* 오라클 상태관리 GLOBAL   */
int     oraconn    = 0; /* 오라클 상태관리 LOCAL    */
int     oracon_old = 1; /* 오라클 상태 전송유무           */
int     oracon_snd = 0; /* 오라클 상태 전송유무           */
int     db_errno;

void    SIG_term();                /* signal handler         */
struct  hi_comm_ctrl hcc; /* High-level Comm. Control Block */

int     f_errno;                   /* fcontrol lib 전용 Error 변수    */
int     f_recnum;

static  int  sock = -1;       /* socket for AF_UNIX,SOCK_DGRAM */
static  int  size;            /* length of request data        */
struct  sockaddr_un sock_svr; /* socket for me               */

/*
 *========================================================================
 *
 *   Function : main()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : 하위차로 제어 프로그램 MAIN PROCEDURE
 *
 *========================================================================
*/
int main(int argc, char *argv[])
{
    extern    int    optind,  opterr, optopt;
    extern    char    *optarg;
    int        options, ret, ret_event;
    struct    tm     *tm;
    struct  tagbl_struc   *pcs;
    char    buf[512];
    char    plz_id[7];
    int flag=0;

    signal(SIGHUP,  SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGTERM, SIG_term);
    memset(plz_id, 0x0, sizeof(plz_id));

    opterr = 0;
    while((options = getopt(argc, argv, "l:p:")) != EOF)
    {
        switch (options)
        {
             case 'l': /* 차로번호    */
                  hcc.lane_no = atoi(optarg);
                  break;
             case 'p': /* 영업소ID    */
                  sprintf(plz_id, "%.6s", optarg);
                  break;
             default:  break;
        }
    }
    
    memcpy(hcc.bas_tbl.plz_id, plz_id, 6);
    memcpy(hcc.write_info.plz_id, plz_id, 6);

    lb_user_chg();    /* 사용자ID, GROUP ID를 TCS ID로 FIX         */

    hcc.time = time(0);
    tm = localtime(&hcc.time);
    memcpy(&hcc.cday, tm, sizeof(struct tm));

    //proc_log_open();
    proc_log( "B/L전송 프로세스 START [%d/%d/%d %d:%d:%d] \n", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
    //tagbl_packet_open();
    tagbl_Packet("패킷 START [%d/%d/%d %d:%d:%d] \n", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

    if (init_comm(plz_id) != 0) exit(-1);
    //proc_log("TAGBL 서버 시작\n");

    /*기초사항 Table의 IC번호 = 영업소 plz_id */
    memcpy(&hcc.bas_tbl.plz_id, &plz_id, 6);

    lo_comm_ctrl.port_fd = -1;                     /* initial lcc fd */

    if(lane_bk_comm_open((char *)hcc.device_nm) < 0)     /* 차로통신 개통    */
    {
        proc_log("PORT를 사용할수 없습니다");
        exit(-1);
    }

    while(1)
    {   
        memset(buf, 0x0, sizeof(buf));
        if (getppid() <= 1) break;

        ret_event = event_check();

        hcc.time = time(0);
        tm = localtime(&hcc.time);
        memcpy(&hcc.cday, tm, sizeof(struct tm));

        if(ret_event<=0) continue;
        if(flag==1)
            lane_bk_comm_reopen();

        size = read(sock, buf, sizeof(buf));
        proc_log("===== size = [%d]\n", sizeof(struct tagbl_struc));        
        if(size < (int)sizeof(struct tagbl_struc))
        {
            if(size < 0)
            {
                close(sock);
                sock = -1;
            }
            continue;
        }

        pcs = (struct tagbl_struc *)buf;
        ret = send_tagbl(pcs);

        if(ret < 0)
        {
            proc_log("main tagbl_send [%d]\n", ret);
            break;
        }
        else{            
            proc_log("main tagbl_send OK[%d]\n", ret);
        }

        flag=1;
        //close(sock);
        //lcc_open();
    }

    sock_close_port();
    close(sock);
    //proc_log_close();
    //tagbl_packet_close();

    return 0;
}

/*
 *========================================================================
 *
 *   Function : event_check()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : 차로측 통신 PORT 및 하위통신 제어 응용프로그램으로 부터
 *              DATA 입력 EVENT CHECK.(상위 및 차로측 수신감지)
 *
 *========================================================================
*/
int event_check()
{
    fd_set read_list;
    struct timeval   timeval;
    int    ret_event;

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

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

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

    return(ret_event);
}

/*
 *========================================================================
 *
 *   Function : init_comm()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : 차로통신을 위한 정보의 초기화 처리
 *              1. 기초사항 READ & CHECK.
 *              2. 차로상태정보 READ & CHECK.
 *              3. 상위통신 관리 프로그램과 INTERFACE CHANNEL OPEN.
 *
 *========================================================================
*/
int init_comm(char *plz_id)
{
    struct write_info wi;

    char   port[24+1];
    int    max_lane;
    int    i, j;
    char   io_div;
    int    isr;

    /* 1. 기초사항 READ, 차로번호 CHECK */

    memcpy(wi.plz_id, plz_id, sizeof(wi.plz_id));
    isr = lb_freadx(&wi, FNO_BASICTBL, &hcc.bas_tbl, FEQUAL);
    if (isr < 0){
        proc_log("기초사항-F을 읽을 수 없습니다.", 1);
    }

    memset(port, 0x0, sizeof(port));

    max_lane = MAX_LANE;

    if ((int)hcc.lane_no > max_lane){
        proc_log("입력 차로번호가 최대차로 보다 큽니다.", 1);
        return (-1);
    }

    io_div = hcc.bas_tbl.lane_info[hcc.lane_no-1].io_div[0];
    hcc.asc_des_div = io_div - 48;
    sprintf(port, "%.8s%c", hcc.bas_tbl.lane_info[hcc.lane_no-1].sub_port1, '\0');

    rtrim(port);

    memcpy(hcc.device_nm, port, sizeof(hcc.device_nm));

    proc_log("기초데이터 포트 [%s]\n", port);
#if _LCL_ADDR_CHK
    memset(lcl_addr, 0x00, sizeof(lcl_addr));
    for(i=0, j=0; i<(int)sizeof(hcc.bas_tbl.lane_info[hcc.lane_no-1].ip_addr); i++){
        if(hcc.bas_tbl.lane_info[hcc.lane_no-1].ip_addr[i] != ' '){
              lcl_addr[j] = hcc.bas_tbl.lane_info[hcc.lane_no-1].ip_addr[i];
              j++;
        }
    }
#else
    memset(lcl_addr, 0x00, sizeof(lcl_addr));
    memcpy(lcl_addr, "ANY_ADDRESS", strlen("ANY_ADDRESS"));
#endif

    /* 3. 하위통신 관리 응용프로그램과의 INTERFACE를 위한 SOCKET */
    if (lcc_open() != 0)
    {
        proc_log("차로관리 명령 수신 채널 오픈 오류", 1);
        return (-1);
    }

    return (0);
}

/*
 *========================================================================
 *
 *   Function : SIG_term()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : signal handler(SIGTERM)
 *
 *========================================================================
*/
void SIG_term(int signo)
{
    printf("Signal [%d]\n", signo);
    exit(0);
}

/*
 *========================================================================
 *
 *   Function : lcc_open()
 *   Progrmer : JBY (baarong@neighbor21.co.kr)
 *   Date     : 2018.09.05
 *   Modified :
 *   Remark   : 관리자 프로그램의 차로제어를 위한 INTERFACE CHANNEL OPEN.
 *
 *========================================================================
*/
int lcc_open()
{
    char    lcc_path[128];

    sprintf(lcc_path, "%s/%s/tagbl_svr%.6s%02d", DIR_TCS, DIR_SPOOL, hcc.bas_tbl.plz_id, hcc.lane_no);
    unlink(lcc_path);
    sock = socket(AF_UNIX, SOCK_DGRAM, 0);

    proc_log(" (lcc_function.c) 관리자 OPEN SOCK (%d) PATH (%s)\n", sock, lcc_path);

    if (sock < 0) return (-1);

    bzero(&sock_svr, sizeof(sock_svr));
    sock_svr.sun_family = AF_UNIX;
    strcpy(sock_svr.sun_path, lcc_path);

    if (bind(sock, (struct sockaddr *)&sock_svr, sizeof(sock_svr)) < 0)
    {
        close(sock);
        return (-1);
    }
    listen(sock, 1);

    //fcntl(sock, F_SETFL, O_NONBLOCK);

    return (0);
}
