import { currDt } from "/js/utils/common.js";
import { requestGet, apiGet } from "/js/utils/restApi.js";
import { TMapMngr } from "/js/vworld/map-mngr.js";
import { LayerType, LayerIndex } from "/js/vworld/map-const.js";
import { TWebSocket } from "/js/websocket/websocket.js";
import * as MAIN from "./main.js";
export let _mapManager = null;
let _webSocket = null;
export let _cctvMap = new Map();
export let _vmsMap = new Map();
let _trafficMap = new Map();
window.$trafficMap = _trafficMap;
let _timerFetchFcltStts = null; // 시설물 상태정보 요청 타이머
let _timerFetchTraffic = null; // 교통정보 요청 타이머
let _timerFetchIncdData = null; // 돌발정보 요청 타이머

const requestFetchFcltStts = () => {
    if (_timerFetchFcltStts) window.clearTimeout(_timerFetchFcltStts);
    _timerFetchFcltStts = window.setTimeout(() => fetchFcltStts(), 2 * 60 * 1000);
};
const requestFetchTraffic = () => {
    if (_timerFetchTraffic) window.clearTimeout(_timerFetchTraffic);
    _timerFetchTraffic = window.setTimeout(() => fetchTraffic(), 5 * 60 * 1000);
};
const requestFetchIncdData = () => {
    if (_timerFetchIncdData) window.clearTimeout(_timerFetchIncdData);
    _timerFetchIncdData = window.setTimeout(() => fetchIncdData(), 2 * 60 * 1000);
};
let _timerFetchUnitStts = null; // 프로세스 상태정보 요청 타이머
const requestFetchUnitStts = () => {
    if (_timerFetchUnitStts) window.clearTimeout(_timerFetchUnitStts);
    _timerFetchUnitStts = window.setTimeout(() => fetchUnitStts(), 2 * 60 * 1000);
};

// 웹소켓 초기화
function websocketConnect(clientType) {
    _webSocket = new TWebSocket(clientType, onSocketReceived, onSocketDisconnected, onSocketError, onSocketConnected);
    _webSocket.connect();
}
function onSocketConnected(AClientType, AMessage) {
    console.log(`${currDt()}: onSocketConnected, ${AClientType}, `, AMessage);
}
function onSocketReceived(AClientType, AMessage) {
    //console.log(`${currDt()}: onSocketReceived, ${AClientType}, `, AMessage);
    const command = AMessage.command;
    const jsonData = AMessage.data;
    if (command === "itsFcltStts" || command === "bisFcltStts") {
        updateFcltStts(jsonData);
        if (command === "bisFcltStts") {
            //const sttsArray = Array.from( _sttsMap.values() );
            MAIN.updateFcltStts(_sttsMap);
        }
        requestFetchFcltStts();
    } else if (command === "itsUnitStts" || command === "bisUnitStts") {
        if (command === "itsUnitStts") {
            MAIN.updateUnitStts(jsonData); //ITS 프로세스
        }
        if (command === "bisUnitStts") {
            requestFetchUnitStts();
        }
    } else if (command === "traffic") {
        // 소통정보 가공완료
        fetchTraffic();
    } else if (command === "form-save") {
        // VMS 메시지 생성 저장
    }
}

function onSocketDisconnected(AClientType, AMessage) {
    console.log(`${currDt()}: onSocketDisconnected, ${AClientType}, `, AMessage);
}
function onSocketError(AClientType, AMessage) {
    console.log(`${currDt()}: onSocketError, ${AClientType}, `, AMessage);
}

function FcltStts(type) {
    this.type = type;
    this.total = 0;
    this.normal = 0;
    this.error = 0;
    this.collect = 0;
    this.objLists = new Array();
}
export const _sttsMap = new Map();
_sttsMap.set("CCTV", new FcltStts("CCTV"));
_sttsMap.set("VMS", new FcltStts("VMS"));
_sttsMap.set("VDS", new FcltStts("VDS"));
_sttsMap.set("DSRC", new FcltStts("DSRC"));
_sttsMap.set("SIG", new FcltStts("신호제어기"));
_sttsMap.set("CCAM", new FcltStts("교차로카메라"));
//_sttsMap.set("BIT", new FcltStts("BIT"));

export function doMap() {
    // 지도객체 먼저 생성 하여야 함
    _mapManager = new TMapMngr("map", "tooltip");
    websocketConnect("op");
    _mapManager.onMapMoveEndFunc  = onMapMoveEndFunc;     // 지도 이동/줌 변경 이벤트 반환
    _mapManager.onMouseClickFunc  = onMouseClickFunc;     // 객체 마우스 클릭 이벤트 반환
    _mapManager.onContextMenuFunc = onContextMenuFunc;    // 객체 컨텍스트 이벤트 반환
    //_mapManager.onSelectObjFunc   = onSelectObjFunc;      // 객체 선택 이벤트 반환
    //_mapManager.onFcltDragEndFunc = onFcltDragEndFunc;    // 객체(시설물) 편집시 객체 이동후 좌표 반환

    // 지도 초기화설정
    _mapManager.showTrafficTooltip(false);
    _mapManager.setSelectMode(true);
    _mapManager.toggleBaseMap(true);
}
function onMapMoveEndFunc(AZoom, ACenterX, ACenterY, ALeft, ABottom, ARight, ATop) {
    //console.log(`${currDt()}: onMapMoveEndFunc, ${AZoom}, ${ACenterX}, ${ACenterY}, ${ALeft}, ${ABottom}, ${ARight}, ${ATop}`);
    $('.cctv-right-btn-click').remove();
    $('.vms-right-btn-click').remove();
}
function onMouseClickFunc(ALyrIdx, ALyrName, ANmbr, ACoordX, ACoordY, X, Y) {
    //console.log(`${currDt()}: onMouseClickFunc, ${ALyrIdx}, ${ALyrName}, ${ANmbr}, ${ACoordX}, ${ACoordY}, ${X}, ${Y}`);
    if (ALyrIdx === -1) {
        $('.cctv-right-btn-click').remove();
        $('.vms-right-btn-click').remove();
    }
    // const obj = _mapManager.findLayerObject(ALyrIdx, ANmbr);
    // if (!obj) {
    //     return;
    // }

    if (ALyrName === "VMS") {
    } else if (ALyrName === "CCTV") {
    }
    //  else if (ALyrName === "BIT") {
    // }

    let option = 'width = 580, height = 550, top = 200, left = 674, resizable=no, scrollbars=no';
    if (ALyrIdx >= LayerIndex.Link1 && ALyrIdx <= LayerIndex.Link5) {
        window.open('./detail-traffic-pop-up.html?id=' + encodeURIComponent(ANmbr) + '&type=link', '구간선택', option);
    }
    else if (ALyrIdx >= LayerIndex.Ifsc1 && ALyrIdx <= LayerIndex.Ifsc5) {
        window.open('./detail-traffic-pop-up.html?id=' + encodeURIComponent(ANmbr) + '&type=ifsc', '구간선택', option);
    }
    else if (ALyrIdx >= LayerIndex.Road1 && ALyrIdx <= LayerIndex.Road5) {
        window.open('./detail-traffic-pop-up.html?id=' + encodeURIComponent(ANmbr) + '&type=road', '구간선택', option);
    }
}

function onContextMenuFunc(ALyrIdx, ALyrName, ANmbr, ACoordX, ACoordY, X, Y) {
    console.log(`${currDt()}: onContextMenuFunc, ${ALyrIdx}, ${ALyrName}, ${ANmbr}, ${ACoordX}, ${ACoordY}, ${X}, ${Y}`);
    $('.cctv-right-btn-click').remove();
    $('.vms-right-btn-click').remove();
    //cctv 우클릭 이벤트
    if (ALyrIdx === LayerIndex.Cctv) {
        const cctvObj = _mapManager.findLayerObject(LayerIndex.Cctv, ANmbr);
        if (cctvObj) {
            let div = $(`<div class='cctv-right-btn-click'>
                            <div>
                                <div>[CCTV] ${cctvObj.ID} - ${cctvObj.NAME}</div>
                                <div>카메라 영상</div>
                            </div>
                        </div>`);
            $('body').append(div);
            
            if ($('#drawer')[0].offsetWidth - X < div[0].offsetWidth){
                div.css('left', $('#drawer')[0].offsetWidth - div[0].offsetWidth + 12);
            } 
            else {
                div.css('left', X);
            }

            if ($('#drawer')[0].offsetHeight - Y < div[0].offsetHeight){
                div.css('top', $('#drawer')[0].offsetHeight - div[0].offsetHeight + 59);
            } 
            else {
                div.css('top', Y);
            }
            
            if (!_cctvMap.get(cctvObj.ID)){
                _cctvMap.set(cctvObj.ID, new Map());
            }

            $(div).children().eq(0).children().eq(1).on('click',function(e){
                $('.cctv-right-btn-click').remove();
                let src = cctvObj.strmHttpAddr;
                camCtrl(_cctvMap, createVideoDiv, cctvObj, src, X, Y);
            })
        }
    }
    //vms 우클릭 이벤트
    else if (ALyrIdx === LayerIndex.Vms) {
        const vmsObj = _mapManager.findLayerObject(LayerIndex.Vms, ANmbr);
        if (vmsObj) {
            let div = $(`<div class='vms-right-btn-click'>
                            <div>
                                <div>[VMS] ${vmsObj.ID} - ${vmsObj.NAME}</div>
                                <div>카메라 영상</div>
                                <div>표출메시지</div>
                            </div>
                        </div>`);
            $('body').append(div);

            if ($('#drawer')[0].offsetWidth - X < div[0].offsetWidth){
                div.css('left', $('#drawer')[0].offsetWidth - div[0].offsetWidth + 12);
            } 
            else {
                div.css('left', X);
            }

            if ($('#drawer')[0].offsetHeight - Y < div[0].offsetHeight){
                div.css('top', $('#drawer')[0].offsetHeight - div[0].offsetHeight + 59);
            } 
            else {
                div.css('top', Y);
            }

            if (!_cctvMap.get(vmsObj.ID)){
                _cctvMap.set(vmsObj.ID, new Map());
            }
            if (!_vmsMap.get(vmsObj.ID)){
                _vmsMap.set(vmsObj.ID, new Map());
            }
            
            // 카메라 영상 클릭 이벤트
            $(div).children().eq(0).children().eq(1).on('click',function(){
                $('.vms-right-btn-click').remove();
                let src = vmsObj.strmHttpAddr;
                camCtrl(_cctvMap, createVideoDiv, vmsObj, src, X, Y, true);
            });

            //표출메시지 클릭 이벤트
            $(div).children().eq(0).children().eq(2).on('click',function(){
                    $('.vms-right-btn-click').remove();

                    if(!_vmsMap.get(vmsObj.ID).get('div')){
                        vmsMessageCtrl(vmsObj,X, Y);
                    }
            })
        }
    }

}  

/**
 * 표출메시지 이벤트
 * @param {*} obj vms 객체
 * @param {*} X 마우스 X 좌표
 * @param {*} Y 마우스 Y 좌표
 */
export function vmsMessageCtrl(obj, X, Y){
    let vmsData = [];
    //vms 데이터 수신
    getData('/api/vms/common/vms-form/dspl-prst', vmsData, {id:obj.NMBR});
    if (vmsData[0]  && vmsData[0].length > 0) {
        
        vmsData = vmsData[0];
        //vms 이미지 데이터
        let msgs = vmsData[0].msgs;
        //현재 시각
        let now = "제공시각 - " + nowTime();
        //이미지 높이에 따른 박스 높이
        let height = vmsData[0].vms_hght + 80;
        //이미지 높이
        let imgBoxHeight = vmsData[0].vms_hght;
        //이미지 넓이에 따른 박스 넓이
        let width = vmsData[0].vms_wdth + 20;
        //vms div 생성
        let vmsDiv = createMessageDiv(obj, now, vmsData[0].cmnc_stts_desc);
        let vmsLeft = X;
        let vmsTop = Y;

        $('body').append(vmsDiv);
        vmsDiv.children().eq(1).css('height', imgBoxHeight);
        vmsDiv.children().eq(1).children().eq(0).css({height: imgBoxHeight, width: width - 20});
        if ($('#drawer')[0].offsetWidth - X < width){
            vmsLeft = $('#drawer')[0].offsetWidth - width + 12;
        } 
        if ($('#drawer')[0].offsetHeight - Y < height){
            vmsTop = $('#drawer')[0].offsetHeight - height + 59;
        }

        vmsDiv.css({left:vmsLeft, top:vmsTop, height: height});

        let imgPosition         = vmsDiv.children().eq(1).children().eq(0);
        let phaseNumPosition    = vmsDiv.children().eq(2).children().eq(0);
        let intervalNumPosition = vmsDiv.children().eq(2).children().eq(1);
        let closePosition       = vmsDiv.children().eq(0).children().eq(0);
        let vmsInfo = _vmsMap.get(obj.ID);
        vmsInfo.set('div', vmsDiv);
        setVmsInterval(msgs, imgPosition, phaseNumPosition, intervalNumPosition, 0, obj.ID);
        //vmsInfo.set('intervalArr', intervalArr);
        
        dragEvent(vmsDiv, 'vms-box');
        
        closePosition.on('click', function(){
            clearTimeout(vmsInfo.get('interval'));
            vmsInfo.get('div').remove();
            vmsInfo.delete('div');
        });
    }
    else {
        //현재 시각
        let now = '표출메시지가 없습니다.';
        //이미지 높이에 따른 박스 높이
        let height = 144;
        //이미지 높이
        let imgBoxHeight = 64;
        //이미지 넓이에 따른 박스 넓이
        let width = 404;
        //vms div 생성
        let vmsDiv = createMessageDiv(obj, now);
        let vmsLeft = X;
        let vmsTop = Y;

        $('body').append(vmsDiv);
        vmsDiv.children().eq(1).css('height', imgBoxHeight);
        vmsDiv.children().eq(1).children().eq(0).css({height: imgBoxHeight, width: width - 20});
        if ($('#drawer')[0].offsetWidth - X < width){
            vmsLeft = $('#drawer')[0].offsetWidth - width + 12;
        } 

        if ($('#drawer')[0].offsetHeight - Y < height){
            vmsTop = $('#drawer')[0].offsetHeight - height + 59;
        }

        vmsDiv.css({left:vmsLeft, top:vmsTop, width:width, height: height});

        let imgPosition         = vmsDiv.children().eq(1).children().eq(0);
        let closePosition       = vmsDiv.children().eq(0).children().eq(0);
        imgPosition.css('background-color', 'black');
        let vmsInfo = _vmsMap.get(obj.ID);
        vmsInfo.set('div', vmsDiv);
        dragEvent(vmsDiv, 'vms-box');
        
        closePosition.on('click', function(){
            vmsInfo.get('div').remove();
            vmsInfo.delete('div');
        });
    }
}

/**
 * vms 이미지 인터벌
 * @param {*} value  vms 데이터
 * @param {*} position vms 이미지 위치
 * @param {*} phase phase 번호 텍스트 위치
 * @param {*} num 카운트 텍스트 위치
 */
export function setVmsInterval(data, position, phase, num, idx, id){
    if (data[idx]) {
        $(position).prop('src', 'data:image/png;base64,'+ data[idx].vms_dspl_msg_imag);
        let time = data[idx].dspl_hh;
        let intervalNum = data[idx].dspl_hh;
        idx++;
        $(num).text(intervalNum--);
        $(phase).text(idx + '/' + data.length);
        let timeInterval = setInterval(()=>{
            $(num).text(intervalNum--);
            if(intervalNum === 0){
                clearInterval(timeInterval);
            }
        }, 1000);
        if(idx === data.length){
            idx = 0;
        }
        let interval = setTimeout(() => {
            window.clearTimeout(interval);
            setVmsInterval(data, position, phase, num, idx, id);
        }, time * 1000);
        _vmsMap.get(id).set('interval', interval);
    }
}

/**
 * 시설물 클릭 시 카메라 영상 생성 및 이동 이벤트
 * @param {*} map 해당 맵 객체
 * @param {*} obj 해당 시설물 객체
 * @param {*} src 영상 소스
 * @param {*} X X좌표
 * @param {*} Y Y좌표
 */
 export function camCtrl(map, method, obj, src, X, Y, vmsTrue){
        let cctvBox = method(obj);
        $("body").append(cctvBox);
        let cctvLeft = X;
        let cctvTop  = Y;
        if ($('#drawer')[0].offsetWidth - X < cctvBox[0].offsetWidth){
            cctvLeft = $('#drawer')[0].offsetWidth - cctvBox[0].offsetWidth + 12;
        } 

        if ($('#drawer')[0].offsetHeight - Y < cctvBox[0].offsetHeight){
            cctvTop = $('#drawer')[0].offsetHeight - cctvBox[0].offsetHeight + 59;
        }
        cctvBox.css({left:cctvLeft, top:cctvTop});

        let cctvInfo = map.get(obj.ID);
        cctvInfo.set('div', cctvBox);
        let player = webRtcConnector(obj, $('#' + obj.ID).children().eq(1).children().eq(0), 'video' + obj.ID, vmsTrue);
        if (player) {
            cctvInfo.set('video', player);
        }
        cctvBox.children().eq(0).children().eq(0).on('click',function(){
            cctvBox.remove();
            if (cctvInfo.get('video')) {
                cctvInfo.get('video').Stop();
            }
        });

        dragEvent(cctvBox, 'cctv-box');
}

/**
 * 카메라 영상 div 생성
 * @param {*} obj 데이터 객체
 * @returns 생성 div
 */
 export function createVideoDiv(obj){
    let div = $(`<div class="cctv-box dx-nav-item" id=${obj.ID} draggable="true">
        <div class="b2 dx-theme-border-color">${obj.ID} - ${obj.NAME} <span class="b0 dx-theme-border-color" title="닫기">X</span></div>
        <div>
            <div class="bg-black"></div>
        </div>
    </div>`);
    return div;
}

function webRtcConnector(obj, videoBox, id, vmsTrue){
    //let { web_rtc_svr_ip, web_rtc_svr_port, web_rtc_id } = obj;
    let { rtc_svr_ip, rtc_svr_port, rtc_id } = obj;
    console.log(obj);
    if (vmsTrue) {
        rtc_svr_ip = obj.web_rtc_svr_ip;
        rtc_svr_port = obj.web_rtc_svr_port;
        rtc_id = obj.web_rtc_id;
    }
    let isNull = nullArrChecker([rtc_svr_ip, rtc_svr_port, rtc_id]);
    if (!isNull) {
        videoBox.append($(`<video id="${id}" class="cctv-body" style="width:100%; height:100%;" autoplay playsinline muted></video>`))
        let video = new HiVeWebRtcPlayer(id, rtc_svr_ip, rtc_svr_port, rtc_id);
        video.Play();
        return video;
    } else {
        videoBox.css('background-color', '');
        videoBox.append($(`<div class="empty-body" id="${id}">
                            <h5>영상 스트리밍 정보를 확인해주세요.</h5> 
                            <br>
                            <div class="error-content">
                                <div class="fr">
                                    <div class='error-label'>
                                        WEB RTC IP
                                    </div>
                                    <div class='ml-5'> : </div>
                                    <div class='ml-5'>
                                        ${rtc_svr_ip}
                                    </div>
                                </div>
                                <div class="fr">
                                    <div class='error-label'>
                                        WEB RTC PORT
                                    </div>
                                    <div class='ml-5'> : </div>
                                    <div class='ml-5'>
                                        ${rtc_svr_port}
                                    </div>
                                </div>
                                <div class="fr">
                                    <div class='error-label'>
                                        WEB RTC ID
                                    </div>
                                    <div class='ml-5'> : </div>
                                    <div class='ml-5'>
                                        ${rtc_id}
                                    </div>
                                </div>
                            </div>
                        </div>`))
    }
}
/**
 * 메시지 표출 div 생성
 * @param {*} obj 데이터 객체
 * @param {*} now 현재 시각
 * @returns 생성 div
 */
 export function createMessageDiv(obj, now, cmncSttsDesc){
    const procClass = cmncSttsDesc === "통신두절" || !cmncSttsDesc ? 't-red' : '';
    let div = $(`<div draggable="true" class="vms-box dx-nav-item">
                    <div class="b2 dx-theme-border-color">${obj.ID} - ${obj.NAME} &nbsp;&nbsp;<span class="b0 dx-theme-border-color" title="닫기">X</span></div>
                    <div>
                        <img class='vms-img'>
                    </div>
                    <div class="${procClass}">${now} <span class="phase-num"></span>&nbsp;&nbsp;<span class="interval-num"></span></div>
                </div>`);
    return div;
}

/**
 * 드래그 이벤트 
 * @param {*} position 드래그 상자 위치
 */
export function dragEvent(position, classNm){
    $(position).on('mousedown', function(){
        for (let ii = 0; ii < $('.' + classNm).length; ii++ ){
            $($('.' + classNm)[ii]).css('z-index', '100');
        };
        $(position).css('z-index', '101');
    })
    
    position.on("dragstart", function(ev){
        let offsetX = ev.offsetX;
        let offsetY = ev.offsetY;
        $('#drawer').off('drop');
        $('#drawer').off('dragover');
        
        $('#drawer').on('dragover', function(ev){
            ev.preventDefault();
        })
        
        $('#drawer').on('drop',function(ev){
            ev.preventDefault();
            $(position).css({left : ev.clientX - offsetX, top : ev.clientY - offsetY});
        })
    });
}

function setTranslate(xPos, yPos, el) {
    el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
}

function onSelectObjFunc(ALyrIdx, ALyrName, ANmbr, ACoordX, ACoordY, X, Y) {
    //console.log(`${currDt()}: onSelectObjFunc, ${ALyrIdx}, ${ALyrName}, ${ANmbr}, ${ACoordX}, ${ACoordY}, ${X}, ${Y}`);
}
function onFcltDragEndFunc(ALyrIdx, ALyrName, ANmbr, ACoordX, ACoordY) {
    //console.log(`${currDt()}: onFcltDragEndFunc, ${ALyrIdx}, ${ALyrName}, ${ANmbr}, ${ACoordX}, ${ACoordY}`);
}

export function loadingData() {
    fetchBaseData();
    fetchFcltData();
    fetchUnitStts();
    fetchIncdData(); // 돌발정보 요청
}

/**
 * Promise.all 사용해서 하나라도 오류가 발생하면 다음 함수가 실행되지 않도록 한다.
 * 개별 오류 catch 하면 다음 작업에서 계속 오류가 발생(객체를 찾지 못함)하기 때문에
 * 아예 다음작업이 수행되지 않도록 catch 를 한번 만 잡는다.
 * 즉, 오류가 발생하면 그냥 오류 발생 후 다음 작업이 진행되지 않도록 한다.
 */
async function fetchBaseData() {
    //console.time("***** fetchBaseData: ");
    const node = apiGet("/api/database/node/list"); // 노드정보 요청
    const link = apiGet("/api/database/link/list"); // 링크정보 요청
    const ifsc = apiGet("/api/database/ifsc/list"); // 링크정보 요청
    const road = apiGet("/api/database/road/list"); // 도로정보 요청
   
    Promise.all([node, link, ifsc, road])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            //console.log(`${currDt()}: BaseData, NODE(${values[0].length}), LINK(${values[1].length}), IFSC(${values[2].length}), ROAD(${values[3].length})`);
            _mapManager.makeLayer(LayerIndex.Node, values[0]);
            _mapManager.makeTrafficObject(LayerType.LINK, values[1]);
            _mapManager.makeTrafficObject(LayerType.IFSC, values[2]);
            _mapManager.makeTrafficObject(LayerType.ROAD, values[3]);
            _trafficMap.set('node', values[0]);
            _trafficMap.set('link', values[1]);
            _trafficMap.set('ifsc', values[2]);
            _trafficMap.set('road', values[3]);
            fetchTraffic();
            fetchBaseVrtx();
        })
        .catch((err) => {
            console.error(`${currDt()}: Error in fetchBaseData ${err}`);
        })
        //.finally(() => console.timeEnd("***** fetchBaseData: "));
}

async function fetchTraffic() {
    //console.time("***** fetchTraffic: ");
    const link = apiGet("/api/manage/main/traffic/link"); // 링크소통정보 요청
    const ifsc = apiGet("/api/manage/main/traffic/ifsc"); // 링크소통정보 요청
    const road = apiGet("/api/manage/main/traffic/road"); // 도로소통정보 요청
    
    // 결측구간, 반복정체구간은 async 로 조회한다.
    requestGet("/api/manage/main/syst-opr/miss-link-traf", recvMissLinkTraf);
    requestGet("/api/manage/main/syst-opr/repeat-congest", recvRepeatCongest);
    Promise.all([link, ifsc, road])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            //console.log(`${currDt()}: Traffic, LINK(${values[0].length}), IFSC(${values[1].length}), ROAD(${values[2].length})`);
            _mapManager.updateTrafficObject(LayerType.LINK, values[0]);
            _mapManager.updateTrafficObject(LayerType.IFSC, values[1]);
            _mapManager.updateTrafficObject(LayerType.ROAD, values[2]);
        })
        .catch((err) => {
            console.error(`Error in fetchTraffic ${err}`);
        })
        //.finally(() => console.timeEnd("***** fetchTraffic: "));

    // 요청시간을 기준으로 교통정보 요청 타이머 리셋
    requestFetchTraffic();
}

function recvMissLinkTraf(jsonData) {
    MAIN.updateMissLinkTraf(jsonData);
}
function recvRepeatCongest(jsonData) {
    MAIN.updateRepeatCongest(jsonData);
}
async function fetchBaseVrtx() {
    //console.time("***** fetchBaseVrtx: ");

    // 버텍스를 표출할 레벨을 설정한다.
    _mapManager.setLayerVisible(LayerIndex.Link1, 16);
    _mapManager.setLayerVisible(LayerIndex.Link2, 17, 18, 19);
    _mapManager.setLayerVisible(LayerIndex.Ifsc1, 14);
    _mapManager.setLayerVisible(LayerIndex.Ifsc2, 15);
    _mapManager.setLayerVisible(LayerIndex.Road1, 10);
    _mapManager.setLayerVisible(LayerIndex.Road2, 11, 12, 13);
//feature.setGeometry(bufferedFeature.getGeometry());

//console.error("***** fetchBaseVrtx_1: ");
    //const link1 = apiGet("/api/manage/main/map/vrtx/link/1"); // 버텍스정보 요청(1 => 16)
    const link2 = apiGet("/api/manage/main/map/vrtx/link/2"); // 버텍스정보 요청(2 => 17,18,19)
    //const ifsc3 = apiGet("/api/manage/main/map/vrtx/ifsc/3"); // 버텍스정보 요청(3 => 15)
    const ifsc4 = apiGet("/api/manage/main/map/vrtx/ifsc/4"); // 버텍스정보 요청(4 => 14)
    //const road5 = apiGet("/api/manage/main/map/vrtx/road/5"); // 버텍스정보 요청(5 => 13)
    const road6 = apiGet("/api/manage/main/map/vrtx/road/6"); // 버텍스정보 요청(6 => 10, 11, 12)
    //Promise.all([link1, link2, ifsc3, ifsc4, road5, road6])
    Promise.all([link2, ifsc4, road6])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            // console.log(
            //     `${currDt()}: FcltData, LINK1(${values[0].length}), LINK2(${values[1].length}), IFSC3(${values[2].length}), IFSC4(${values[3].length}), ROAD5(${
            //         values[4].length
            //     }), ROAD6(${values[5].length})`
            // );
            //console.error("***** fetchBaseVrtx_2: ");
            _mapManager.makeLayer(LayerIndex.Link1, values[0]);
            //console.error("***** fetchBaseVrtx_3: ");
            _mapManager.makeLayer(LayerIndex.Link2, values[0]);
            //console.error("***** fetchBaseVrtx_4: ");
            _mapManager.makeLayer(LayerIndex.Ifsc1, values[1]);
            //console.error("***** fetchBaseVrtx_5: ");
            _mapManager.makeLayer(LayerIndex.Ifsc2, values[1]);
            //console.error("***** fetchBaseVrtx_6: ");
            _mapManager.makeLayer(LayerIndex.Road1, values[2]);
            //console.error("***** fetchBaseVrtx_7: ");
            _mapManager.makeLayer(LayerIndex.Road2, values[2]);
            //console.error("***** fetchBaseVrtx_8: ");
            _trafficMap.set('link1', values[0]);
            //console.error("***** fetchBaseVrtx_9: ");
            _trafficMap.set('link2', values[0]);
            //console.error("***** fetchBaseVrtx_10: ");
            _trafficMap.set('ifsc1', values[1]);
            //console.error("***** fetchBaseVrtx_11: ");
            _trafficMap.set('ifsc2', values[1]);
            //console.error("***** fetchBaseVrtx_12: ");
            _trafficMap.set('road1', values[2]);
            //console.error("***** fetchBaseVrtx_13: ");
            _trafficMap.set('road2', values[2]);
            //console.error("***** fetchBaseVrtx_14: ");
            fetchFcltStts();
        })
        .catch((err) => {
            console.error(`Error in fetchBaseVrtx ${err}`);
        })
        .finally(() => {
            $('.loading-box').css('display','none');
        });
}

async function fetchFcltData() {
    //console.time("***** fetchFcltData: ");
    const cctv = apiGet("/api/cctv/common/cctv-list"); // CCTV
    const vms  = apiGet("/api/vms/common/vms-list"); // VMS
    const vds  = apiGet("/api/vds/common/vds-list"); // VDS
    const dsrc = apiGet("/api/rse/tb_rse_ctlr"); // RSE
    const sig = apiGet("/api/scrs/tb_sc_sgnl_ctlr"); // 신호제어기(SIG)
    const ccam = apiGet("/api/scrs/tb_sc_ixr_cmra_mngm/list"); // 교차로 카메라
    Promise.all([cctv, vms, vds, dsrc, sig, ccam])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            // console.log(
            //     //`${currDt()}: FcltData, CCTV(${values[0].length}), VMS(${values[1].length}), VDS(${values[2].length}),  PARK(${values[3].length}), BIT(${values[4].length})`
            //     `${currDt()}: FcltData, CCTV(${values[0].length}), VMS(${values[1].length}), VDS(${values[2].length})`
            // );

            _mapManager.makeLayer(LayerIndex.Cctv, values[0]);
            _mapManager.makeLayer(LayerIndex.Vms, values[1]);
            _mapManager.makeLayer(LayerIndex.Vds, values[2]);
            _mapManager.makeLayer(LayerIndex.Dsrc, values[3]);
            _mapManager.makeLayer(LayerIndex.Sig, values[4]);
            _mapManager.makeLayer(LayerIndex.CCam, values[5]);
            fetchFcltStts();
        })
        .catch((err) => {
            console.error(`Error in fetchFcltData ${err}`);
        })
        //.finally(() => console.timeEnd("***** fetchFcltData: "));
}
// 시설물 상태정보 요청(타이머 또는 웹소켓에 의해 실행됨)
async function fetchFcltStts() {
    //console.time("***** fetchFcltStts: ");

    const its = apiGet("/api/common/stts/total"); // ITS 상태정보 요청
    //const bit = apiGet("/api/bis/stts/bit/total"); // BIT 상태정보 요청

    //Promise.all([its, bit])
    Promise.all([its])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            //console.log(`${currDt()}: FcltStts, ITS(${values[0].fclt_list.length}))`);
            //console.log(`${currDt()}: FcltStts, ITS(${values[0].fclt_list.length}), BIT(${values[1].fclt_list.length})`);
            updateFcltStts(values[0]);
            //updateFcltStts(values[1]);
            MAIN.updateFcltStts(_sttsMap);

            //const sttsArray = Array.from(_sttsMap.values());
            //console.log(sttsArray);
        })
        .catch((err) => {
            console.error(`Error in fetchFcltStts ${err}`);
        })
        //.finally(() => console.timeEnd("***** fetchFcltStts: "));

    // 요청시간을 기준으로 상태정보 요청 타이머 리셋
    requestFetchFcltStts();
}
function updateFcltStts(jsonData) {
    jsonData.fclt_list.forEach((el) => {
        let lyrInfo = null;
        const stts = _sttsMap.get(el.fclt_type);
        if (!stts) {
            return;
        }
        let toNumber = false;
        if (el.fclt_type === "CCTV") {
            lyrInfo = _mapManager.getLayer(LayerIndex.Cctv);
            toNumber = true;
        } else if (el.fclt_type === "VMS") {
            lyrInfo = _mapManager.getLayer(LayerIndex.Vms);
            toNumber = true;
        } else if (el.fclt_type === "VDS") {
            lyrInfo = _mapManager.getLayer(LayerIndex.Vds);
            toNumber = true;
        } else if (el.fclt_type === "DSRC") {
            lyrInfo = _mapManager.getLayer(LayerIndex.Dsrc);
            toNumber = true;
        } 
        else if (el.fclt_type === "SIG") {
            lyrInfo = _mapManager.getLayer(LayerIndex.Sig);
            toNumber = true;
        }
        else if (el.fclt_type === "CCAM") {
            lyrInfo = _mapManager.getLayer(LayerIndex.CCam);
        }
        if (lyrInfo) {
            stts.total = el.total_cnt;
            stts.normal = el.normal_cnt;
            stts.error = el.error_cnt;
            stts.collect = el.col_err_cnt;
            stts.objLists = el.fclt_objs;
            el.fclt_objs.forEach((obj) => {
                const fclt = lyrInfo.findObject(toNumber ? Number(obj.fclt_nmbr) : obj.fclt_nmbr);
                if (fclt) {
                    fclt.updateStts(obj.stts_cd, obj.updt_dt);
                } else {
                    console.warn(`fetchFcltStts: Not Found Object, ${obj.fclt_type}, ${obj.fclt_nmbr}, ${obj.fclt_id}`);
                }
            });
        } else {
            console.error(currDt(), " Unknown Fclt Type: ", el.fclt_type);
        }
    });
}
// 센터프로세스 상태정보 요청(타이머 또는 웹소켓에 의해 실행됨)
export async function fetchUnitStts() {
    if (_timerFetchUnitStts) window.clearTimeout(_timerFetchUnitStts);
    //console.time("***** fetchUnitStts: ");

    const its = apiGet("/api/common/stts/process/its"); // 센터프로세스 ITS
    //const bis = apiGet("/api/bis/stts/process"); // 센터프로세스 BIT

    Promise.all([its])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            //console.log(`${currDt()}: UnitStts, ITS(${values[0].length}), BIS(${values[1].length})`);
            //console.log(`${currDt()}: UnitStts, ITS(${values[0].length})`);
            MAIN.updateUnitStts(values[0]); //ITS 프로세스
            //updateUnitStts(values[1]); //BIS 프로세스
        })
        .catch((err) => {
            console.error(`Error in fetchUnitStts ${err}`);
        })
        //.finally(() => console.timeEnd("***** fetchUnitStts: "));

    // 요청시간을 기준으로 상태정보 요청 타이머 리셋
    requestFetchUnitStts();
}
// function updateUnitStts(jsonData) {
//     //console.log("updateUnitStts: ", jsonData);
//     jsonData.forEach((obj) => {
//         const runStts = obj.run_sts.slice(-1);
//         let comStts = obj.com_sts.slice(-1);
//         let dbStts = obj.db_sts.slice(-1);
//         if (runStts == "1") {
//             comStts = "1";
//             dbStts = "1";
//         }

//         // const comImg = "<img src='/images/application_wall/stts" + comStts + ".png'>";
//         // //const dbImg = "<img src='/images/application_wall/stts" + dbStts + ".png'>";
//         // setHtml(".A" + obj.syst_id + "_server", comImg);
//         // if (comStts == null || comStts == "0" || comStts == "2") {
//         //     windowPop(obj.syst_id);
//         // }
//     });
//     //MAIN._dataUnitSttsList = jsonData;
//     MAIN._gridFcltSttsBoard.option("dataSource", jsonData);
// }

// 돌발정보 수신
function recvIncdData(jsonData) {
    //console.log(`${currDt()}: recvIncdData: ${jsonData.length} EA.`);
    _mapManager.makeLayer(LayerIndex.Incd, jsonData); // 레이어 생성
    MAIN.updateIncdData(jsonData);
    //console.timeEnd("***** fetchIncdData: ");
}
// 돌발정보 수신
function recvAutoIncd(jsonData) {
    //console.log( `${ currDt() }: recvAutoIncd: ${ jsonData.length } EA.` );
    MAIN.updateAutoIncd(jsonData);
}
// 돌발정보요청
function fetchIncdData() {
    //console.time("***** fetchIncdData: ");
    requestGet("/api/manage/main/syst-opr/incd-ocrr", recvIncdData); // 돌발정보
    requestGet("/api/manage/main/syst-opr/auto-incd", recvAutoIncd); // 시스템 자동 돌발 정보

    // 요청시간을 기준으로 돌발정보 요청 타이머 리셋
    requestFetchIncdData();
}

// 시설물 개별적으로 상태정보 요청
async function fetchFcltSttsIndividual() {
    const cctv = apiGet("/api/cctv/monitoring/stts"); // CCTV 상태정보 요청
    const vms = apiGet("/api/vms/monitoring/stts"); // VMS 상태정보 요청
    const vds = apiGet("/api/vds/monitoring/ctlr-stts"); // VDS 상태정보 요청
    //const bit = apiGet("/api/bis/stts/bit"); // BIT 상태정보 요청
    const rse = apiGet("/api/utis/stts/rse"); // RSE 상태정보 요청

    //Promise.all([cctv, vms, vds, rse, bit])
    Promise.all([cctv, vms, vds, rse])
        .then((results) => Promise.all(results.map((r) => r.json())))
        .then((values) => {
            //console.log(`${currDt()}: CCTV(${values[0].length}), VMS(${values[1].length}), VDS(${values[2].length}), BIT(${values[3].length})`);
            //console.log(`${currDt()}: CCTV(${values[0].length}), VMS(${values[1].length}), VDS(${values[2].length})`);

            const cctvStts = recvCctvSttsInfo(values[0]);
            const vmsStts = recvVmsSttsInfo(values[1]);
            const vdsStts = recvVdsSttsInfo(values[2]);
            //const bitStts = recvBitSttsInfo(values[3]);
            const rseStts = recvRseSttsInfo(values[3]);

            //console.log(currDt(), "CCTV: ", cctvStts);
            //console.log(currDt(), " VMS: ", vmsStts);
            //console.log(currDt(), " VDS: ", vdsStts);
            //console.log(currDt(), " BIT: ", bitStts);
            //console.log(currDt(), " RSE: ", rseStts);
        })
        .catch((err) => {
            console.error(`Error in fetchFcltStts ${err}`);
        });

    // 요청시간을 기준으로 시설물 상태정보 요청 타이머 리셋
    requestFetchFcltStts();
}

function recvNodeInfo(AJsonData) {
    //console.log("recvNodeInfo: " + AJsonData.length + " EA.");
    _mapManager.makeLayer(LayerIndex.Node, AJsonData);
}
function recvLinkInfo(AJsonData) {
    //console.log("recvLinkInfo: " + AJsonData.length + " EA.");
    _mapManager.makeTrafficObject(LayerType.LINK, AJsonData);

    requestGet("/api/manage/main/traffic/link", recvLinkTrafInfo); // 소통정보 요청
    requestGet("/api/manage/main/map/vrtx/link/1", recvLinkVrtxInfo, LayerIndex.Link1); // 버텍스정보 요청(1 => 16)
    requestGet("/api/manage/main/map/vrtx/link/2", recvLinkVrtxInfo, LayerIndex.Link2); // 버텍스정보 요청(2 => 17,18,19)
}
function recvLinkTrafInfo(AJsonData) {
    //console.log("recvLinkTrafInfo: " + AJsonData.length + " EA.");
    _mapManager.updateTrafficObject(LayerType.LINK, AJsonData);
}

function recvIfscInfo(AJsonData) {
    //console.log("recvIfscInfo: " + AJsonData.length + " EA.");
    _mapManager.makeTrafficObject(LayerType.IFSC, AJsonData);

    requestGet("/api/manage/main/traffic/ifsc", recvIfscTrafInfo); // 소통정보 요청
    requestGet("/api/manage/main/map/vrtx/ifsc/3", recvIfscVrtxInfo, LayerIndex.Ifsc1); // 버텍스정보 요청(3 => 14)
    requestGet("/api/manage/main/map/vrtx/ifsc/4", recvIfscVrtxInfo, LayerIndex.Ifsc2); // 버텍스정보 요청(4 => 15)
}
function recvIfscTrafInfo(AJsonData) {
    //console.log("recvIfscTrafInfo: " + AJsonData.length + " EA.");
    _mapManager.updateTrafficObject(LayerType.IFSC, AJsonData);
}

function recvRoadInfo(AJsonData) {
    //console.log("recvRoadInfo: " + AJsonData.length + " EA.");
    _mapManager.makeTrafficObject(LayerType.ROAD, AJsonData);

    requestGet("/api/manage/main/traffic/road", recvRoadTrafInfo); // 소통정보 요청
    requestGet("/api/manage/main/map/vrtx/road/5", recvRoadVrtxInfo, LayerIndex.Road1); // 버텍스정보 요청(5 => 10, 11, 12)
    requestGet("/api/manage/main/map/vrtx/road/6", recvRoadVrtxInfo, LayerIndex.Road2); // 버텍스정보 요청(6 => 13)
}
function recvRoadTrafInfo(AJsonData) {
    //console.log("recvRoadTrafInfo: " + AJsonData.length + " EA.");
    _mapManager.updateTrafficObject(LayerType.ROAD, AJsonData);
}

function recvLinkVrtxInfo(AJsonData, ALyrIdx) {
    //console.log(`${currDt()}: recvLinkVrtxInfo: ${ALyrIdx}, ${AJsonData.length} EA.`);
    _mapManager.makeLayer(ALyrIdx, AJsonData);
}
function recvIfscVrtxInfo(AJsonData, ALyrIdx) {
    //console.log(`${currDt()}: recvIfscVrtxInfo: ${ALyrIdx}, ${AJsonData.length} EA.`);
    _mapManager.makeLayer(ALyrIdx, AJsonData);
}
function recvRoadVrtxInfo(AJsonData, ALyrIdx) {
    //console.log(`${currDt()}: recvRoadVrtxInfo: ${ALyrIdx}, ${AJsonData.length} EA.`);
    _mapManager.makeLayer(ALyrIdx, AJsonData);
}
// CCTV
function recvCctvInfo(AJsonData) {
    //console.log("recvCctvInfo: " + AJsonData.length + " EA.");
    _mapManager.makeLayer(LayerIndex.Cctv, AJsonData);
    requestGet("/api/cctv/monitoring/stts", recvCctvSttsInfo); // 상태정보 요청
}
// CCTV 상태
function recvCctvSttsInfo(AJsonData) {
    let stts = new FcltStts();
    const lyrInfo = _mapManager.getLayer(LayerIndex.Cctv);
    if (lyrInfo == null) {
        return stts;
    }
    AJsonData.forEach((el, idx) => {
        const obj = lyrInfo.findObject(el.nmbr);
        if (obj) {
            stts.total++;
            const sttsCd = el.cmnc_stts_cd.slice(-1);
            if (Number(sttsCd) == 0) {
                stts.normal++;
            }
            obj.updateStts(el.cmnc_stts_cd, el.updt_dt);
        }
    });
    stts.error = stts.total - stts.normal;
    //console.log(`${currDt()} recvCctvSttsInfo: ${AJsonData.length} EA.`);
    return stts;
}

// VMS
function recvVmsInfo(AJsonData) {
    //console.log("recvVmsInfo: " + AJsonData.length + " EA.");
    _mapManager.makeLayer(LayerIndex.Vms, AJsonData);
    requestGet("/api/vms/monitoring/stts", recvVmsSttsInfo); // 상태정보 요청
}
// VMS 상태
function recvVmsSttsInfo(AJsonData) {
    let stts = new FcltStts();
    const lyrInfo = _mapManager.getLayer(LayerIndex.Vms);
    if (lyrInfo == null) {
        return stts;
    }
    AJsonData.forEach((el, idx) => {
        const obj = lyrInfo.findObject(el.nmbr);
        if (obj) {
            stts.total++;
            const sttsCd = el.cmnc_stts_cd.slice(-1);
            if (Number(sttsCd) == 0) {
                stts.normal++;
            }
            obj.updateStts(el.cmnc_stts_cd, el.updt_dt);
        }
    });
    stts.error = stts.total - stts.normal;
    //console.log(`${currDt()} recvVmsSttsInfo: ${AJsonData.length} EA.`);
    return stts;
}

// VDS
function recvVdsInfo(AJsonData) {
    //console.log("recvVdsInfo: " + AJsonData.length + " EA.");
    _mapManager.makeLayer(LayerIndex.Vds, AJsonData);
    requestGet("/api/vds/monitoring/ctlr-stts", recvVdsSttsInfo); // 상태정보 요청
}
// VDS 상태
function recvVdsSttsInfo(AJsonData) {
    let stts = new FcltStts();
    const lyrInfo = _mapManager.getLayer(LayerIndex.Vds);
    if (lyrInfo == null) {
        return stts;
    }
    AJsonData.forEach((el, idx) => {
        const obj = lyrInfo.findObject(el.nmbr);
        if (obj) {
            stts.total++;
            const sttsCd = el.cmnc_stts_cd.slice(-1);
            if (Number(sttsCd) == 0) {
                stts.normal++;
                if (el.coll_cnt == 0) {
                    stts.collect++;
                }
            }
            obj.updateStts(el.cmnc_stts_cd, el.updt_dt);
        }
    });
    stts.error = stts.total - stts.normal;
    //console.log(`${currDt()} recvVdsSttsInfo: ${AJsonData.length} EA.`);
    return stts;
}

// RSE
function recvRseInfo(AJsonData) {
    //console.log("recvRseInfo: " + AJsonData.length + " EA.");
    _mapManager.makeLayer(LayerIndex.Rse, AJsonData);
    //requestGet("/api/utis/stts/rse", recvRseSttsInfo); // 상태정보 요청
}
// RSE 상태
function recvRseSttsInfo(AJsonData) {
    let stts = new FcltStts();
    const lyrInfo = _mapManager.getLayer(LayerIndex.Rse);
    if (lyrInfo == null) {
        return stts;
    }
    AJsonData.forEach((el, idx) => {
        const obj = lyrInfo.findObject(el.fclt_id);
        if (obj) {
            stts.total++;
            const sttsCd = el.stts_cd.slice(-1);
            if (Number(sttsCd) == 0) {
                stts.normal++;
            }
            obj.updateStts(el.stts_cd, el.updt_dt);
        }
    });
    stts.error = stts.total - stts.normal;
    //console.log(`${currDt()} recvRseSttsInfo: ${AJsonData.length} EA.`);

    // 시설물 상태정보 요청 타이머 설정
    //_timerLoadingFcltStts = window.setTimeout(function() {
    //  loadingFcltStts();
    //}, (60 * 1000));
    return stts;
}

// Park
function recvParkInfo(AJsonData) {
    //console.log("recvParkInfo: " + AJsonData.length + " EA.");
    _mapManager.makeLayer(LayerIndex.Park, AJsonData);
}

// BIT
// function recvBitInfo(AJsonData) {
//     console.log("recvBitInfo: " + AJsonData.length + " EA.");
//     _mapManager.makeLayer(LayerIndex.Bit, AJsonData);
// }

// function recvBitSttsInfo(AJsonData) {
//     let stts = new FcltStts();
//     const lyrInfo = _mapManager.getLayer(LayerIndex.Bit);
//     if (lyrInfo == null) {
//         return stts;
//     }
//     AJsonData.forEach((el, idx) => {
//         const obj = lyrInfo.findObject(el.fclt_id);
//         if (obj) {
//             stts.total++;
//             const sttsCd = el.stts_cd.slice(-1);
//             if (Number(sttsCd) == 0) {
//                 stts.normal++;
//             }
//             obj.updateStts(el.stts_cd, el.updt_dt);
//         }
//     });
//     stts.error = stts.total - stts.normal;
//     console.log(`${currDt()} recvBitSttsInfo: ${AJsonData.length} EA.`);

    // 시설물 상태정보 요청 타이머 설정
    //_timerLoadingFcltStts = window.setTimeout(function() {
    //  loadingFcltStts();
    //}, (60 * 1000));
//     return stts;
// }


window.selectLink = function selectLink(linkId) {
    const map = _mapManager.getInfo();
    let lyrIdx = LayerIndex.Link2;
    let zoom = map.zoom;
    if (map.zoom == 16) {
        lyrIdx = LayerIndex.Link1;
    }
    else if (map.zoom >= 17) {
        lyrIdx = LayerIndex.Link2;
    }
    else {
        zoom = 17;
        lyrIdx = LayerIndex.Link2;
    }
    _mapManager.selectLayerObject(lyrIdx, linkId, zoom);
}