let _size  = [48, 48, 48, 48, 40, 32, 24, 22, 20, 18, 18,],
    _Map = null,
    _SelectedObj = null,
    _CctvArray = [],
    _CctvFlag = false,
    _CctvListFlag = false,
    _IntersectionArray = [],
    _IntersectionFlag = false,
    _IntersectionListFlag = false,
    _IntersectionCameraArray = [],
    _AtrdArray = [],
    _AtrdData = [],
    _AtrdMap = new Map(),
    _VmsArray = [],
    _VmsFlag = false,
    _VmsListFlag = false,
    _IncidentArray = [],
    _IncidentFlag = false,
    _IncidentListFlag = false,
    _TrafficArray  = [],
    _TrafficFlag = false,
    _TrafficListFlag = false,
    selectIncidentId = null,
    _ParkingArray = [],
    _ParkingFlag  = false,
    _ParkingListFlag = false;

const g_color = new Map();
g_color.set('LTC0', '#888888;');
g_color.set('LTC1', '#2fba2c;');
g_color.set('LTC2', '#ffc500;');
g_color.set('LTC3', '#ee0000;');

$(()=>{
    /**
     * 카카오 맵 생성
     * @type {HTMLElement}
     */
    const container = document.getElementById('map'); //지도를 담을 영역의 DOM 레퍼런스
    const options = { //지도를 생성할 때 필요한 기본 옵션
        center: new kakao.maps.LatLng(36.0191816, 129.3432983), //지도의 중심좌표.
        level: 6,
        maxLevel: 9,
        minLevel: 1,
        disableDoubleClickZoom: true
    };
    _Map = new kakao.maps.Map(container, options);
    const mapTypeControl = new kakao.maps.MapTypeControl();
    _Map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
    const zoomControl = new kakao.maps.ZoomControl();
    _Map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);

    /**
     * Map Zoom Level Change 이벤트
     */
    kakao.maps.event.addListener(_Map, 'zoom_changed', function () {
        markerSizeChangeWithZoomLevel(_CctvArray, _CctvFlag);
        markerSizeChangeWithZoomLevel(_VmsArray, _VmsFlag);
        markerSizeChangeWithZoomLevel(_ParkingArray, _ParkingFlag);
        markerSizeChangeWithZoomLevel(_IncidentArray, _IncidentFlag);
        intersectionMarkerChangeWithZoomLevel();
        intersectionCameraChangeWidthZoomLevel();
        if (_AtrdArray.length > 0) {
            atrdMarkerResize();
        }
        getVertex();
    });

    kakao.maps.event.addListener(_Map, 'dragend', function() {
        getVertex();
    })

    function atrdMarkerResize() {
        let size = 48;
        let level = _Map.getLevel();
        if (level >= 7) {
            size = 24;
        }

        _AtrdArray.forEach((atrd)=>{
           const imageSize = new kakao.maps.Size(size, size);
            const imageSrc  = '/images/icon/atrd' + atrd.obj.drct_cd +'.png';
            const imageOption = {
                offset: new kakao.maps.Point(size/2, size),
            };
            const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
            atrd.marker.setImage(markerImage);
        })

        if (level === 3) {
            level = 4;
        }
        if (level >= 8) {
            level = 7;
        }
        else if (level >= 6) {
            level = 6;
        }
        const atrdInfo = _AtrdMap.get(level.toString());
        if (atrdInfo) {
            _AtrdData = [];
            let upHillArr = [];
            let downHillArr = [];
            const $selectedLi = $(".left-list-area .list-content.list > li.click");
            let id;
            let idArr;
            if ($selectedLi[0]) {
                id = $selectedLi.attr('id');
            }
            if (id) {
                idArr = id.split("_");
            }
            atrdInfo.forEach((atrd)=>{
                if (atrd.atrd_id === idArr[1] || atrd.atrd_id == idArr[2]) {
                    _AtrdData.push(atrd);

                    if (atrd.atrd_id === idArr[1]) {
                        upHillArr.push(atrd);
                    }
                    else {
                        downHillArr.push(atrd);
                    }
                }
            })
            if (upHillArr[0]) {
                let upHillX = upHillArr[0].x_crdn_arr.split(',')[0];
                let upHillY = upHillArr[0].y_crdn_arr.split(',')[0];
                _AtrdArray[0].marker.setPosition(new kakao.maps.LatLng(upHillY, upHillX));
            }

            if (downHillArr[0]) {
                let downHillX = downHillArr[0].x_crdn_arr.split(',')[0];
                let downHillY = downHillArr[0].y_crdn_arr.split(',')[0];
                _AtrdArray[1].marker.setPosition(new kakao.maps.LatLng(downHillY, downHillX));
            }
        }
    }

    /**
     * 스마트교차로 카메라 레벨별 이미지 보이기 감추기
     */
    function intersectionCameraChangeWidthZoomLevel() {
        const level = _Map.getLevel();
        const size = [48, 48, 48]
        const levelSize = size[level];;
        if (_IntersectionCameraArray.length > 0) {
            _IntersectionCameraArray.forEach((obj) => {
                const content = $('<div title='+obj.NAME+'>');
                content.css(
                    {
                        width: levelSize+ 'px',
                        height: levelSize+ 'px',
                        backgroundImage:'url(/images/icon/intersection-cctv.png)',
                        backgroundSize : levelSize+'px '+levelSize+'px',
                        backgroundRepeat: 'no-repeat',
                        backgroundPosition : 'center',
                        transform : 'rotate(' + obj.obj.cmra_angn +'deg)',
                        cursor    : 'pointer'
                    });

                obj.marker.setContent(content[0]);
                content.on('click', ()=> {
                    obj.click();
                });

                if (level <= 2 && _IntersectionFlag) {
                    obj.marker.setMap(_Map);
                    obj.polyline.setMap(_Map);
                } else {
                    obj.marker.setMap(null);
                    obj.polyline.setMap(null);
                }
            })
        }
    }

    /**
     * 스마트교차로 레벨별 이미지 보이기 감추기
     */
    function intersectionMarkerChangeWithZoomLevel() {
        const level = _Map.getLevel();
        if (_IntersectionArray.length > 0) {
            _IntersectionArray.forEach((obj)=>{
                setMarkerImage(obj, "");
                if (level > 2 && _IntersectionFlag) {
                    obj.marker.setVisible(true);
                }
                else {
                    obj.marker.setVisible(false);
                }
            })
        }
    }

    /**
     * 맵 레벨별 이미지 변환
     * @param array
     */
    function markerSizeChangeWithZoomLevel(array) {
        if (array && array.length > 0) {
            array.forEach((obj)=>{
                if (obj.isClick) {
                    setMarkerImage(obj, 2)
                }
                else {
                    setMarkerImage(obj, 1);
                }
            });
        }
    }

    /**
     * 범례 클릭 색 변환
     * */
    $('.legend-bottom button').on('click', function (){
        const target     = $(this);
        const legendIcon = target.children().eq(0);
        const legendText = target.children().eq(1).text();
        const isShow     = !legendIcon.hasClass('active');
        switch (legendText) {
            case 'CCTV' :
                onOffFacility(_CctvArray, isShow, legendIcon, target, null);
                _CctvFlag = isShow;
                break;
            case '스마트교차로':
                onOffFacility(_IntersectionArray, isShow, legendIcon, target, _IntersectionCameraArray);
                _IntersectionFlag = isShow;
                break;
            case '도로전광판':
                onOffFacility(_VmsArray, isShow, legendIcon, target, null);
                _VmsFlag = isShow;
                break;
            case '돌발정보':
                onOffFacility(_IncidentArray, isShow, legendIcon, target, null);
                _IncidentFlag = isShow;
                break;
            case '소통정보':
                onOffFacility(_TrafficArray, isShow, legendIcon, target, _AtrdArray);
                _TrafficFlag = isShow;
                break;
            case '주차정보':
                onOffFacility(_ParkingArray, isShow, legendIcon, target, null);
                _ParkingFlag = isShow;
                break;
        }
    })

    /**
     * 범례 호버 색 변환
     * */
    $('.legend-bottom ul li').hover((event)=>{
        const iconDiv = $(event.currentTarget).children().eq(0);
        if (!iconDiv.hasClass('active')) {
            iconDiv.children().eq(0).addClass('hover');
        }
        else {
            if (iconDiv.children().eq(0).hasClass('hover')) {
                iconDiv.children().eq(0).removeClass('hover');
            }
        }
    }, (event)=>{
        const iconDiv = $(event.currentTarget).children().eq(0);
        if (!iconDiv.hasClass('active')) {
            iconDiv.children().eq(0).removeClass('hover');
        }
        else {
            if (iconDiv.children().eq(0).hasClass('hover')) {
                iconDiv.children().eq(0).removeClass('hover');
            }
        }
    });

    /**
     * 탭 호버 색 변환
     * */
    $('.left-list-area .list-tab > li').hover((event)=>{
        const iconDiv = $(event.currentTarget);
        if (!iconDiv.hasClass('active')) {
            iconDiv.children().eq(0).addClass('hover');
        }
        else {
            if (iconDiv.children().eq(0).hasClass('hover')) {
                iconDiv.children().eq(0).removeClass('hover');
            }
        }
    }, (event)=>{
        const iconDiv = $(event.currentTarget);
        if (!iconDiv.hasClass('active')) {
            iconDiv.children().eq(0).removeClass('hover');
        }
        else {
            if (iconDiv.children().eq(0).hasClass('hover')) {
                iconDiv.children().eq(0).removeClass('hover');
            }
        }
    });

    initFaicilityData();
    getVertex();
    let _MakerArr = [];
    $('.tab-title > div').on('click', function(){
        let searchType = $('.tab-title > div.active').text();
        if (searchType === $(this).text()) return;
        $('.tab-title > div').toggleClass("active");
        searchType = $(this).text();
        let list;
        let spot;
        if (searchType === '지점 검색') {
            list = 'none';
            spot = 'block';
            $('.list-content.spot').html("");
        }
        else {
            list = 'block';
            spot = 'none';
            $('.list-content.list > li').css('display', 'block');
        }

        $('#search-box').val("");
        $('.list-content.list').css('display', list);
        $('.list-content.spot').css('display', spot);
        if (_MakerArr.length > 0) {
            _MakerArr.forEach((obj)=>{
                obj.setMap(null);
            });
            _MakerArr = [];
        }
    })


    $('#search-box').on('keyup', function () {
        const searchType = $('.tab-title > div.active').text();
        const searchText = $(this).val();

        if (searchType === '리스트') {
            const $list = $('.list-content.list > li');
            if (!$list.length) return;

            for (let ii = 0; ii < $list.length; ii++) {
                const li = $list.eq(ii);
                if ($(this).val().length === 0) {
                    li.css('display', 'block');
                }
                else {
                    let text = $('.list-content.list > li').eq(ii).text().toLowerCase();
                    if (text.includes(searchText.toLowerCase())) {
                        li.css('display', 'block');
                    }
                    else {
                        li.css('display', 'none');
                    }
                }
            }
        }
        else {
            if (_MakerArr.length > 0) {
                _MakerArr.forEach((obj)=>{
                    obj.setMap(null);
                });
                _MakerArr = [];
            }
            $('.list-content.spot').html("");
            if (!searchText || !searchText.trim()) return;
            $.ajax({
                url: 'https://dapi.kakao.com/v2/local/search/address.json',
                headers: { 'Authorization': 'KakaoAK 4896b94398b96949d349881d004835cf'},
                data :{
                    query : searchText,
                },
                type: 'GET'
            }).done(function(data) {
                if (data && data.documents.length > 0) {
                    let str = "";
                    const setMap = new Map();

                    const bounds = new daum.maps.LatLngBounds();
                    let minX;
                    let minY;
                    let maxX;
                    let maxY;
                    let idx = 0;
                    data.documents.forEach((obj)=>{
                        if (!setMap.get(obj.address_name) && obj.address_name.includes("경북 포항시")) {
                            idx++;
                            let addr = obj.address_name;
                            if (obj.x && obj.y) {
                                const position = new kakao.maps.LatLng(obj.y, obj.x);
                                let marker = new kakao.maps.Marker({
                                    position : position,
                                    title : addr ,
                                    content : addr
                                });

                                new kakao.maps.event.addListener(marker, 'click', function() {
                                    moveLocation(obj.x, obj.y, idx);
                                })
                                if (!minX) {
                                    minX = obj.x;
                                }

                                if (!maxX) {
                                    maxX = obj.x;
                                }
                                if (!minY) {
                                    minY = obj.y;
                                }

                                if (!maxY) {
                                    maxY = obj.y;
                                }

                                minX = minX <= obj.x ? minX : obj.x;
                                maxX = maxX >= obj.x ? maxX : obj.x;
                                minY = minY <= obj.y ? minY : obj.y;
                                maxY = maxY >= obj.y ? maxY : obj.y;

                                marker.setMap(_Map);
                                _MakerArr.push(marker);
                                setMap.set(addr, obj);

                                str+= `<li id="spot-${idx}" onclick="moveLocation(${obj.x}, ${obj.y}, ${idx})">
                                            ${obj.address_name}
                                       </li>`;
                            }
                        }
                    });

                    if (minX && minY && maxX && maxY) {
                        bounds.extend(new daum.maps.LatLng(minY, minX));
                        bounds.extend(new daum.maps.LatLng(maxY, maxX));
                        _Map.setBounds(bounds);
                        $('.list-content.spot').html(str);
                        getVertex();
                    }
                }
            });
        }
    })
});

function moveLocation(xCoordinate, yCoordinate, listIndex) {
    const position = new kakao.maps.LatLng(yCoordinate, xCoordinate);

    _Map.setCenter(position);
    _Map.setLevel(3);
    $('.list-content.spot > li.click').removeClass('click');
    $('#spot-' +listIndex).addClass('click');
    getVertex();
}

function getVertex() {
    if (_TrafficArray.length > 0) {
        _TrafficArray.forEach((obj) => {
            obj.setVisibleMarker(false);
            if (obj.infoWindow) {
                obj.infoWindow.setMap(null);
            }
        })
        _TrafficArray = [];
    }

    let level = _Map.getLevel();
    const bounds = _Map.getBounds();
    const swLatLng = bounds.getSouthWest();
    const neLatLng = bounds.getNorthEast();
    const data = {
        levl : level,
        swLat : swLatLng.getLat(),
        neLat : neLatLng.getLat(),
        swLng : swLatLng.getLng(),
        neLng : neLatLng.getLng(),
    }

    getDataAsync('/api/traffic/vertex-list', 'POST', data, null, (jsonData)=>{
        if (jsonData && jsonData.length > 0) {
            jsonData.forEach((obj)=>{
                const trafficObj = new TrafficObj(obj);
                if (_AtrdData.length > 0) {
                    _AtrdData.forEach((atrd)=>{
                        if (atrd.road_id.toString() === trafficObj.ID.toString()) {
                            trafficObj.polyBackLine.setOptions({
                                    strokeColor : 'black',
                            });
                        }
                    })
                }
                _TrafficArray.push(trafficObj);
            })
        }
    })
}

function initFaicilityData() {
    getDataAsync('/api/traffic/cctv-list', 'POST', null, null, (jsonData)=>{
        if (jsonData && jsonData.length > 0) {
            _CctvArray = receiveFacilityData(jsonData, _CctvArray, TbCCtvObj, _CctvListFlag, 'cctv');
        }
    }, null);

    getDataAsync('/api/traffic/vms-list', 'POST', null, null, (jsonData)=>{
        if (jsonData && jsonData.length > 0) {
            jsonData.sort((a, b)=>{
                return a.vms_nm > b.vms_nm ? 1 : a.vms_nm < b.vms_nm ? -1 : 0;
            })
            _VmsArray = receiveFacilityData(jsonData, _VmsArray, TbVmsObj, _VmsListFlag, 'vms');
        }
    }, null);

    getDataAsync('/api/traffic/incd-list', 'POST', null, null, (jsonData)=>{
        if (jsonData && jsonData.length > 0) {
            _IncidentArray = receiveFacilityData(jsonData, _IncidentArray, TbIncdObj, _IncidentListFlag, 'incident');
            if (selectIncidentId) {
                _IncidentArray.forEach((incd)=>{
                    if (incd.ID === selectIncidentId) {
                        incd.click();
                    }
                })
            }
        }
    }, null);

    getDataAsync('/api/itcs/list', 'POST', null, null, (jsonData)=>{
        if (jsonData && jsonData.length > 0) {
            jsonData.sort((a, b)=>{
                return a.ixr_nm > b.ixr_nm ? 1 : a.ixr_nm < b.ixr_nm ? -1 : 0;
            });
            let data = [];
            jsonData.forEach((obj)=>{
                if(obj.detail.length > 0) {
                    data.push(obj);
                }
            })
            _IntersectionArray = receiveFacilityData(data, _IntersectionArray, IntersectionObj, _IntersectionListFlag, 'intersection');
        }
    }, null);

    if (_TrafficListFlag) {
        getDataAsync("/api/traffic/atrd-vertex-all", "POST", null, null, (jsonData)=>{
            if (jsonData && jsonData.length > 0) {
                _AtrdMap = new Map();
                jsonData.forEach((obj)=>{
                    _AtrdMap.set(obj.level, obj.list);
                });
            }
        }, null);

        getDataAsync('/api/traffic/atrd-list', 'POST', null, null, (jsonData)=>{
            if (jsonData) {
                let listStr = "";
                let mobileStr = "";
                let atrdData = [];

                for (let key in jsonData){
                    atrdData.push({
                        name : key,
                        list : jsonData[key]
                    });
                }

                atrdData.sort((a,b)=>{
                    return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
                });

                atrdData.forEach((obj)=>{
                    let upHillId = null;
                    let downHillId = null;
                    const list = obj.list;
                    if (list && list.length === 2) {
                        upHillId   = list[0].atrd_id;
                        downHillId = list[1].atrd_id;

                        if (list[0].drct_cd === "1") {
                            upHillId   = list[1].atrd_id;
                            downHillId = list[0].atrd_id;
                        }
                    }
                    listStr += `<li id="atrd_${upHillId}_${downHillId}" onclick="atrdClickEvent('${upHillId}', '${downHillId}')">${obj.name}</li>`
                    mobileStr += `<option value="${upHillId}_${downHillId}">${obj.name}</option>`
                });

                const $mobileSelect = $('.mobile-select');
                $mobileSelect.append($(mobileStr));
                $mobileSelect.on('change', function(){
                    const ids = $(this).val();
                    if (ids && ids !== '-') {
                        const idArr = ids.split('_');
                        atrdClickEvent(idArr[0], idArr[1]);
                    }
                    else {
                        if (_AtrdArray.length > 0) {
                            _AtrdArray.forEach((atrd)=>{
                                atrd.close();
                            })
                            _AtrdData = [];
                            getVertex();
                        }
                    }
                })
                const listSection = $('.left-list-area .list-content.list');
                listSection.empty();
                listSection.html(listStr);
            }
        });
    }
}

/**
 * 간선도로 클릭 이벤트
 * @param AupHillId 상행 ID
 * @param AdownHillId 하행 ID
 */
function atrdClickEvent(AupHillId, AdownHillId) {
    if (_AtrdArray.length > 0) {
        _AtrdArray.forEach((atrd)=>{
            atrd.close();
        });
        _AtrdArray = [];
    }
    _AtrdData = [];
    const $selectedLi = $('.left-list-area .list-content.list > li.click');
    if ($selectedLi) {
        $selectedLi.removeClass('click');
    }
    const $selectLi = $('#atrd_' + AupHillId  + "_" + AdownHillId);
    $selectLi.addClass('click');
    $selectLi.focus();

    //상행, 하행 ID 가 있다면 실행
    if (AupHillId && AdownHillId) {
        const upHillArr = [];
        const downHillArr = [];
        const bounds = new daum.maps.LatLngBounds();

        //전체 간선도로 목록을 담은 Map 에서 기준값을 5레벨로 잡아 포커스 좌표를 설정
        if (_AtrdMap.get("5")) {
            const basicAtrd = _AtrdMap.get("5");
            for (let idx in basicAtrd) {
                const obj = basicAtrd[idx];
                if(obj.atrd_id == AupHillId || obj.atrd_id == AdownHillId) {
                    bounds.extend(new daum.maps.LatLng(obj.y_crdn_min, obj.x_crdn_min));
                    bounds.extend(new daum.maps.LatLng(obj.y_crdn_max, obj.x_crdn_max));
                }
            }
            _Map.setBounds(bounds);

            //전체 레벨이 다있는게 아니므로 로드 레벨은 재설정
            let level = _Map.getLevel();
            if (level >= 8) {
                level = 7;
            }
            else if (level >= 6) {
                level = 6;
            }

            /**
             * 범위를 포커스 하게 되면 레벨이 변경되므로 변경 된 레벨의 간선도로 목록에서
             * 상행, 하행 ID가 포함된 데이터 갖고오며 상행, 하행 데이터 따로 구분
             */
            const atrdInfo = _AtrdMap.get(level.toString());
            if (atrdInfo) {
                atrdInfo.forEach((atrd)=>{
                    if (atrd.atrd_id === AupHillId || atrd.atrd_id == AdownHillId) {
                        _AtrdData.push(atrd);

                        if (atrd.atrd_id === AupHillId) {
                            upHillArr.push(atrd);
                        }
                        else {
                            downHillArr.push(atrd);
                        }
                    }
                })
            }
            //레벨이 변경됐으므로 다시한번 버텍스를 초기화해준다
            getVertex();

            //각 상행 하행의 첫번째 좌표를 가지고 상행, 하행 아이콘을 생성 하며 객체는 array에 보관해둠
            if (upHillArr[0]) {
                const upHillObj = new TbAtrdObj(upHillArr[0]);
                _AtrdArray.push(upHillObj);
            }

            if (downHillArr[0]) {
                const downHillObj = new TbAtrdObj(downHillArr[0]);
                _AtrdArray.push(downHillObj);
            }
        }
    }
}

/**
 * 간선도로 상,하행 마커 그리기
 * @param src 상, 하행 코드
 * @param lat X 좌표
 * @param lng Y 좌표
 * @param name 명칭
 * @returns {daum.maps.Marker} 생성 마커
 */
function drawAtrdMakrer(src, lng, lat, name) {
    let imageSize;
    let imageOption;
    let imageSrc = '/images/icon/atrd' + src + '.png';

    //레벨별 사이즈를 다르게 표출
    const level = _Map.getLevel();
    let size = 48;
    if (level >= 7) {
        size = 24;
    }

    imageSize = new daum.maps.Size(size, size);
    imageOption = {
        offset: new daum.maps.Point(size/2, size),
    };

    let markerImage = new daum.maps.MarkerImage(imageSrc, imageSize, imageOption);
    let markerPosition = new daum.maps.LatLng(lng, lat);

    let atrdSideMarker = new daum.maps.Marker({
                               position: markerPosition,
                               image: markerImage,
                               zIndex: 5,
                               title: name,
                            });
    return atrdSideMarker;
}

/**
 * 소통정보 Object
 */
class TrafficObj {
    constructor(obj) {
        this.ID = obj.roadway_id;
        this.NAME = obj.roadway_nm;
        this.obj = obj;
        this.infoWindow = null;
        this.polyLine = null;
        this.polyBackLine = null;
        this.init();
    }
    
    init() {
        const _self = this;
        const trafficObj = this.obj;
        const xArray = trafficObj.x_crdn.split(",");
        const yArray = trafficObj.y_crdn.split(",");
        const linePath = [];
        for (let ii = 0; ii < xArray.length; ii++) {
            const x_crdn = Number(xArray[ii]);
            const y_crdn = Number(yArray[ii]);
            const coordinates = new kakao.maps.LatLng(y_crdn, x_crdn);
            linePath.push(coordinates);
        }

        let strokeWeight = 5;
        let strokeWeightBack = 7;
        const level = _Map.getLevel();

        if (level == 3) {
            strokeWeightBack = 6;
        } else if (level == 5 || level == 4) {
            strokeWeight = 3;
            strokeWeightBack = 5;
        } else if (level >= 6) {
            strokeWeight = 2;
            strokeWeightBack = 4;
        }
        this.polyBackLine = new daum.maps.Polyline({
                path: linePath, // 선을 구성하는 좌표배열 입니다
                strokeWeight: strokeWeightBack, // 선의 두께 입니다
                strokeColor: '#eeeeee', // 선의 색깔입니다
                strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
                strokeStyle: 'solid', // 선의 스타일입니다
                zIndex: 1
            });
        this.polyLine = new daum.maps.Polyline({
            path: linePath, // 선을 구성하는 좌표배열 입니다
            strokeWeight: strokeWeight, // 선의 두께 입니다
            strokeColor: g_color.get(trafficObj.cmtr_grad_cd), // 선의 색깔입니다
            strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
            strokeStyle: 'solid', // 선의 스타일입니다
            zIndex: 2
        });

        this.setVisibleMarker(_TrafficFlag);

        daum.maps.event.addListener(this.polyLine, 'mouseover', function (event) {

            this.setOptions({strokeColor: '#0000FF'});
            const iwContent =
                `<div class="trafficPop">
                            <div class="traffic-speed ${trafficObj.cmtr_grad_cd}">
                                <span class="traffic-name">${_self.NAME}</span>
                                <span class="traffic-speed-info border-back ${trafficObj.cmtr_grad_cd}">${trafficObj.grad_nm}</span>
                            </div>
                            <div class="traffic-info">
                                <span>${trafficObj.strt_nm_node} → ${trafficObj.end_nm_node}</span>
                                <br>
                                <span>소요시간 : </span>
                                <span class="${trafficObj.cmtr_grad_cd}">약 ${textFormat(trafficObj.trvl_hh)}분 </span>
                                <span>&nbsp; 속도 : </span>
                                <span class="${trafficObj.cmtr_grad_cd}">약 ${textFormat(trafficObj.sped)}km/h</span>
                            </div>
                         </div>`;
            _self.infoWindow = new daum.maps.CustomOverlay({
                map: _Map,
                clickable: true,
                position: event.latLng,
                content: iwContent,
                xAnchor: -0.1,
                yAnchor: 1.1,
                zIndex: 4
            });

        });

        daum.maps.event.addListener(this.polyLine, 'mouseout', function () {
            this.setOptions({strokeColor:  g_color.get(trafficObj.cmtr_grad_cd)});
            if (_self.infoWindow != null) _self.infoWindow.setMap(null);
        });
    }

    setVisibleMarker(isVisible) {
        const isShow = isVisible ? _Map : null;
        this.polyBackLine.setMap(isShow);
        this.polyLine.setMap(isShow);
    }
}

/**
 * 간선도로 Object
 */
class TbAtrdObj {
    constructor(obj) {
        this.ID = obj.atrd_id;
        this.NAME = obj.atrd_nm;
        this.X_CRDN = null;
        this.Y_CRDN = null;
        this.obj = obj;
        this.marker = null;
        this.imgSrc = '/images/icon/atrd';
        this.isClick = false;
        this.init();
    }

    init() {
        if (this.obj.x_crdn_arr) {
            this.X_CRDN = this.obj.x_crdn_arr.split(",")[0];
        }

        if (this.obj.y_crdn_arr) {
            this.Y_CRDN = this.obj.y_crdn_arr.split(",")[0];
        }
        const name = this.NAME + " [" + this.obj.drct_nm + "]";
        this.marker = drawAtrdMakrer(this.obj.drct_cd, this.Y_CRDN, this.X_CRDN, name);
        this.click();
    }

    click() {
        this.setVisibleMarker(true);
    }

    setVisibleMarker(isVisible) {
        let visible = isVisible ? _Map : null;
        this.marker.setMap(visible);
        this.isClick = isVisible;
    }

    close() {
        this.setVisibleMarker(false);
    }
}

/**
 * CCTV Object
 */
class TbCCtvObj {
    constructor(obj) {
        this.ID = obj.cctv_mngm_nmbr;
        this.NAME = obj.istl_lctn_nm;
        this.X_CRDN = obj.x_crdn;
        this.Y_CRDN = obj.y_crdn;
        this.obj = obj;
        this.marker = null;
        this.infoWindow = null;
        this.isClick = false;
        this.imgSrc = '/images/icon/cctv';
        this.timer = null;
    }

    init() {
        this.marker = markerInit(this, _CctvFlag);
    }

    setVisibleMarker(isVisible) {
        this.marker.setVisible(isVisible);
    }

    click() {
        const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));

        if (_SelectedObj != null) {
            if (_SelectedObj === this) {
                return;
            }
            _SelectedObj.close();
        }
        _SelectedObj = this;

        const selectedLi = $('#cctv-' + this.ID);
        selectedLi.addClass('click');
        selectedLi.focus();

        _Map.setCenter(coordinates);
        const iwContent =
            `<div class="cctv-info-window">
                    <div class="title">
                        <div class="cctv-name-${this.ID}">${this.NAME}</div>
                        <div onclick="infoWindowEvent('cctv', '${this.ID}', 'close')">X</div>
                    </div>
                    <div class="content">
                        <div>
                            <video id="video-${this.ID}" class="video-js" playsinline style="width: 100%; height: 100%;"></video>
                        </div>
                        <div>
                            <div>※ CCTV영상은 30초간 제공됩니다.</div>
                            <div class="continue-play">계속재생</div>
                        </div>
                    </div>
                </div>`;
        $('body').append($(iwContent));
        this.infoWindow = $('.cctv-info-window');
        let position = getInfoWidowPosition(this.infoWindow);
        let top = position[0];
        let left = position[1];
        this.infoWindow.css({
            top : top + 'px',
            left : left + 'px',
            position : 'absolute'
        });
        this.infoWindow.draggable({containment : 'body', handle: '.cctv-name-'+this.ID});
        // this.infoWindow = new kakao.maps.CustomOverlay({position: coordinates, content: iwContent, zindex: 15, yAnchor: 1.1});
        // this.infoWindow.setMap(_Map);
        let video = videojs("video-" + this.ID, {
            sources: [
                {
                    src: this.obj.strm_http_addr,
                    type: "application/x-mpegURL",
                    crossorigin: "anonymous",
                },
            ],
            responsive: false,
            autoplay: true,
            muted: true,
            preload: "metadata",
        });

        video.on('error', ()=>{
            if (video.error().code === 4) {
                video.pause();
                video.dispose();
                if (this.timer) {
                    clearTimeout(this.timer);
                }
                $('.content > div:nth-child(1)').append($('<img src="/images/icon/error.png">'));
                $('.content > div:nth-child(1)').css({
                    display : 'flex',
                    alignItems : 'center',
                    justifyContent : 'center',
                });
                video = null;
            }
        })

        this.timer = setTimeout(()=>{
            if (video) {
                video.pause();
            }
        }, 30000);

        let cctvObj = this;
        $('.continue-play').on('click', ()=>{
            if (cctvObj.timer) {
                setTimeout(cctvObj.timer);
            }
            if (video) {
                video.play();
                cctvObj.timer = setTimeout(()=>{
                    video.pause();
                }, 30000);
            }
        });
        setMarkerImage(this, 2);
        this.isClick = true;
        moveToScroll(_CctvListFlag, _CctvArray, this.ID);
    }


    close() {
        this.isClick = false;
        _SelectedObj     = null;
        setMarkerImage(this, 1);
        let oldPlayer    = document.getElementById("video-" + this.ID);
        let selectedLi   = $("#cctv-" + this.ID);
        if (selectedLi.hasClass('click')) {
            selectedLi.removeClass('click');
        }
        if (_CctvListFlag) {
            $('.mobile-select').val("-");
        }
        if (oldPlayer) {
            videojs(oldPlayer).dispose();
        }
        if (this.infoWindow) {
            this.infoWindow.remove();
            // this.infoWindow.setMap(null);
            this.infoWindow = null;
        }
        if (this.timer) {
            clearTimeout(this.timer);
        }
    }
}
/**
 * Parking Object
 */
class TbParkingObj {
    constructor(obj) {
        this.ID = obj.park_id;
        this.NAME = obj.park_nm;
        this.X_CRDN = obj.x_crdn;
        this.Y_CRDN = obj.y_crdn;
        this.obj = obj;
        this.marker = null;
        this.infoWindow = null;
        this.isClick = false;
        this.imgSrc = '/images/icon/parking';
        this.timer = null;
    }

    init() {
        this.marker = markerInit(this, _ParkingFlag);
    }

    setVisibleMarker(isVisible) {
        this.marker.setVisible(isVisible);
    }

    click() {
        const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));

        if (_SelectedObj != null) {
            if (_SelectedObj === this) {
                return;
            }
            _SelectedObj.close();
        }
        _SelectedObj = this;

        const selectedLi = $('#parking-' + this.ID);
        selectedLi.addClass('click');
        selectedLi.focus();

        _Map.setCenter(coordinates);
        const iwContent =
            `<div class="parking-info-window">
                    <div class="title">
                        <div class="parking-name-${this.ID}">${this.NAME}</div>
                        <div onclick="infoWindowEvent('parking', '${this.ID}', 'close')"></div>
                    </div>
                    <div class="content">
                        <div>주차장정보</div>
                        <div>
                            <div>주차면수</div>
                            <div>${this.obj.park_num}대</div>
                        </div>
                        <div>
                            <div>구분</div>
                            <div>${this.obj.park_type}대</div>
                        </div>
                        <div>
                            <div>기본요금</div>
                            <div>${this.obj.park_fee_type}</div>
                        </div>
                        <div>
                            <div>주소</div>
                            <div>${this.obj.addr}</div>
                        </div>
                    </div>
                </div>`;
        $('body').append($(iwContent));
        this.infoWindow = $('.parking-info-window');
        let position = getInfoWidowPosition(this.infoWindow);
        let top = position[0];
        let left = position[1];
        this.infoWindow.css({
            top : top + 'px',
            left : left + 'px',
        });
        this.infoWindow.draggable({containment : 'body', handle: '.cctv-name-'+this.ID});
        let parkingObj = this;
        setMarkerImage(this, 2);
        this.isClick = true;
        moveToScroll(_ParkingListFlag, _ParkingArray, this.ID);
    }


    close() {
        this.isClick = false;
        _SelectedObj     = null;
        setMarkerImage(this, 1);
        let selectedLi   = $("#parking-" + this.ID);
        if (selectedLi.hasClass('click')) {
            selectedLi.removeClass('click');
        }

        if (_ParkingListFlag) {
            $('.mobile-select').val("-");
        }

        if (this.infoWindow) {
            this.infoWindow.remove();
            this.infoWindow = null;
        }
    }
}

/**
 * VMS Object
 */
class TbVmsObj {
    constructor(obj) {
        this.ID = obj.vms_ctlr_nmbr;
        this.NAME = obj.vms_nm;
        this.X_CRDN = obj.x_crdn;
        this.Y_CRDN = obj.y_crdn;
        this.obj    = obj;
        this.marker = null;
        this.infoWindow = null;
        this.isClick = false;
        this.imgSrc = '/images/icon/vms';
        this.timer = null;
    }

    init() {
        this.marker = markerInit(this, _VmsFlag);
    }

    setVisibleMarker(isVisible) {
        this.marker.setVisible(isVisible);
    }

    click() {
        if (_SelectedObj != null) {
            if (_SelectedObj === this) {
                return;
            }
            _SelectedObj.close();
        }
        _SelectedObj = this;
        const selectedLi = $('#vms-' + this.ID);
        selectedLi.addClass('click');
        selectedLi.focus();
        const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
        _Map.setCenter(coordinates);
        let phaseArray = [];
        let width;
        let height;
        let isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
        switch (this.obj.vms_type_cd) {
            case 'VMC1':
                width  = 400;
                height = 64;

                break;
            case 'VMC2':
                width  = 384;
                height = 64;
                break;
            case 'VMC3':
                width  = 288;
                height = 160;
                break;
            case 'VMC4':
                width  = 256;
                height = 192;
                break;
        }
        const windowHeight = $(window).height();
        if (isMobile || windowHeight < 900) {
            width = width/2;
            height = height/2;
        }
        width = width +'px';
        height = height + 'px';

        const msg = this.obj.msg;

        if (!msg || msg.length === 0) {
            width = '256px';
            height = '50px';
        }

        let iwContent =
            `<div class="vms-info-window" style="width: calc(${width} + 10px); height: calc(${height} + 50px);">
                    <div class="title">
                        <div class="vms-name-${this.ID}">${this.NAME}</div>
                        <div onclick="infoWindowEvent('vms', ${this.ID}, 'close')">X</div>
                    </div>
                    <div class="content" style="width: ${width}; height: ${height};">`;
                    if (msg && msg.length > 0) {
                        for (let idx in msg) {
                            let msgObj = msg[idx];
                            let className = '';
                            if (idx === "0") {
                                className = 'active'
                            }
                            iwContent += `<img id="phase-${msgObj.phase}" class="${className}" style="width: ${width}; height: ${height};" src="/api/traffic/vms-dspl-image/${this.ID}/${msgObj.phase}">`;
                            phaseArray.push(msgObj.phase);
                        }
                    }
                    else {
                        iwContent += '표출 이미지 데이터가 없습니다.';
                    }
        iwContent += `</div></div>`;
        // this.infoWindow = new kakao.maps.CustomOverlay({position: coordinates, content: iwContent, zindex: 15, yAnchor: 1.2});
        $('body').append($(iwContent));

        this.infoWindow = $('.vms-info-window');
        let position = getInfoWidowPosition(this.infoWindow);
        let top = position[0];
        let left = position[1];

        this.infoWindow.css({
            top : top + 'px',
            left : left + 'px',
            position: 'absolute',
            zIndex : '999',
        })
        this.infoWindow.draggable({containment : 'body', handle: '.vms-name-'+this.ID});
        // this.infoWindow.setMap(_Map);
        setMarkerImage(this, 2)

        this.isClick = true;
        moveToScroll(_VmsListFlag, _VmsArray, this.ID);

        let cnt = 1;
        this.timer = setInterval(()=>{
            if (phaseArray.length > 0) {
                if (cnt === phaseArray.length) {
                    cnt = 0;
                }
                const activeImage = $('.vms-info-window .content img.active');
                if (activeImage[0]) {
                    activeImage.removeClass('active');
                }
                $("#phase-" + phaseArray[cnt]).addClass('active');
                cnt++;
            }
        }, 4000);

    }

    close() {
        this.isClick = false;
        _SelectedObj = null;
        setMarkerImage(this, 1);

        let selectedLi   = $("#vms-" + this.ID);
        if (selectedLi.hasClass('click')) {
            selectedLi.removeClass('click');
        }

        if (_VmsListFlag) {
            $('.mobile-select').val("-");
        }

        if (this.infoWindow) {
            // this.infoWindow.setMap(null);
            this.infoWindow.remove();
            this.infoWindow = null;
        }
        if (this.timer) {
            clearTimeout(this.timer);
        }
    }
}

/**
 * 돌발정보 Object
 */
class TbIncdObj {
    constructor(obj) {
        this.ID         = obj.incd_ocrr_id;
        this.NAME       = obj.incd_titl;
        this.X_CRDN     = obj.x_crdn;
        this.Y_CRDN     = obj.y_crdn;
        this.obj        = obj;
        this.marker     = null;
        this.infoWindow = null;
        this.isClick    = false;
        this.imgSrc     = '/images/icon/incd';
    }

    init() {
        this.marker = markerInit(this, _IncidentFlag);
    }

    setVisibleMarker(isVisible) {
        this.marker.setVisible(isVisible);
    }

    click() {
        if (_SelectedObj != null) {
            if (_SelectedObj === this) {
                return;
            }
            _SelectedObj.close();
        }
        _SelectedObj = this;
        const selectedLi = $('#incident-' + this.ID);
        selectedLi.addClass('click');
        selectedLi.focus();
        const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
        _Map.setCenter(coordinates);

        let iwContent =
            `<div class="incident-info-window">
                    <div class="title">
                        <div class="incident-name-${this.ID}">${this.NAME}</div>
                        <div onclick="infoWindowEvent('incident', '${this.ID}', 'close')">X</div>
                    </div>
                    <div class="content">
                        <div>
                            위치 : ${this.obj.road_nm}
                        </div>
                        <div>
                            설명 : ${this.obj.incd_expl}
                        </div>
                        <div>
                            기간 : ${this.obj.incd_strt_dt} ~ ${this.obj.incd_end_prar_dt}
                        </div>
                    </div>
            </div>`;

        // this.infoWindow = new kakao.maps.CustomOverlay({position: coordinates, content: iwContent, zindex: 15, yAnchor: 1.2});
        // this.infoWindow.setMap(_Map);
        $('body').append($(iwContent));
        this.infoWindow = $('.incident-info-window');
        let position = getInfoWidowPosition(this.infoWindow);
        let top = position[0];
        let left = position[1];
        this.infoWindow.css({
            top : top + 'px',
            left : left + 'px',
            position: 'absolute',
            zIndex : '999',
        })
        this.infoWindow.draggable({containment : 'body', handle: '.incident-name-'+ this.ID});


        setMarkerImage(this, 2);

        this.isClick = true;

        moveToScroll(_IncidentListFlag, _IncidentArray, this.ID);
    }

    close() {
        this.isClick = false;
        _SelectedObj = null;
        setMarkerImage(this, 1)
        let selectedLi = $("#incident-" + this.ID);
        if (selectedLi.hasClass('click')) {
            selectedLi.removeClass('click');
        }

        if (_IncidentListFlag) {
            $('.mobile-select').val("-");
        }

        if (this.infoWindow) {
            // this.infoWindow.setMap(null);
            this.infoWindow.remove();
            this.infoWindow = null;
        }
    }
}

/**
 * 스마트 교차로 Object
 */
class IntersectionObj {
    constructor(obj) {
        this.ID         = obj.ixr_id;
        this.NAME       = obj.ixr_nm;
        this.X_CRDN     = obj.x_crdn;
        this.Y_CRDN     = obj.y_crdn;
        this.obj        = obj;
        this.marker     = null;
        this.infoWindow = null;
        this.isClick    = false;
        this.imgSrc     = '/images/icon/intersection';
        this.detail     = [];
    }

    init() {
        let imageSrc    = this.imgSrc + '.png', // 마커이미지의 주소입니다
            size        = _size[_Map.getLevel()],
            imageSize   = new kakao.maps.Size(size, size), // 마커이미지의 크기입니다
            imageOption = {
                offset: new kakao.maps.Point(size/2, size/2),
                alt: this.NAME,
            };

        // 마커의 이미지정보를 가지고 있는 마커이미지를 생성합니다
        let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption),
            markerPosition = new kakao.maps.LatLng(this.Y_CRDN, this.X_CRDN); // 마커가 표시될 위치입니다

        this.marker = new kakao.maps.Marker(
            {map: _Map, position: markerPosition, image: markerImage, zindex: 10, clickable: true, title : this.NAME}
        );
        const level     = _Map.getLevel();
        const isVisible = (level > 2 && _IntersectionFlag);
        this.marker.setVisible(isVisible);
        let _self = this;
        kakao.maps.event.addListener(this.marker, 'click', ()=> _self.click());
    }

    setVisibleMarker(isVisible) {
        if (_Map.getLevel() <= 2) isVisible = false;
        this.marker.setVisible(isVisible);
    }

    click() {
        if (_SelectedObj != null) {
            // if (_SelectedObj === this) {
            //     return;
            // }
            _SelectedObj.close();
        }
        _SelectedObj = this;
        const selectedLi = $('#intersection-' + this.ID);
        selectedLi.addClass('click');
        selectedLi.focus();
        const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
        _Map.setCenter(coordinates);

        this.isClick = true;

        moveToScroll(_IntersectionListFlag, _IntersectionArray, this.ID);
        _Map.setLevel(2);
    }

    close() {
        this.isClick = false;
        _SelectedObj = null;
        if (_IntersectionListFlag) {
            $('.mobile-select').val("-");
        }
        let selectedLi = $("#intersection-" + this.ID);
        if (selectedLi.hasClass('click')) {
            selectedLi.removeClass('click');
        }

    }
}

/**
 * 스마트교차로 카메라 Object
 */
class IntersectionCameraObj {
    constructor(obj) {
        this.ID = obj.cmra_id + '_' + obj.drct_dvsn_cd;
        this.NAME = obj.drct_lctn;
        this.X_CRDN = obj.cmra_x_crdn;
        this.Y_CRDN = obj.cmra_y_crdn;
        this.obj = obj;
        this.marker = null;
        this.infoWindow = null;
        this.isClick = false;
        this.timer = null;
        this.polyline = null;
    }

    init() {
        this.marker = intersectionCameraMarkerInit(this);
    }

    setVisibleMarker(isVisible) {
        const visible = isVisible && _Map.getLevel() <= 2 ? _Map : null;
        this.marker.setMap(visible);
        this.polyline.setMap(visible);
    }

    click() {
        const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
        if (_SelectedObj != null) {
            if (_SelectedObj === this) {
                return;
            }
            _SelectedObj.close();
        }
        _SelectedObj = this;

        _Map.setCenter(coordinates);

        const iwContent =
            `<div class="cctv-info-window">
                    <div class="title">
                        <div class="ixr-name-${this.ID}">${this.NAME}</div>
                        <div class="close-window">X</div>
                    </div>
                    <div class="content">
                        <div>
                            <video id="video-${this.ID}" class="video-js" style="width: 100%; height: 100%;"></video>
                        </div>
                        <div>
                            <div>※ CCTV영상은 30초간 제공됩니다.</div>
                            <div class="continue-play">계속재생</div>
                        </div>
                    </div>
                </div>`;
        $('body').append($(iwContent));
        this.infoWindow = $('.cctv-info-window');
        let position = getInfoWidowPosition(this.infoWindow);
        let top = position[0];
        let left = position[1];
        this.infoWindow.css({
            top : top + 'px',
            left : left + 'px',
            position: 'absolute',
            zIndex : '999',
        });

        this.infoWindow.draggable({containment : 'body', handle : '.ixr-name-' + this.ID});

        let video = videojs("video-" + this.ID, {
            sources: [
                {
                    src: this.obj.hmpg_cmra_url,
                    type: "application/x-mpegURL",
                    crossorigin: "anonymous",
                },
            ],
            responsive: false,
            autoplay: true,
            muted: true,
            preload: "metadata",
        });

        video.on('error', ()=>{
            if (video.error().code === 4) {
                video.pause();
                video.dispose();
                $('.content > div:nth-child(1)').append($('<img src="/images/icon/error.png">'));
                $('.content > div:nth-child(1)').css({
                    display : 'flex',
                    alignItems : 'center',
                    justifyContent : 'center',
                });
                video = null;
            }
        });


        this.timer = setTimeout(() => {
            if (video) {
                video.pause();
            }
        }, 30000);

        let _self = this;
        $('.continue-play').on('click', () => {
            if (_self.timer) {
                setTimeout(_self.timer);
            }
            if (video) {
                video.play();
                _self.timer = setTimeout(() => {
                    video.pause();
                }, 30000);
            }
        });
        this.isClick = true;
        $('.close-window').on('click', (event)=> {
            event.preventDefault();
            this.close();
        });
    }

    close() {
        this.isClick    = false;
        _SelectedObj     = null;
        let oldPlayer   = document.getElementById("video-" + this.ID);
        if (oldPlayer) {
            videojs(oldPlayer).dispose();
        }
        if (this.infoWindow) {
            // this.infoWindow.setMap(null);
            this.infoWindow.remove();
            this.infoWindow = null;
        }
        if (this.timer) {
            clearTimeout(this.timer);
        }
    }
}

/**
 * 인포윈도우 이벤트
 * @param type 시설물 유형
 * @param id 요소 ID
 * @param event 이벤트 종류 (click, close)
 */
function infoWindowEvent(type, id, event) {
    window.event.preventDefault();
    let array = [];
    switch (type) {
        case 'cctv':
            array = _CctvArray;
            break;
        case 'vms':
            array = _VmsArray;
            break;
        case 'incident':
            array = _IncidentArray;
            break;
        case 'intersection':
            array = _IntersectionArray;
            break;
        case 'parking':
            array = _ParkingArray;
            break;
    }

    if (array.length > 0) {
        let idx = array.findIndex(markerObj => markerObj.ID == id);
        if (event === 'click') {
            array[idx].click();
            if (_TrafficFlag) {
                getVertex();
            }
        }
        else if (event === 'close') {
            array[idx].close();
        }
        else {}
    }
}

/**
 * 범례 클릭 시설물 아이콘 보이기 / 감추기
 * @param array 시설물 리스트
 * @param isShow 보이기/감추기(true / false)
 * @param icon 범례 아이콘
 * @param target 범례 요소
 */
function onOffFacility(array, isShow, icon, target, subArray) {
    if (isShow === false) {
        icon.removeClass('active');
        target.removeClass('active');
        array.forEach((obj)=>{
            obj.setVisibleMarker(false);
            if (obj.isClick === true) {
                obj.close();
            }
        });
        if (subArray) {
            subArray.forEach((obj)=>{
                obj.setVisibleMarker(false);
                if (obj.isClick === true) {
                    obj.close();
                }
            })
        }
    }
    else {
        icon.addClass('active')
        target.addClass('active');
        array.forEach((obj)=>{
            obj.setVisibleMarker(true);
        });

        if (subArray) {
            subArray.forEach((obj)=>{
                obj.setVisibleMarker(true);
            })
        }
    }
}

let isHide = false

/**
 * 좌측 목록 토글 이벤트
 */
function toggleEvent() {
    const $listArea = $('.left-list-area');
    const $toggleButton = $('.toggle-button');

    if (!isHide) {
        $toggleButton.animate({
            left: 0
        }, 'slow');
        $listArea .animate({
            left: -$listArea.width()
        }, 'slow');
        $toggleButton.text('>');
    }
    else {
        $toggleButton.animate({
            left: $listArea.width()
        }, 'slow');
        $listArea .animate({
            left: 0
        }, 'slow');
        $toggleButton.text('<');
    }
    isHide = !isHide;
}

window.addEventListener('resize', function(event) {
    if ($(this).width() > 450) {
        const $toggleButton = $('.toggle-button');
        const $listArea = $('.left-list-area');
        const left = $toggleButton.offset().left;
        const listLeft = $listArea.offset().left;
        if ($(this).width() >= 920) {
            if (left > 0 && left < 400) {
                $toggleButton.css('left', 400);
            }

            if (listLeft > -400 && listLeft < 0) {
                $listArea.css('left', -400);
            }
        }
        else {
            if (left > 0 && left > 275) {
                $toggleButton.css('left', 275);
            }

            if (listLeft < -273) {
                $listArea.css('left', -273);
            }
        }
    }
})
/**
 * 시설물 마커 초기화
 * @param obj 시설물 객체
 * @returns {kakao.maps.Marker}
 */
function markerInit(obj, flag) {
    let imageSrc    = obj.imgSrc + '1.png', // 마커이미지의 주소입니다
        size        = _size[_Map.getLevel()],
        imageSize   = new kakao.maps.Size(size, size), // 마커이미지의 크기입니다
        imageOption = {
            offset: new kakao.maps.Point(size/2, size/2),
            alt: obj.NAME,
        };

    // 마커의 이미지정보를 가지고 있는 마커이미지를 생성합니다
    let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption),
        markerPosition = new kakao.maps.LatLng(obj.Y_CRDN, obj.X_CRDN); // 마커가 표시될 위치입니다

    let marker = new kakao.maps.Marker(
        {map: _Map, position: markerPosition, image: markerImage, zindex: 10, clickable: true, title : obj.NAME}
    );

    marker.setVisible(flag);

    kakao.maps.event.addListener(marker, 'mouseover', function () {
        if (!obj.isClick) {
            setMarkerImage(obj, 2);
        }
    });

    kakao.maps.event.addListener(marker, 'mouseout', function () {
        if (!obj.isClick) {
            setMarkerImage(obj, 1)
        }
    });

    kakao.maps.event.addListener(marker, 'click', ()=> obj.click());

    return marker;
}

/**
 * 스마트 교차로 카메라 마커 초기화
 * @param obj 스마트 교차로 카메라 객체
 * @returns {kakao.maps.Marker}
 */
function intersectionCameraMarkerInit(obj) {
    const position =  new kakao.maps.LatLng(obj.Y_CRDN, obj.X_CRDN);
    const content = $('<div id="camera_'+obj.ID+'" title="'+obj.NAME+'">');
    const angle = Number(obj.obj.cmra_angn);
    content.css(
        {
            width: '38.45px',
            height: '38.45px',
            backgroundImage:'url(/images/icon/intersection-cctv.png)',
            backgroundSize : '38.45px 38.45px',
            backgroundRepeat: 'no-repeat',
            backgroundPosition : 'center',
            transform : 'rotate(' + angle +'deg)'
        });

    const marker = new daum.maps.CustomOverlay({
        content: content[0],
        position: position,
        zindex: 15,
    });

    const linePath1 = [obj.obj.start_x, obj.obj.start_y]
    const linePath2 = [obj.obj.end_x, obj.obj.end_y];
    const color = ['#888888', '#15B337', '#15B337', '#15B337', '#FFAA00', '#FFAA00', '#EB260C', '#EB260C', '#EB260C'];
    obj.polyline = new kakao.maps.Polyline({
        path: [
            new kakao.maps.LatLng(linePath1[1], linePath1[0]),
            new kakao.maps.LatLng(linePath2[1], linePath2[0]),
        ],
        strokeWeight: 10,
        strokeColor: color[obj.obj.acrd_los],
        strokeOpacity: 1,
        strokeStyle: 'solid',
        endArrow: true,
        name : obj.NAME,
    });

    if (_Map.getLevel() <= 2 && _IntersectionFlag){
        marker.setMap(_Map);
        obj.polyline.setMap(_Map);
    }

    content.on('click', ()=> {
        obj.click();
    });

    return marker;
}

/**
 * 시설물 이미지 유형 변경 이벤트
 * @param obj 시설물 객체
 * @param type 시설물 이미지 유형
 */
function setMarkerImage(obj, type) {
    const size = _size[_Map.getLevel()];
    const point = size/2;
    const imageSize = new kakao.maps.Size(size, size);
    const imageSrc  = obj.imgSrc + type +'.png';
    const imageOption = {
        offset: new kakao.maps.Point(point, point),
        alt: obj.NAME
    };
    const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
    obj.marker.setImage(markerImage);
}

/**
 * 선택 리스트 스크롤 높이 반환 이벤트
 * @param selectIndex 선택 인덱스
 * @returns {number} 스크롤 높이
 */
function getScrollTop(selectIndex) {
    let scrollTop = 0;
    for (let ii=0; ii < selectIndex; ii++) {
        let height = $('.left-list-area .list-content.list').children().eq(ii).css('height');
        if (height) {
            height = Number(height.replace('px', ''));
            if (!isNaN(height)) {
                scrollTop += height;
            }
        }
    }
    return scrollTop;
}

/**
 * 좌측 리스트 선택 시 스크롤 변경 이벤트
 * @param flag
 * @param array
 * @param id
 */
function moveToScroll(flag, array, id) {
    if (flag) {
        let selectIndex = array.findIndex((obj)=> obj.ID == id);
        let scrollTop = getScrollTop(selectIndex);
        $('.left-list-area .list-content.list').animate({
            scrollTop : scrollTop + 'px'
        });
        $('.mobile-select').val(id);
    }
}

/**
 * 시설물 데이터 처리 메서드
 * @param jsonData 수신 데이터
 * @param array 시설물 Object Array List
 * @param facilityClass 시설물 Object Class
 * @param listFlag 시설물 리스트 목록 표출 플래그
 * @param type 시설물 유형
 * @returns {*[]} 시설물 Object Array List
 */
function receiveFacilityData(jsonData, array, facilityClass, listFlag, type) {
    if (array.length > 0) {
        array.forEach((obj)=>{
            obj.marker.setVisible(false);
        })
    }
    if (type === 'intersection') {
        if (_IntersectionCameraArray.length > 0) {
            _IntersectionCameraArray.forEach((obj) => {
                obj.marker.setMap(null);
                obj.polyline.setMap(null);
            })
        }
    }
    array = [];
    let listStr = "";
    let mobileStr = "";
    jsonData.forEach((obj)=>{
        const markerObj = new facilityClass(obj);
        if (type === 'intersection') {
            if (obj.detail && obj.detail.length > 0) {
                obj.detail.forEach((cameraObj)=>{
                    const camera = new IntersectionCameraObj(cameraObj);
                    camera.init();
                    _IntersectionCameraArray.push(camera);
                })
            }
        }
        markerObj.init();
        listStr += `<li id="${type}-${markerObj.ID}" onclick="infoWindowEvent('${type}', '${markerObj.ID}' , 'click')">${markerObj.NAME}</li>`
        mobileStr += `<option value="${markerObj.ID}">${markerObj.NAME}</option>`;
        array.push(markerObj);
    });

    if (listFlag === true) {
        const listSection  = $('.left-list-area .list-content.list');
        listSection.empty();
        listSection.html(listStr);
        const $mobileSelect = $('.mobile-select');
        $mobileSelect.append($(mobileStr));
        $mobileSelect.on('change', function(){
            const id = $(this).val();
            if (id && id !== "-") {
                infoWindowEvent(type, id , 'click');
            }
        })
    }
    return array;
}

//https://map.kakao.com/link/search/카카오

function getInfoWidowPosition(infoWindow) {
    const map = $('#map');
    let mapHalfW = map.innerWidth() / 2;
    let mapHalfH = map.innerHeight() / 2;
    let mapTop = map.offset().top;
    let halfW   = infoWindow.innerWidth() / 2;
    let height  = infoWindow.innerHeight();
    let left = mapHalfW - halfW;
    let iconH = _size[_Map.getLevel()];
    let top = mapTop + mapHalfH - height - iconH;
    return [top, left];
}