<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Monitoring</title>
    <link rel="stylesheet" href="/static/css/reset.css">
    <link rel="stylesheet" href="/static/css/common.css">
    <link rel="stylesheet" href="/static/css/monitoring.css">
    <script src="/static/js/jquery-1.10.2.min.js"></script>
    <script src="/static/js/common.js"></script>
    <script src="/static/js/sockjs.min.js"></script>
    <script src="/static/js/stomp.min.js"></script>
</head>
<body>
    <div class="container">
        <div th:replace="~{header}"></div>
        <div class="wrap">
            <div class="left-box">
                <div class="container-1">
                    <div class="title">지역센터 연계상태 정보<div class="refresh-button" onclick="refreshMonitoringData(this)"><img src="/static/image/arrow-clockwise.svg">새로고침</div></div>
                    <div style="width: 100%; height: calc(100% - 30px); overflow: auto;">
                        <div style="min-width : 1435px;">
                            <table class="monitoring-table" style="width: 100%;" >
                                <thead>
                                    <tr>
                                        <th style="width:20px;"></th>
                                        <th colspan="5">지역센터정보 (전체 : <span class="tot"></span> / 이상 : <span class="error"></span>)</th>
                                        <th colspan="3">수신정보 (전체 : <span class="tot"></span> / 이상 : <span class="error"></span>)</th>
                                        <th colspan="3">송신정보 (전체 : <span class="tot"></span> / 이상 : <span class="error"></span>)</th>
                                        <th colspan="2">민간교통정보송신 (전체 : <span class="tot"></span> / 이상 : <span class="error"></span>)</th>
                                        <th colspan="2">신호연계정보 (전체 : <span class="tot"></span> / 이상 : <span class="error"></span>)</th>
                                    </tr>
                                    <tr>
                                        <th></th>
                                        <th id="commState">상태</th>
                                        <th id="centerId">지역ID</th>
                                        <th id="centerNm">지역교통정보센터</th>
                                        <th id="ipAddress">IP</th>
                                        <th id="commPort">PORT</th>
                                        <th id="rinfoTypeDesc">정보유형</th>
                                        <th id="rlogDate">수집시각</th>
                                        <th id="rdataCnt">수신건수</th>
                                        <th id="sinfoTypeDesc">정보유형</th>
                                        <th id="slogDate">송신시각</th>
                                        <th id="sdataCnt">송신건수</th>
                                        <th id="mlogDate">송신시각</th>
                                        <th id="mdataCnt">송신건수</th>
                                        <th id="slLogDate">상태업데이트시각</th>
                                        <th id="slCommState">상태</th>
                                    </tr>
                                </thead>
                                <tbody class="monitoring-tbody"></tbody>
                            </table>
                        </div>
                    </div>
                    <div class="loading"><img src="/static/image/loading.gif" alt="로딩 이미지"></div>
                </div>
                <div class="wr-bar">
                    <span></span><span></span><span></span><span></span>
                </div>
                <div class="container-3">
                    <div class="title">프로세스 상태 정보<div class="refresh-button" onclick="refreshProcessStatusData(this)"><img src="/static/image/arrow-clockwise.svg">새로고침</div></div>
                    <div style="width: 100%; height: calc(100% - 30px); overflow: auto;">
                        <div style="width: 100%; height: 100%; min-width: 400px;">
                            <table class="process-table">
                                <thead>
                                <tr>
                                    <th style="width: 20px"></th>
                                    <th id="processId">ID</th>
                                    <th id="runState">상태</th>
                                    <th id="processNm">프로세스명</th>
                                    <th id="regDate">상태 업데이트 시각</th>
                                </tr>
                                </thead>
                                <tbody class="conn_tbody"></tbody>
                            </table>
                        </div>
                    </div>
                    <div class="loading"><img src="/static/image/loading.gif" alt="로딩 이미지"></div>
                </div>
            </div>
            <div class="dock-bar">
                <span></span><span></span><span></span><span></span>
            </div>
            <div class="container-2">
                <div class="title">통신이력</div>
                <div class="tab">
                    <div onclick="tabChange('rcv')" id="rcv_tab" class="on">수신이력</div>
                    <div onclick="tabChange('send')" id="send_tab">송신이력</div>
                    <div onclick="tabChange('moct')" id="moct_tab">민간정보 송신이력</div>
                    <div onclick="tabChange('int_status')" id="int_status_tab">신호연계정보</div>
                </div>
                <div class="log-box">
                    <div>
                        <table class="rcv_log_tb on">
                            <colgroup>
                                <col width="20px">
                                <col width="25%">
                                <col width="25%">
                                <col width="25%">
                                <col width="12%">
                                <col width="calc(12% - 20px)">
                            </colgroup>
                            <thead>
                            <tr>
                                <th></th>
                                <th>시각</th>
                                <th>송신센터</th>
                                <th>수신센터</th>
                                <th>구분</th>
                                <th>건수</th>
                            </tr>
                            </thead>
                            <tbody>
                            <tr>
                                <td></td>
                                <td colspan="5" class="empty-box">표출 정보 없음</td>
                            </tr>
                            </tbody>
                        </table>
                        <table class="send_log_tb">
                            <colgroup>
                                <col width="20px">
                                <col width="25%">
                                <col width="25%">
                                <col width="25%">
                                <col width="12%">
                                <col width="calc(12% - 20px)">
                            </colgroup>
                            <thead>
                            <tr>
                                <th></th>
                                <th>시각</th>
                                <th>송신센터</th>
                                <th>수신센터</th>
                                <th>구분</th>
                                <th>건수</th>
                            </tr>
                            </thead>
                            <tbody>
                            <tr>
                                <td></td>
                                <td colspan="5" class="empty-box">표출 정보 없음</td>
                            </tr>
                            </tbody>
                        </table>
                        <table class="moct_log_tb">
                            <colgroup>
                                <col width="20px">
                                <col width="25%">
                                <col width="25%">
                                <col width="25%">
                                <col width="12%">
                                <col width="calc(12% - 20px)">
                            </colgroup>
                            <thead>
                            <tr>
                                <th></th>
                                <th>시각</th>
                                <th>송신센터</th>
                                <th>수신센터</th>
                                <th>구분</th>
                                <th>건수</th>
                            </tr>
                            </thead>
                            <tbody>
                            <tr>
                                <td></td>
                                <td colspan="5" class="empty-box">표출 정보 없음</td>
                            </tr>
                            </tbody>
                        </table>
                        <table class="int_status_log_tb">
                            <thead>
                            <tr>
                                <th style="width: 20px;"></th>
                                <th>교차로</th>
                                <th>운영모드</th>
                                <th>수집시각</th>
                                <th>통신상태</th>
                            </tr>
                            </thead>
                            <tbody>
                            <tr>
                                <td></td>
                                <td colspan="4" class="empty-box">표출 정보 없음</td>
                            </tr>
                            </tbody>
                        </table>
                    </div>
                    <div class="loading"><img src="/static/image/loading.gif" alt="로딩 이미지"></div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

<script>
    const thArr        = $('.monitoring-table thead tr:nth-child(2) th:not(:first)');
    const processThArr = $('.process-table thead tr:nth-child(2) th:not(:first)');
    const lResizer     = document.querySelector('.dock-bar');
    const wrResizer    = document.querySelector('.wr-bar');
    const leftPanel    = document.querySelector('.left-box');
    const con1         = document.querySelector('.container-1');
    const con3        = document.querySelector('.container-3');
    const lBottomPanel = document.querySelector('.container-2');
    const tbody        = $('.monitoring-tbody');
    const tabs         = $('.tab > div');
    const columns      = [];
    let reconnectTimer = null;
    let reconnectDelay = 3000; // 3초 후 재연결
    let reconnectAttempts = 0;
    let maxReconnectAttempts = 10;

    let _MonitoringData = [];
    let _ProcessStatusData = [];;
    let webSocket = null;

    connect();

    /**
     * WebSocket Connect
     */
    function connect() {
        webSocket = new SockJS("/ws.do");

        webSocket.onopen = function (message) {
            console.log("WebSocket Connected");
            reconnectAttempts = 0; // 재연결 성공 → 카운터 초기화
            wsOpen(message);
        };

        webSocket.onmessage = function (message) {
            wsOnMessage(message);
        };

        webSocket.onclose = function (message) {
            console.log("WebSocket Closed...");
            attemptReconnect();
        };

        webSocket.onerror = function (message) {
            console.error("WebSocket 에러", message);
            // 일부러 close 호출해서 onclose에서 재연결하도록 함
            webSocket.close();
        };
    }

    /**
     * Connect Success CallBack
     * @param message
     */
    function wsOpen(message) {
        console.log(message);
        //wsSendMessage(message);
    }

    /**
     * Receive Message CallBack
     * @param message
     */
    function wsOnMessage(message) {
       if (message && message.data) {
           const { process, local } = JSON.parse(message.data);
           receiveMonitoringData(local); //지역센터 연계 상태 정보
           receiveProcessStatusData(process); //외부 연계 상태 정보
       }
    }

    /**
     * Close Websocket Reconnect
     */
    function attemptReconnect() {
        if (reconnectAttempts >= maxReconnectAttempts) {
            console.error("재연결 최대 횟수 초과");
            return;
        }

        reconnectAttempts++;
        console.log(`재연결 시도 ${reconnectAttempts}회...`);

        clearTimeout(reconnectTimer);
        reconnectTimer = setTimeout(() => {
            connect();
        }, reconnectDelay);
    }

    /**
     * 지역센터 연계산태 정보 새로고침
     * @param el
     */
    function refreshMonitoringData(el) {
        $(el).addClass('off');
        callApi('/api/monitoring/refreshLocalCenterLinkInfos', 'POST', null, receiveMonitoringData, null, 'container-1');
        setTimeout(()=>$(el).removeClass('off'), 5000);
    }

    /**
     * Data Sorting And Draw Table
     * @param res
     */
    function receiveMonitoringData(res) {
       _MonitoringData = res;
       let sortData = res;
       if (res && res.length && $('.monitoring-table').hasClass('sorting')) {
           sortData = [...res];
           const ascEl  = $('.monitoring-table .asc');
           const descEl = $('.monitoring-table .desc');
           let column = null;
           let asc;
           let desc;

           if (ascEl.length) {
               column = ascEl.attr('id');
               asc = -1;
               desc = 1;
           }
           else if (descEl.length) {
               column = descEl.attr('id');
               asc = 1;
               desc = -1;
           }
           sortData.sort(function(a, b) {
               const aIsNumber = typeof a[column] === 'number' || !isNaN(Number(a[column]));
               const bIsNumber = typeof b[column] === 'number' || !isNaN(Number(b[column]));
               if (aIsNumber && !bIsNumber) return asc;          // 숫자 < 문자열
               if (!aIsNumber && bIsNumber) return desc;           // 문자열 > 숫자
               return a[column] > b[column] ? desc : a[column] === b[column] ? 0 : asc;
           });
       }

       drawMonitoringTable(sortData);
    }

    /**
     * 지역센터 연계상태 정보 테이블 생성
     * @param data
     */
    function drawMonitoringTable(data) {
        const checkInput = $('.container-1 input[type="checkbox"]:checked');
        let checkId = checkInput.length ? checkInput.attr('id') : "";

        tbody.empty();

        if (data && data.length) {
            // 집계
            const summary = data.reduce((acc, obj) => {
                const { isCenter, isSig, commState, rcommState, scommState, mcommState, slCommState } = obj;
                if (isCenter === 'Y') {
                    acc.centerTot++;
                    if (commState === '1') acc.centerErr++;
                    if (rcommState === '1') acc.rcvErr++;
                    if (scommState === '1') acc.sendErr++;
                    if (mcommState === '1') acc.moctErr++;
                }
                if (isSig === 'Y') {
                    acc.sigTot++;
                    if (slCommState === '1') acc.sigError++;
                }
                return acc;
            }, {centerTot: 0, centerErr: 0, rcvErr: 0, sendErr: 0, moctErr: 0, sigTot: 0, sigError: 0});

            // 헬퍼 함수
            const fmt = (val, fallback = '-') => val != null ? val : fallback;
            const fmtNum = val => val != null ? Number(val).toLocaleString() : '-';

            // 행 생성
            const rows =
                data.map(obj => `
                        <tr onclick="rowClick(this, getLogHistoryInfos, 'monitoring-tbody')"
                            ondblclick="openPopupDetail('${obj.centerId}')">
                            <td><input id="check_${obj.centerId}" value="${obj.centerId}" type="checkbox"
                                style="display: none" onchange="checkEvent(this, 'monitoring-tbody')"></td>
                            <td class="comm${obj.commState}"><div>${isNaN(Number(obj.commState)) ? obj.commState : ''}</div></td>
                            <td class="back_${obj.commState}">${obj.centerId}</td>
                            <td class="back_${obj.commState}">${obj.centerNm}</td>
                            <td class="back_${obj.commState}">${fmt(obj.ipAddress)}</td>
                            <td class="back_${obj.commState}">${fmt(obj.commPort)}</td>
                            <td class="back_${obj.rcommState}" onclick="tabChange('rcv')">${fmt(obj.rinfoTypeDesc)}</td>
                            <td class="back_${obj.rcommState}" onclick="tabChange('rcv')">${fmt(obj.rlogDate)}</td>
                            <td class="back_${obj.rcommState}" onclick="tabChange('rcv')">${fmtNum(obj.rdataCnt)}</td>
                            <td class="back_${obj.scommState}" onclick="tabChange('send')">${fmt(obj.sinfoTypeDesc)}</td>
                            <td class="back_${obj.scommState}" onclick="tabChange('send')">${fmt(obj.slogDate)}</td>
                            <td class="back_${obj.scommState}" onclick="tabChange('send')">${fmtNum(obj.sdataCnt)}</td>
                            <td class="back_${obj.mcommState}" onclick="tabChange('moct')">${fmt(obj.mlogDate)}</td>
                            <td class="back_${obj.mcommState}" onclick="tabChange('moct')">${fmtNum(obj.mdataCnt)}</td>
                            <td class="back_${obj.slCommState}" onclick="tabChange('int_status')">${fmt(obj.slLogDate)}</td>
                            <td onclick="tabChange('int_status')" class="comm${obj.slCommState}">
                                <div>${obj.slCommState === null ? '-' : ''}</div>
                            </td>
                        </tr>
                    `).join('');

            tbody.html(rows);

            // 헤더 카운트 채우기
            const values = [
                summary.centerTot, summary.centerErr,
                summary.centerTot, summary.rcvErr,
                summary.centerTot, summary.sendErr,
                summary.centerTot, summary.moctErr,
                summary.sigTot, summary.sigError
            ];
            $('.monitoring-table thead tr:nth-child(1) span').each((i, el) => $(el).text(values[i]));

            if (checkId) { //선택 된 Tr 재클릭
                $('#' + checkId).parent().parent().click();
            }
        }
    }

    /**
     * 지역센터 연계상태 상세정보 팝업
     * @param centerId 센터 ID
     */
    function openPopupDetail(centerId){
        const url = "/popupDetailLogs.do?centerId=" + centerId;
        const name = "지역센터 연계 상세정보";
        const option = "width = 985, height = 980, top = 0, left = 452, location = no"
        window.open(url, name, option);
    }

    /**
     * 외부 연계 상태 상세정보 팝업
     */
    function openPopupLinkedDetail(){
        const url = "/popupLinkedDetailLogs.do";
        const name = "외부 연계 상세정보";
        const option = "width = 985, height = 980, top = 0, left = 452, location = no"
        window.open(url, name, option);
    }

    /**
     * 외부 연계 상태 정보 새로고침
     * @param el
     */
    function refreshProcessStatusData(el) {
        $(el).addClass('off');
        callApi('/api/monitoring/refreshProcessStatus', 'POST', null, receiveProcessStatusData, null, 'container-3');
        setTimeout(()=>$(el).removeClass('off'), 5000);
    }

    /**
     * 외부 연계상태 정보 데이터 sorting & Draw Table
     * @param data
     */
    function receiveProcessStatusData(data) {
        _ProcessStatusData = data;
        let sortData = data;
        if (data && data.length) {
            sortData = [...data];

            if ($('.process-table').hasClass('sorting')) {
                const ascEl  = $('.process-table .asc');
                const descEl = $('.process-table .desc');
                let column = null;
                let asc;
                let desc;

                if (ascEl.length) {
                    column = ascEl.attr('id');
                    asc = -1;
                    desc = 1;
                }
                else if (descEl.length) {
                    column = descEl.attr('id');
                    asc = 1;
                    desc = -1;
                }

                sortData.sort(function(a, b) {
                    let aVal = a[column];
                    let bVal = b[column];
                    if (column === 'regDate' || column ===  'cnt') {
                        aVal = !a.linkHistory ? 0 : a.linkHistory[0][column];
                        bVal = !b.linkHistory ? 0 : b.linkHistory[0][column];
                    }
                    const aIsNumber = typeof aVal === 'number' || !isNaN(Number(aVal));
                    const bIsNumber = typeof bVal === 'number' || !isNaN(Number(bVal));
                    if (aIsNumber && !bIsNumber) return asc;          // 숫자 < 문자열
                    if (!aIsNumber && bIsNumber) return desc;           // 문자열 > 숫자
                    return aVal > bVal ? desc : aVal === bVal ? 0 : asc;
                });
            }
        }

        drawProcessStatusTable(sortData);
    }

    /**
     * 외부 연계 상태 정보 테이블 생성
     * @param data
     */
    function drawProcessStatusTable(data) {
        const checkInput = $('.container-3 input[type="checkbox"]:checked');
        let checkId = "";
        let historyData = [];
        if (checkInput.length) {
            checkId = checkInput.attr('id').replace('check_', '');
        }

        const connTbody = $('.conn_tbody');
        connTbody.empty();
        let str = '';
        if (data && data.length) {
            data.forEach((obj)=>{
                let checkClass = "";
                if (obj.processId === checkId) {
                    historyData = obj.linkHistory;
                    checkClass = 'on';
                }

                str += `<tr class="${checkClass}" onclick="rowClick(this, null, 'conn_tbody')">
                            <td><input id="check_${obj.processId}" value="${obj.processId}" type="checkbox" style="display: none" onchange="checkEvent(this, 'conn_tbody')"></td></td>
                            <td>${obj.processId}</td>
                            <td class="comm${obj.runState}"><div></div></td>
                            <td>${obj.processNm}</td>
                            <td>${obj.lastRegDate}</td>
                        </tr>`;
            });
        }

        connTbody.html(str);
        if (checkId) { //선택된 tr 이 있을 시 해당 프로세스 연계 이력 테이블 업데이트
            $('#check_' + checkId).prop('checked', true);
            processLogHistoryCallBack(historyData);
        }
    }

    /**
     * Drag Resizing
     */
    resizeHeight(lResizer, 'left-box', 'calc(70% - 8px)', '30%', leftPanel, lBottomPanel);
    resizeWidth(wrResizer, 'left-box', 'calc(100% - 428px)', '420px', con1, con3);

    /**
     * 프로세스별 외부 연계 이력
     * @param processId 프로세스 ID
     */
     function getProcessLogHistoryInfos(processId) {
         callApi("/api/monitoring/getProcessLogHistoryInfos", 'POST', { processId }, processLogHistoryCallBack, null);
     }

    /**
     * CallBack Process Log Data
     * @param data CallBack data
     */
     function processLogHistoryCallBack(data) {
        const processName = $('.conn_tbody tr.on').children().eq(3).text();
        $('.container-4 .title').html('연계이력 - ' + processName);
        const container = $('.conn_log_tb tbody');
        let str = '';

        if (data && data.length) {
            data.forEach((obj)=>{
                str += `<tr onclick="rowClick(this, null, 'conn_log_tb tbody')">
                            <td><input type="checkbox" style="display: none;" onchange="checkEvent(this, 'conn_log_tb tbody')"></td>
                            <td>${obj.regDate}</td>
                            <td>${obj.cnt ? Number(obj.cnt).toLocaleString("ko-KR") : '-'}</td>
                        </tr>`
            })
        }
        else {
            str = `<tr><td></td><td colspan="2" class="empty-box">표출 정보 없음</td></tr>`
        }

        container.html(str);
    }

    /**
     * 지역센터 연계상태 정보 통신 이력(수신, 송신, 민간, 신호연계)
     * @param centerId
     */
    function getLogHistoryInfos(centerId) {
        callApi("/api/monitoring/getLogHistoryInfos", 'POST', { centerId }, logHistoryCallBack, null);
    }

    /**
     * 지역센터 연계상태 정보 통신 이력 테이블 생성
     * @param data
     */
    function logHistoryCallBack(data) {
        $('.container-2 .title').text('통신이력 - ' +  $('.monitoring-tbody tr.on').children().eq(3).text());
        const rcvTbody     = $('.rcv_log_tb tbody');
        const sendTbody    = $('.send_log_tb tbody');
        const mocTbody     = $('.moct_log_tb tbody');
        const intStatTbody = $('.int_status_log_tb tbody');
        let rcv = null, send = null, moct = null, intStat = null;
        if (data) {
            rcv = data.rcv;
            send = data.send;
            moct = data.moct;
            intStat = data.intStat;
        }

        rcvTbody.html(makeLogTbody(rcv, 'rcv'));
        sendTbody.html(makeLogTbody(send, 'send'));
        mocTbody.html(makeLogTbody(moct, 'send'));
        intStatTbody.html(makeIntStatTbody(intStat));
    }

    /**
     * 수신, 송신, 민간정보 tbody 생성
     * @param data Draw Data
     * @param type table type
     * @returns {string}
     */
    function makeLogTbody(data, type) {
        let str = `<tr>
                      <td></td>
                      <td colspan="5" class="empty-box">표출 정보 없음</td>
                   </tr>`;
        if (data && data.length) {
            str = "";
            for (let idx in data) {
                const obj = data[idx];
                str += `<tr onclick="rowClick(this, null, '${type}_log_tb tbody')">
                            <td><input id="check_${type + idx}" type="checkbox" style="display: none" onchange="checkEvent(this, '${type}_log_tb tbody')"></td>
                            <td>${obj.logDate || '-'}</td>
                            <td>${obj.fromNm || '-'}</td>
                            <td>${obj.toNm || '-'}</td>
                            <td>${obj.infoKind || '-'}</td>
                            <td>${obj.dataCnt != null ? Number(obj.dataCnt).toLocaleString() : '-'}</td>
                        </tr>`;
            }
        }
        return str;
    }

    /**
     * 통신이력 - 신호연계정보 tbody
     * @param data draw data
     * @returns {string} tbody string
     */
    function makeIntStatTbody(data) {
        let str = `<tr>
                      <td></td>
                      <td colspan="4" class="empty-box">표출 정보 없음</td>
                   </tr>`;
        if (data && data.length) {
            str = "";
            for (let idx in data) {
                const obj = data[idx];
                const { centerId, collDate, commStat, intNm, intNo, operModeDesc } = obj;
                str += `<tr onclick="rowClick(this)">
                            <td><input id="check_int_${centerId + '_' + intNo}" type="checkbox" style="display: none" onchange="checkEvent(this)"></td>
                            <td>${intNo + '_' + intNm}</td>
                            <td>${operModeDesc}</td>
                            <td>${collDate}</td>
                            <td>${commStat === '0' ? '정상' : '이상'}</td>
                        </tr>`;
            }
        }
        return str;
    }

    /**
     * table row click
     * @param el this
     * @param method row click method
     * @param tbody row tbody
     */
    function rowClick(el, method, tbody) {
        $('.' + tbody).find('tr input[type="checkbox"]:checked').prop('checked', false);
        const check = $(el).children().eq(0).find('input[type="checkbox"]');
        check.prop('checked', true).trigger('change');
        if (method) {
            method(check.val());
        }
    }

    /**
     * 지역센터 연계상태 정보 sorting
     */
    thArr.on('click', function(e) {
        sortingData(_MonitoringData, drawMonitoringTable, this, 'monitoring-table');
    });

    /**
     * 외부 연계상태 정보 sorting
     */
    processThArr.on('click', function(e) {
        processSortingData(_ProcessStatusData, drawProcessStatusTable, this, 'process-table');
    });

    /**
     * 통신 이력 Tab click
     * @param type rcv, send, moct, int_status
     */
    function tabChange(type) {
        const selectBox = $('.log-box .' + type + '_log_tb');
        if (selectBox.hasClass('on')) return;
        $('.log-box table.on').removeClass('on');
        $('.tab .on').removeClass('on');
        $('#' + type  + '_tab').addClass('on');
        selectBox.addClass('on');
    }

</script>