(function ($) {
    'use strict';
    var map,map_view,geo_layer,markers_source,markers_source_cluster,clusters_layer,layerMidpoint=[],layerLines=[],layerCircles=[],geolocation, layerGeodata=[], extentGeodata=[];
    var drag_interaction, new_marker_layer, featured_slider_drag = false,lat_center = null, lon_center = null;
    var selected_feature = null, song_selected_feature = null, first_geolocate = false, map_initialized = false, map_runtime_initialized = false, startup_overlays_initialized = false, current_map_style = 'default_style', live_tracking_enabled = false, live_tracking_name = '';
    var categories = [], mapping_categories_icon = {}, mapping_categories_name = {}, markers_connections = [], pin_marker = [], features = [], geodatas = [], features_filter = [], geodata_filter = [], array_list = [], story_positions = {}, array_gif = [], array_gif_canvas = [];
    var accuracyFeature = new ol.Feature();
    var positionFeature = new ol.Feature();
    var dragPanInteraction, timeout_change_resolution = null, set_live_tracking_interval=null, get_live_tracking_interval=null;
    var default_style=null, satellite_style=null, default_style_d=null, satellite_style_d=null, street_overlay_layer=null, street_overlay_layer_d=null, satellite_overlay_layer=null, satellite_overlay_layer_d=null;
    var marker_index = -1, marker_animation = false;
    var new_marker_mode = false, new_marker_clicked = false, connections_visible = true, story_initialized = false;
    var updateWhileAnimating = false, updateWhileInteracting = false, loadTilesWhileAnimating = false, loadTilesWhileInteracting = false, preload_tiles = 10, renderBuffer = 100;
    var clusterize_list, story, ol3d = null, globe_mode=false, radiusLayer=null;
    var vector_geometries=null, pin_marker_layer = null, direction_layer = null;
    var progress_circle, search_radius_slider, audio_prompt = null;
    var initialCenter = null, initialZoom = null, first_time_filter=true, user_interacted_during_marker_load = false;
    var my_location_follow_enabled = false, change_first_time = false;
    var markers_ajax_request = null, viewport_load_timer = null, viewport_loading_enabled = false;
    var loaded_marker_bbox = null, loaded_marker_bbox_truncated = false, requested_marker_bbox_key = null, marker_metadata_loaded = false, marker_request_sequence = 0, viewport_filter_refresh = false, direct_marker_pending = true;
    var icon_check_category_0 = '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z"></path></svg>';
    var icon_check_category_1 = '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z"></path></svg>';
    var icon_check_category_2 = '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M19,19H5V5H19V19M17,17H7V7H17V17Z"></path></svg>';
    var geolocate_current_mode = 'off';
    var audio_player = new Audio(), audio_player_marker = new Audio(), first_song_play=true;
    var liveTrackingSource = null, liveTrackingLayer = null, liveTrackingMarkers = {}, get_live_tracking_positions_running = false, set_live_tracking_position_running = false;;
    var coordinates_contextmenu = null, share_location_zoom = null, share_location_id_marker = null, markerSlider = null, featuredSlider = null;
    var videoPromises = [];
    var add_marker_boundaries_source = null;
    var add_marker_boundaries_layer = null;
    var wake_lock_enabled = false;
    var wake_lock_enable_pending = false;
    var wake_lock_user_event_bound = false;
    var wake_lock_mode_one_event_bound = false;
    window.custom_start_lat = null;
    window.custom_start_lon = null;
    window.selecting_start_point = false;
    window.custom_end_lat = null;
    window.custom_end_lon = null;
    window.selecting_end_point = false;
    window.route_waypoints = [];
    window.selecting_waypoint_index = -1;

    if(window.innerWidth <= 600) {
        var hit_tolerance = 20;
    } else {
        var hit_tolerance = 5;
    }

    document.addEventListener("touchmove", function(e){
        if(!map_initialized) {
            e.preventDefault();
        }
    },{passive: false});

    function getWakeLockMode() {
        var wake_lock = parseInt(window.wake_lock,10);
        if(isNaN(wake_lock)) {
            return 0;
        }
        return wake_lock;
    }

    function canEnableWakeLock() {
        var wake_lock = getWakeLockMode();
        if(wake_lock===0) {
            return false;
        }
        if(wake_lock===1) {
            return true;
        }
        if(wake_lock===2) {
            return live_tracking_enabled && geolocate_current_mode==='live_tracking' && my_location_follow_enabled && geolocation && geolocation.getTracking();
        }
        return false;
    }

    function disableWakeLock() {
        if(typeof noSleep==='undefined' || !noSleep || typeof noSleep.disable!=='function') {
            wake_lock_enabled = false;
            wake_lock_enable_pending = false;
            removeWakeLockUserEvent();
            return;
        }
        if(wake_lock_enabled || wake_lock_enable_pending) {
            try {
                noSleep.disable();
            } catch (error) {}
        }
        wake_lock_enabled = false;
        wake_lock_enable_pending = false;
        removeWakeLockUserEvent();
    }

    function removeWakeLockUserEvent() {
        if(!wake_lock_user_event_bound) {
            return;
        }
        document.removeEventListener('click', enableWakeLockFromUserEvent, false);
        document.removeEventListener('touchend', enableWakeLockFromUserEvent, false);
        document.removeEventListener('pointerup', enableWakeLockFromUserEvent, false);
        wake_lock_user_event_bound = false;
    }

    function enableWakeLockFromUserEvent() {
        removeWakeLockUserEvent();
        if(wake_lock_enabled) {
            wake_lock_enable_pending = false;
            return;
        }
        if(!canEnableWakeLock()) {
            disableWakeLock();
            return;
        }
        if(typeof noSleep==='undefined' || !noSleep || typeof noSleep.enable!=='function') {
            wake_lock_enabled = false;
            wake_lock_enable_pending = false;
            return;
        }
        try {
            noSleep.enable();
            wake_lock_enabled = true;
            wake_lock_enable_pending = false;
        } catch (error) {
            wake_lock_enabled = false;
            wake_lock_enable_pending = true;
            waitWakeLockUserEvent();
        }
    }

    function waitWakeLockUserEvent() {
        if(wake_lock_user_event_bound) {
            return;
        }
        wake_lock_user_event_bound = true;
        document.addEventListener('click', enableWakeLockFromUserEvent, false);
        document.addEventListener('touchend', enableWakeLockFromUserEvent, false);
        document.addEventListener('pointerup', enableWakeLockFromUserEvent, false);
    }

    function handleWakeLockModeOneUserEvent() {
        if(getWakeLockMode()!==1 || wake_lock_enabled) {
            return;
        }
        enableWakeLockFromUserEvent();
    }

    function bindWakeLockModeOneUserEvent() {
        if(wake_lock_mode_one_event_bound) {
            return;
        }
        wake_lock_mode_one_event_bound = true;
        document.addEventListener('click', handleWakeLockModeOneUserEvent, false);
        document.addEventListener('touchend', handleWakeLockModeOneUserEvent, false);
        document.addEventListener('pointerup', handleWakeLockModeOneUserEvent, false);
    }

    function syncWakeLock() {
        if(canEnableWakeLock()) {
            if(wake_lock_enabled) {
                return;
            }
            wake_lock_enable_pending = true;
            if(navigator.userActivation && navigator.userActivation.isActive) {
                enableWakeLockFromUserEvent();
            } else {
                waitWakeLockUserEvent();
            }
        } else {
            disableWakeLock();
        }
    }

    $(document).bind("contextmenu",function(e){
        return false;
    });

    new RangeTouch('input[type="range"]', {});

    bindWakeLockModeOneUserEvent();

    window.check_map = function() {
        if(getWakeLockMode()===1) {
            syncWakeLock();
        }
        var r = parseInt(window.loading_text_color.substring(1, 3), 16);
        var g = parseInt(window.loading_text_color.substring(3, 5), 16);
        var b = parseInt(window.loading_text_color.substring(5, 7), 16);
        var rgba =  "rgba(" + r + ", " + g + ", " + b + ",0.25)";
        $('#map_password').css('background-color',rgba);
        progress_circle = new ProgressBar.Circle('.progress-circle', {
            strokeWidth: 5,
            easing: 'easeInOut',
            duration: 500,
            color: window.loading_text_color,
            trailColor: rgba,
            trailWidth: 5,
            text: {
                autoStyleContainer: false
            },
            step: function(state, circle) {
                var value = Math.round(circle.value() * 100);
                if (value === 0) {
                    circle.setText('');
                } else {
                    circle.setText(value);
                }
            }
        });
        progress_circle.animate(0);
        init_map();
    }

    window.show_icon_play = function () {
        $('html').css('pointer-events','initial');
        $('body').css('pointer-events','initial');
        if(window.lazy_loading==0) {
            $('.progress-circle').fadeIn();
        }
        $('#icon_play').fadeIn();
        $('.loading').removeClass('hidden');
        $('#background_loading').addClass('background_opacity');
    }

    function init_map() {
        if(window.lazy_loading>0 && window.auto_start && window.password_protected==0) {
            $('.loading').hide();
            $('#background_loading').hide();
            start_map();
            return;
        }
        if(window.auto_start==1 && window.loading_visible==0) {
            if(window.password_protected==0) {
                $('.map_render').css('opacity',1);
                start_map();
                map.getView().setCenter(ol.proj.fromLonLat([0, 0]));
                map.getView().setZoom(1);
                $('html').css('pointer-events','initial');
                $('body').css('pointer-events','initial');
            } else {
                start_map();
            }
        } else {
            $('.loading').removeClass('hidden');
            $('#background_loading').addClass('background_opacity');
            if(background_image!='') {
                var background_image_load = new Image();
                background_image_load.crossOrigin = 'anonymous';
                $(background_image_load).on('load',function () {
                    $('#background_loading').css('background-image',"url('content/"+window.background_image+"')");
                    $('#background_loading').fadeIn(100);
                    if(window.auto_start) {
                        start_map();
                    } else {
                        show_icon_play();
                    }
                }).attr('src','content/'+window.background_image);
            } else {
                if(window.auto_start) {
                    start_map();
                } else {
                    show_icon_play();
                }
            }
        }
    }

    window.start_map = function() {
        $('html').css('pointer-events','none');
        $('body').css('pointer-events','none');
        $('#icon_play').hide();
        progress_circle.animate(0.1);
        if(window.password_protected==1) {
            show_password_input();
        } else {
            render_map();
            if(window.lazy_loading>0) {
                return;
            }
            if(window.loading_visible==1) {
                $('.progress-circle').fadeIn();
            } else {
                $('.loading').hide();
                $('.map_render').css('opacity',1);
                map.getView().setCenter(ol.proj.fromLonLat([0, 0]));
                map.getView().setZoom(1);
                $('html').css('pointer-events','initial');
                $('body').css('pointer-events','initial');
            }
        }
    }

    window.show_password_input = function () {
        $('html').css('pointer-events','initial');
        $('body').css('pointer-events','initial');
        $('.progress-circle').hide();
        $('.protect').fadeIn();
        $('.loading').removeClass('hidden');
        $('#background_loading').addClass('background_opacity');
        $(document).keyup(function(event) {
            if($('.protect').is(':visible')) {
                if (event.key == "Enter") {
                    event.preventDefault();
                    check_password_map();
                }
            }
        });
    }

    function render_map() {
        fix_logo();
        var scale = window.innerHeight / 1100;
        scale = Math.min(0.6, Math.max(0.3, scale))
        document.documentElement.style.setProperty("--scale_overlay_input", scale);
        if(window.my_location_mode==='disabled') {
            $('.my_position_icon').addClass('hidden');
            window.default_my_location = 0;
        }
        window.captcha = new Captcha($('#captcha_canvas'));
        window.issue_captcha = new Captcha($('#issue_captcha_canvas'));
        window.photo_captcha = new Captcha($('#photo_captcha_canvas'));
        viewer_refresh_visible_captchas();
        $('#btn_select_start_map,#btn_reset_start_map,#btn_select_end_map,#btn_reset_end_map').tooltipster({
            delay: 10,
            hideOnClick: true,
            position: 'top',
            theme: 'tooltipster-borderless'
        });
        $('#button_actions div').tooltipster({
            delay: 10,
            hideOnClick: true,
            position: 'bottom',
            theme: 'tooltipster-borderless'
        });
        if(window.map_mode=='large') {
            window.globe=0;
        }
        if(search_radius_enabled) {
            $("#search_radius_slider").ionRangeSlider({
                onChange: function (data) {
                    window.search_radius_m = data.from;
                    change_radius_m();
                }
            });
            search_radius_slider = $("#search_radius_slider").data("ionRangeSlider");
        }
        set_colors();
        initialize_map();
        inizialize_resize_sheet_icon();
        fix_ui();
        init_category_fields_logic();
        markerSlider = initCategorySlider('slider_categories_marker', 'sheet_categories');
        if(window.weather!='none') {
            $('.weather').css('opacity',1);
        } else {
            $('.weather').hide();
        }
        update_footer_visibility();
    }

    window.go_to_home = function() {
        map_view.animate({
            center: initialCenter,
            zoom: initialZoom,
            duration: 500
        });
    }

    window.set_colors = function() {
        document.documentElement.style.setProperty('--sml-main-color', window.main_color_hex);
        document.documentElement.style.setProperty('--sml-main-hover', window.darker_color_hex);
        document.documentElement.style.setProperty('--sml-main-contrast', get_contrast_color(window.main_color_hex));
        document.documentElement.style.setProperty('--sml-main-soft', hexToRgbA(window.main_color_hex,0.16));
        $('#markers_loading_status').css({
            'background-color': window.main_color_hex,
            'border-color': window.darker_color_hex,
            'color': get_contrast_color(window.main_color_hex)
        });
        $('.list_icon').css('color',window.main_color_hex);
        $('.search_icon').css('color',window.main_color_hex);
        $('.filter_icon').css('color',window.main_color_hex);
        $('.features_icon i').css('color',window.main_color_hex);
        $('#report_issue_div span').css('color',window.main_color_hex);
        $('#form_new_review button[type="submit"]').css('background',window.main_color_hex);
        $('#form_add_photo button[type="submit"]').css('background',window.main_color_hex);
        $('#form_report_issue button[type="submit"]').css('background',window.main_color_hex);
        $('.nav_marker_next').css('color',window.main_color_hex+' !important');
        $('.nav_marker_prev').css('color',window.main_color_hex+' !important');
        $('.new_marker_msg').css('color',window.main_color_hex);
        $('.drag_marker_msg').css('color',window.main_color_hex);
        $('.new_marker_btn').css('background-color',window.main_color_hex);
        $('.resize_sheet_icon').css('color',window.main_color_hex);
        $('#search_radius_container .irs--round .irs-bar').css('background-color',window.main_color_hex);
        $('#search_radius_container .irs--round .irs-handle').css('border-color',window.main_color_hex);
        $('#search_radius_container').css('color',window.main_color_hex);
        $('#search_radius_infinity').css('accent-color',window.main_color_hex);
        $('.btn_share_cookie_denied').css('background-color',window.main_color_hex);
    };

    window.update_footer_visibility = function() {
        var has_visible_children = false;
        $('.map-legal-footer').children().each(function() {
            if (!$(this).hasClass('hidden') && $(this).css('display') !== 'none') {
                has_visible_children = true;
            }
        });
        if (!has_visible_children) {
            $('.map-legal-footer').css({'padding': '0px', 'height': '0px', 'overflow': 'hidden', 'border': 'none'});
        } else {
            $('.map-legal-footer').css({'padding': '', 'height': '', 'overflow': '', 'border': ''});
        }
    };

    window.fix_ui = function () {
        if(!window.enable_search && !window.enable_list && (window.enable_categories==0 || window.enable_categories==3)) {
            $('.sheet_detail').css({'top':'6px','max-height':'calc(100% - 52px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
        }
        if(!window.enable_list && window.enable_search) {
            $('#searchbox').css({'margin-left':'6px','width':'calc(100% - 14px)'});
        }
        if(!window.enable_search && window.enable_list && (window.enable_categories==0 || window.enable_categories==3)) {
            $('.search_div').css({'background-color':'unset','width':'auto','box-shadow':'none'});
            $('.list_icon').addClass('only');
            $('.list_detail').css({'top':'44px','max-height':'calc(100% - 88px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('.sheet_detail').css({'top':'44px','max-height':'calc(100% - 88px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
        }
        if(!window.enable_search && !window.enable_list && (window.enable_categories==1 || window.enable_categories==2)) {
            $('.search_div').css({'background-color':'unset','width':'auto','box-shadow':'none'});
            $('.filter_icon').addClass('only');
            $('.list_detail').css({'top':'44px','max-height':'calc(100% - 88px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('.sheet_detail').css({'top':'6px','max-height':'calc(100% - 52px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('.filter_icon').css({'right':'unset','left':'0','width':'32px'});
            $('.categories_div').css({'top':'44px','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('#count_categories').addClass('hidden');
        }
        if(!window.enable_search && window.enable_list && (window.enable_categories==1 || window.enable_categories==2)) {
            $('.search_div').css({'background-color':'unset','width':'auto','box-shadow':'none'});
            $('.filter_icon').addClass('only');
            $('.list_icon').addClass('only');
            $('.list_detail').css({'top':'44px','max-height':'calc(100% - 88px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('.sheet_detail').css({'top':'44px','max-height':'calc(100% - 88px)','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('.filter_icon').css({'right':'unset','left':'38px','width':'32px'});
            $('.categories_div').css({'top':'44px','border-top-left-radius':'10px','border-top-right-radius':'10px'});
            $('#count_categories').addClass('hidden');
        }
        if($('.new_marker_btn').length && $('.live_tracking_btn').length) {
            $('.live_tracking_btn').css('margin-top','6px');
            $('.live_tracking_stop_btn').css('margin-top','6px');
        }
        if($('.search_div').hasClass('hidden')) {
            $('.btn_bar').addClass('btn_bar_no_search');
            $('.new_marker_msg').addClass('btn_bar_no_search');
            $('.drag_marker_msg').addClass('btn_bar_no_search');
            $('.new_sheet_detail').addClass('btn_bar_no_search');
        } else {
            $('.search_div').fadeIn();
        }
    }

    function get_contrast_color(hex) {
        hex = String(hex || '').replace('#','');
        if(hex.length===3) {
            hex = hex.split('').map(function (value) { return value + value; }).join('');
        }
        if(!/^[0-9a-f]{6}$/i.test(hex)) return '#ffffff';
        var r = parseInt(hex.substring(0,2),16);
        var g = parseInt(hex.substring(2,4),16);
        var b = parseInt(hex.substring(4,6),16);
        return ((r * 299 + g * 587 + b * 114) / 1000) > 150 ? '#111111' : '#ffffff';
    }

    var timeuot_change_coordinates, current_lat=0, current_lon=0;
    window.initialize_map = function () {
        setTimeout(function () {
            $('.logo').css('opacity',1);
            $('.logo_mobile').css('opacity',1);
            if(!globe_mode) {
                $('.new_marker_btn').css({'opacity':1,'pointer-events':'initial'});
                $('.live_tracking_btn').css({'opacity':1,'pointer-events':'initial'});
                $('.live_tracking_stop_btn').css({'opacity':1,'pointer-events':'initial'});
                $('#live_tracking_count').css({'opacity':1,'pointer-events':'none'});
            }
        },200);
        ol.style.IconImageCache.shared.setSize(1000);
        updateWhileAnimating = window.updateWhileAnimating;
        updateWhileInteracting = window.updateWhileInteracting;
        loadTilesWhileAnimating = window.loadTilesWhileAnimating;
        loadTilesWhileInteracting = window.loadTilesWhileInteracting;
        preload_tiles = window.preload_tiles;
        renderBuffer = window.renderBuffer;
        var osm_attributions = '© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors';
        var arcgis_attributions = '© <a href="https://www.esri.com/it-it/legal/copyright-trademarks" target="_blank">Esri</a> tiles - © <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors';
        var maptiler_attributions = '© <a href="https://www.maptiler.com/copyright/" target="_blank">MapTiler</a> tiles - © <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors';
        var here_attributions = '© <a href="https://legal.here.com/en-gb/terms/here-end-user-terms" target="_blank">HERE</a> Technologies';
        var stadia_attributions = '© <a href="https://stadiamaps.com/" target="_blank">Stadia Maps</a> - © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> - © <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors';
        var carto_attributions = '© <a href="https://carto.com/attributions" target="_blank">CARTO</a> tiles - © <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors';
        var google_attributions = '';
        if(window.enable_map_street==1) {
            switch(window.map_street_provider) {
                case 'google':
                    var attributions = google_attributions;
                    if(window.use_street_attributions==1) {
                        if(window.street_attributions!='') {
                            attributions = window.street_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    switch(window.map_style) {
                        case 'google_roadmap':
                            var google_source = new ol.source.Google({
                                key: window.google_api,
                                mapType: 'roadmap',
                                scale: 'scaleFactor1x',
                                highDpi: false,
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true,
                                language: window.google_lang
                            });
                            break;
                        case 'google_terrain':
                            var google_source = new ol.source.Google({
                                key: window.google_api,
                                mapType: 'terrain',
                                layerTypes: ['layerRoadmap'],
                                scale: 'scaleFactor1x',
                                highDpi: false,
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true,
                                language: window.google_lang
                            });
                            break;
                    }
                    default_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: google_source
                    });
                    if(!window.is_webgl) {
                        default_style = default_style_d;
                    } else {
                        default_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: google_source
                        });
                    }
                    break;
                case 'default':
                    switch(window.map_style) {
                        case 'osm_free':
                            var attributions = osm_attributions;
                            if(window.use_street_attributions==1) {
                                if(window.street_attributions!='') {
                                    attributions = window.street_attributions;
                                }
                            } else {
                                attributions = '';
                            }
                            default_style_d = new ol.layer.Tile({
                                preload: preload_tiles,
                                source: new ol.source.XYZ({
                                    url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                                    minZoom: window.street_minzoom,
                                    maxZoom: window.street_maxzoom,
                                    attributions: attributions,
                                    attributionsCollapsible: true
                                })
                            });
                            if(!window.is_webgl) {
                                default_style = default_style_d;
                            } else {
                                default_style = new ol.layer.WebGLTile({
                                    preload: preload_tiles,
                                    source: new ol.source.XYZ({
                                        url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                                        minZoom: window.street_minzoom,
                                        maxZoom: window.street_maxzoom,
                                        attributions: attributions,
                                        attributionsCollapsible: true
                                    })
                                });
                            }
                            break;
                        case 'arcgis_street':
                            var attributions = arcgis_attributions;
                            if(window.use_street_attributions==1) {
                                if(window.street_attributions!='') {
                                    attributions = window.street_attributions;
                                }
                            } else {
                                attributions = '';
                            }
                            default_style_d = new ol.layer.Tile({
                                preload: preload_tiles,
                                source: new ol.source.XYZ({
                                    url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
                                    minZoom: window.street_minzoom,
                                    maxZoom: window.street_maxzoom,
                                    attributions: attributions,
                                    attributionsCollapsible: true
                                })
                            });
                            if(!window.is_webgl) {
                                default_style = default_style_d;
                            } else {
                                default_style = new ol.layer.WebGLTile({
                                    preload: preload_tiles,
                                    source: new ol.source.XYZ({
                                        url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
                                        minZoom: window.street_minzoom,
                                        maxZoom: window.street_maxzoom,
                                        attributions: attributions,
                                        attributionsCollapsible: true
                                    })
                                });
                            }
                            break;
                        case 'arcgis_topo':
                            var attributions = arcgis_attributions;
                            if(window.use_street_attributions==1) {
                                if(window.street_attributions!='') {
                                    attributions = window.street_attributions;
                                }
                            } else {
                                attributions = '';
                            }
                            default_style_d = new ol.layer.Tile({
                                preload: preload_tiles,
                                source: new ol.source.XYZ({
                                    url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
                                    minZoom: window.street_minzoom,
                                    maxZoom: window.street_maxzoom,
                                    attributions: attributions,
                                    attributionsCollapsible: true
                                })
                            });
                            if(!window.is_webgl) {
                                default_style = default_style_d;
                            } else {
                                default_style = new ol.layer.WebGLTile({
                                    preload: preload_tiles,
                                    source: new ol.source.XYZ({
                                        url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
                                        minZoom: window.street_minzoom,
                                        maxZoom: window.street_maxzoom,
                                        attributions: attributions,
                                        attributionsCollapsible: true
                                    })
                                });
                            }
                            break;
                    }
                    break;
                case 'carto':
                    var attributions = carto_attributions;
                    if(window.use_street_attributions==1) {
                        if(window.street_attributions!='') {
                            attributions = window.street_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    default_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.XYZ({
                            url: 'https://{a-d}.basemaps.cartocdn.com/rastertiles/'+window.map_style+'/{z}/{x}/{y}{r}.png',
                            minZoom: window.street_minzoom,
                            maxZoom: window.street_maxzoom,
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        default_style = default_style_d;
                    } else {
                        default_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.XYZ({
                                url: 'https://{a-d}.basemaps.cartocdn.com/rastertiles/'+window.map_style+'/{z}/{x}/{y}{r}.png',
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
                case 'stadia':
                    var attributions = stadia_attributions;
                    if(window.use_street_attributions==1) {
                        if(window.street_attributions!='') {
                            attributions = window.street_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    default_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.XYZ({
                            url: 'https://tiles.stadiamaps.com/tiles/'+window.map_style+'/{z}/{x}/{y}@2x.png',
                            minZoom: window.street_minzoom,
                            maxZoom: window.street_maxzoom,
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        default_style = default_style_d;
                    } else {
                        default_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.XYZ({
                                url: 'https://tiles.stadiamaps.com/tiles/'+window.map_style+'/{z}/{x}/{y}@2x.png',
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
                case 'maptiler':
                    var attributions = maptiler_attributions;
                    if(window.use_street_attributions==1) {
                        if(window.street_attributions!='') {
                            attributions = window.street_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    default_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.TileJSON({
                            url: 'https://api.maptiler.com/maps/'+window.map_style+'/tiles.json?key='+window.maptiler_api,
                            minZoom: window.street_minzoom,
                            maxZoom: window.street_maxzoom,
                            tileSize: 512,
                            crossOrigin: 'anonymous',
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        default_style = default_style_d;
                    } else {
                        default_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.TileJSON({
                                url: 'https://api.maptiler.com/maps/'+window.map_style+'/tiles.json?key='+window.maptiler_api,
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                tileSize: 512,
                                crossOrigin: 'anonymous',
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
                case 'here':
                    var attributions = here_attributions;
                    if(window.use_street_attributions==1) {
                        if(window.street_attributions!='') {
                            attributions = window.street_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    if(window.here_lang=='') {
                        var here_url = 'https://maps.hereapi.com/v3/base/mc/{z}/{x}/{y}/jpeg?size=512&style='+window.map_style+'&apiKey='+window.here_api;
                    } else {
                        var here_url = 'https://maps.hereapi.com/v3/base/mc/{z}/{x}/{y}/jpeg?size=512&lang='+window.here_lang+'&style='+window.map_style+'&apiKey='+window.here_api;
                    }
                    default_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.XYZ({
                            url: here_url,
                            minZoom: window.street_minzoom,
                            maxZoom: window.street_maxzoom,
                            tileSize: 512,
                            crossOrigin: 'anonymous',
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        default_style = default_style_d;
                    } else {
                        default_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.XYZ({
                                url: here_url,
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                tileSize: 512,
                                crossOrigin: 'anonymous',
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
                case 'openfreemap':
                    default_style = new ol.layer.Group();
                    default_style_d = new ol.layer.Group();
                    if(window.openfreemap_street_url!='') {
                        var url_openfreemap = window.openfreemap_street_url;
                    } else {
                        var url_openfreemap = 'https://tiles.openfreemap.org/styles/'+window.map_style.replace('openfreemap_','');
                    }
                    olms.apply(default_style, url_openfreemap);
                    olms.apply(default_style_d, url_openfreemap);
                    break;
                case 'custom':
                    var attributions = '';
                    if(window.use_street_attributions==1) {
                        if(window.street_attributions!='') {
                            attributions = window.street_attributions;
                        }
                    }
                    default_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.XYZ({
                            url: window.street_basemap,
                            minZoom: window.street_minzoom,
                            maxZoom: window.street_maxzoom,
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        default_style = default_style_d;
                    } else {
                        default_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.XYZ({
                                url: window.street_basemap,
                                minZoom: window.street_minzoom,
                                maxZoom: window.street_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
            }
        }
        if(window.enable_map_satellite==1) {
            switch(window.map_satellite_provider) {
                case 'google':
                    var attributions = google_attributions;
                    if(window.use_satellite_attributions==1) {
                        if(window.satellite_attributions!='') {
                            attributions = window.satellite_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    switch(window.map_style_satellite) {
                        case 'google_satellite':
                            var google_source = new ol.source.Google({
                                key: window.google_api_satellite,
                                mapType: 'satellite',
                                scale: 'scaleFactor1x',
                                highDpi: false,
                                minZoom: window.satellite_minzoom,
                                maxZoom: window.satellite_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true,
                                language: window.google_lang_satellite
                            });
                            break;
                        case 'google_hybrid':
                            var google_source = new ol.source.Google({
                                key: window.google_api_satellite,
                                mapType: 'satellite',
                                layerTypes: ['layerRoadmap'],
                                scale: 'scaleFactor1x',
                                highDpi: false,
                                minZoom: window.satellite_minzoom,
                                maxZoom: window.satellite_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true,
                                language: window.google_lang_satellite
                            });
                            break;
                    }
                    satellite_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: google_source
                    });
                    if(!window.is_webgl) {
                        satellite_style = satellite_style_d;
                    } else {
                        satellite_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: google_source
                        });
                    }
                    break;
                case 'default':
                    switch(window.map_style_satellite) {
                        case 'arcgis':
                            var attributions = arcgis_attributions;
                            if(window.use_satellite_attributions==1) {
                                if(window.satellite_attributions!='') {
                                    attributions = window.satellite_attributions;
                                }
                            } else {
                                attributions = '';
                            }
                            satellite_style_d = new ol.layer.Tile({
                                preload: preload_tiles,
                                source: new ol.source.XYZ({
                                    url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
                                    minZoom: window.satellite_minzoom,
                                    maxZoom: (window.satellite_maxzoom>=19) ? 19 : window.satellite_maxzoom,
                                    attributions: attributions,
                                    attributionsCollapsible: true
                                })
                            });
                            if(!window.is_webgl) {
                                satellite_style = satellite_style_d;
                            } else {
                                satellite_style = new ol.layer.WebGLTile({
                                    preload: preload_tiles,
                                    source: new ol.source.XYZ({
                                        url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
                                        minZoom: window.satellite_minzoom,
                                        maxZoom: (window.satellite_maxzoom>=19) ? 19 : window.satellite_maxzoom,
                                        attributions: attributions,
                                        attributionsCollapsible: true
                                    })
                                });
                            }
                            break;
                    }
                    break;
                case 'maptiler':
                    var attributions = maptiler_attributions;
                    if(window.use_satellite_attributions==1) {
                        if(window.satellite_attributions!='') {
                            attributions = window.satellite_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    switch(window.map_style_satellite) {
                        case 'satellite-v2':
                            var endpoint_maptiler = "tiles";
                            break;
                        default:
                            var endpoint_maptiler = "maps";
                            break;
                    }
                    satellite_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.TileJSON({
                            url: 'https://api.maptiler.com/'+endpoint_maptiler+'/'+window.map_style_satellite+'/tiles.json?key='+window.maptiler_api_satellite,
                            minZoom: window.satellite_minzoom,
                            maxZoom: window.satellite_maxzoom,
                            tileSize: 512,
                            crossOrigin: 'anonymous',
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        satellite_style = satellite_style_d;
                    } else {
                        satellite_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.TileJSON({
                                url: 'https://api.maptiler.com/'+endpoint_maptiler+'/'+window.map_style_satellite+'/tiles.json?key='+window.maptiler_api_satellite,
                                minZoom: window.satellite_minzoom,
                                maxZoom: window.satellite_maxzoom,
                                tileSize: 512,
                                crossOrigin: 'anonymous',
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
                case 'here':
                    var attributions = here_attributions;
                    if(window.use_satellite_attributions==1) {
                        if(window.satellite_attributions!='') {
                            attributions = window.satellite_attributions;
                        }
                    } else {
                        attributions = '';
                    }
                    if(window.here_lang_satellite=='') {
                        var here_url = 'https://maps.hereapi.com/v3/base/mc/{z}/{x}/{y}/jpeg?size=512&style='+window.map_style_satellite+'&apiKey='+window.here_api_satellite;
                    } else {
                        var here_url = 'https://maps.hereapi.com/v3/base/mc/{z}/{x}/{y}/jpeg?size=512&lang='+window.here_lang_satellite+'&style='+window.map_style_satellite+'&apiKey='+window.here_api_satellite;
                    }
                    satellite_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.XYZ({
                            url: here_url,
                            minZoom: window.satellite_minzoom,
                            maxZoom: window.satellite_maxzoom,
                            tileSize: 512,
                            crossOrigin: 'anonymous',
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        satellite_style = satellite_style_d;
                    } else {
                        satellite_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.XYZ({
                                url: here_url,
                                minZoom: window.satellite_minzoom,
                                maxZoom: window.satellite_maxzoom,
                                tileSize: 512,
                                crossOrigin: 'anonymous',
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
                case 'custom':
                    var attributions = '';
                    if(window.use_satellite_attributions==1) {
                        if(window.satellite_attributions!='') {
                            attributions = window.satellite_attributions;
                        }
                    }
                    satellite_style_d = new ol.layer.Tile({
                        preload: preload_tiles,
                        source: new ol.source.XYZ({
                            url: window.satellite_basemap,
                            minZoom: window.satellite_minzoom,
                            maxZoom: window.satellite_maxzoom,
                            attributions: attributions,
                            attributionsCollapsible: true
                        })
                    });
                    if(!window.is_webgl) {
                        satellite_style = satellite_style_d;
                    } else {
                        satellite_style = new ol.layer.WebGLTile({
                            preload: preload_tiles,
                            source: new ol.source.XYZ({
                                url: window.satellite_basemap,
                                minZoom: window.satellite_minzoom,
                                maxZoom: window.satellite_maxzoom,
                                attributions: attributions,
                                attributionsCollapsible: true
                            })
                        });
                    }
                    break;
            }
        }
        if(window.initial_coordinates!='') {
            var lat = window.initial_coordinates.split(",")[0];
            var lon = window.initial_coordinates.split(",")[1];
        } else {
            var lat = 45.60627;
            var lon = 9.00083;
        }
        var minZoom = window.street_minzoom;
        var maxZoom = window.street_maxzoom;
        if(window.enable_map_street==0 || window.enable_map_satellite==0) {
            if(window.enable_map_street==1) {
                minZoom = window.street_minzoom;
                maxZoom = window.street_maxzoom;
            }
            if(window.enable_map_satellite==1) {
                minZoom = window.satellite_minzoom;
                maxZoom = window.satellite_maxzoom;
            }
        }
        if(window.extent!==null && window.extent!='' && window.extent!='null' && window.extent!=undefined) {
            var extent = JSON.parse(window.extent);
            map_view = new ol.View({
                center: ol.proj.fromLonLat([lon,lat]),
                enableRotation: false,
                minZoom: minZoom,
                maxZoom: maxZoom,
                extent: extent,
                smoothExtentConstraint: true,
                showFullExtent: true
            });
        } else {
            map_view = new ol.View({
                center: ol.proj.fromLonLat([lon,lat]),
                enableRotation: false,
                minZoom: minZoom,
                maxZoom: maxZoom
            });
        }
        var initial_layer = default_style;
        if(window.street_basemap_overlay!='') {
            street_overlay_layer = new ol.layer.WebGLTile({
                preload: preload_tiles,
                source: new ol.source.XYZ({
                    url: window.street_basemap_overlay
                }),
                opacity: window.street_overlay_opacity
            });
            if(!window.is_webgl) {
                street_overlay_layer = street_overlay_layer_d;
            } else {
                street_overlay_layer_d = new ol.layer.Tile({
                    preload: preload_tiles,
                    source: new ol.source.XYZ({
                        url: window.street_basemap_overlay
                    }),
                    opacity: window.street_overlay_opacity
                });
            }
        }
        if(window.satellite_basemap_overlay!='') {
            satellite_overlay_layer = new ol.layer.WebGLTile({
                preload: preload_tiles,
                source: new ol.source.XYZ({
                    url: window.satellite_basemap_overlay
                }),
                opacity: window.satellite_overlay_opacity
            });
            if(!window.is_webgl) {
                satellite_overlay_layer = satellite_overlay_layer_d;
            } else {
                satellite_overlay_layer_d = new ol.layer.Tile({
                    preload: preload_tiles,
                    source: new ol.source.XYZ({
                        url: window.satellite_basemap_overlay
                    }),
                    opacity: window.satellite_overlay_opacity
                });
            }
        }
        var empty_layer = new ol.layer.Vector({
            source: new ol.source.Vector({})
        });
        var map_layers = [initial_layer];
        if(street_overlay_layer!==null) {
            map_layers.push(street_overlay_layer);
            $('.overlay_slider input').val(parseFloat(street_overlay_layer.getOpacity()));
            $('.overlay_slider').show();
        } else {
            map_layers.push(empty_layer);
        }
        if(window.enable_map_street==0 || window.enable_map_satellite==0) {
            $('.switch_style').hide();
            $('.bottom_left_controls').css('left','0');
            if(window.enable_map_street==1) {
                initial_layer=default_style;
                current_map_style='default_style';
                map_layers = [initial_layer];
                if(street_overlay_layer!==null) {
                    map_layers.push(street_overlay_layer);
                    $('.overlay_slider input').val(parseFloat(street_overlay_layer.getOpacity()));
                    $('.overlay_slider').show();
                } else {
                    map_layers.push(empty_layer);
                }
            }
            if(window.enable_map_satellite==1) {
                initial_layer=satellite_style;
                current_map_style='satellite_style';
                map_layers = [initial_layer];
                if(satellite_overlay_layer!==null) {
                    map_layers.push(satellite_overlay_layer);
                    $('.overlay_slider input').val(parseFloat(satellite_overlay_layer.getOpacity()));
                    $('.overlay_slider').show();
                } else {
                    map_layers.push(empty_layer);
                }
            }
        }
        var fullscreen_control = new ol.control.FullScreen({
            source: 'fullscreen'
        });
        var attribution_control = new ol.control.Attribution({
            target: document.getElementById('map-attributions'),
            collapsible: false,
            collapsed: false
        });
        var units = 'metric';
        switch(window.unit_map) {
            case 'km':
                units = 'metric';
                break;
            case 'miles':
                units = 'us';
                break;
        }
        var scale_control = new ol.control.ScaleLine({
            target: document.getElementById('scale-line-target'),
            units: units,
        });
        const base = window.devicePixelRatio || 1;
        const scaledBase = base > 1.5 ? 1.5 + (base - 1.5) * 0.3 : base;
        const multipliers = { low: 0.7, medium: 0.85, high: 1 };
        let caps = { low: 0.8, medium: 0.9, high: 1 };
        if (base >= 2) caps = { low: 1, medium: 1.1, high: 1.2 };
        const screenWidth = window.innerWidth || 1024;
        if (screenWidth < 768) {
            if (base >= 2) caps = { low: 1, medium: 1.4, high: 1.8 };
        } else if (screenWidth < 1024) {
            if (base >= 2) caps = { low: 1, medium: 1.25, high: 1.5 };
        }
        const quality = window.qualityResolution;
        const multiplier = multipliers[quality] ?? 1;
        const cap = caps[quality] ?? 1.2;
        const pixel_ratio = Math.min(scaledBase * multiplier, cap);
        map = new ol.Map({
            pixelRatio: pixel_ratio,
            renderer: (!window.is_webgl) ? 'canvas' : 'webgl',
            target: 'map',
            controls: ol.control.defaults.defaults({
                attributions: false,
                zoom : true
            }).extend([fullscreen_control, attribution_control]),
            layers: map_layers,
            view: map_view,
            loadTilesWhileAnimating: loadTilesWhileAnimating,
            loadTilesWhileInteracting: loadTilesWhileInteracting,
            moveTolerance: 5
        });
        var mark_user_map_interaction = function () {
            if(window.lazy_loading>0 && !window.markers_loaded) {
                user_interacted_during_marker_load = true;
            }
        };
        map.on('pointerdrag',mark_user_map_interaction);
        map.getViewport().addEventListener('wheel',mark_user_map_interaction,{passive:true,capture:true});
        map.getViewport().addEventListener('dblclick',mark_user_map_interaction,true);
        map.getViewport().addEventListener('keydown',function (event) {
            if(['+','=','-','ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(event.key)) {
                mark_user_map_interaction();
            }
        });
        map.getViewport().addEventListener('click',function (event) {
            if(event.target.closest('.ol-zoom-in, .ol-zoom-out')) {
                mark_user_map_interaction();
            }
        },true);
        map.on('moveend',schedule_viewport_markers_load);
        if (window.show_scale_control) {
            map.addControl(scale_control);
        }
        if (window.enable_measure) {
            initializeMeasureTool(map);
        }
        var contextmenuItems = [
            {
                text: window.viewer_labels.center_map_here,
                classname: 'bold center_icon',
                icon: 'images/center.png',
                callback: (object, map) => {
                    map_view.animate({
                        duration: 300,
                        center: object.coordinate
                    });
                }
            },
            {
                text: window.viewer_labels.zoom_in,
                classname: 'ol-ctx-menu-zoom-in ol-ctx-menu-icon',
                callback: (object, map) => {
                    map_view.animate({
                        zoom: Number(map_view.getZoom()) + 1,
                        duration: 500,
                        center: object.coordinate,
                    });
                }
            },
            {
                text: window.viewer_labels.zoom_out,
                classname: 'ol-ctx-menu-zoom-out ol-ctx-menu-icon',
                callback: (object, map) => {
                    map_view.animate({
                        zoom: Number(map_view.getZoom()) - 1,
                        duration: 500,
                        center: object.coordinate,
                    });
                }
            },
            '-',
            {
                text: '--',
                classname: 'bold feature_name'
            },
            {
                text: '--',
                classname: 'bold current_coordinates'
            },
            {
                text: window.viewer_labels.share_location,
                classname: 'bold share_location',
                callback: (object, map) => {
                    if(window.enable_share_map==1) {
                        share_location_context = true;
                        share_location_zoom = Number(map_view.getZoom()).toFixed(0);
                        toggle_share_map(true);
                    }
                }
            },
            {
                text: '<i class="fas fa-directions" style="width: 15px; text-align: center;"></i>&nbsp;&nbsp;' + window.viewer_labels.directions,
                classname: 'bold context_directions',
                callback: (object, map) => {
                    if (share_location_id_marker != null) {
                        window.marker_current_id = share_location_id_marker;
                    } else {
                        window.marker_current_id = 0;
                    }
                    var coords = coordinates_contextmenu.split(', ');
                    open_directions(parseFloat(coords[0]), parseFloat(coords[1]));
                }
            },
            {
                text: '<i class="fas fa-play" style="width: 15px; text-align: center;"></i>&nbsp;&nbsp;' + window.viewer_labels.directions_from_here,
                classname: 'bold context_directions_from',
                callback: (object, map) => {
                    var coords = coordinates_contextmenu.split(', ');
                    window.custom_start_lat = parseFloat(coords[0]);
                    window.custom_start_lon = parseFloat(coords[1]);
                    window.positionToAddress_start_point(window.custom_start_lat, window.custom_start_lon);
                    $('#btn_reset_start_map').show();
                    window.trigger_route_recalc();
                }
            },
            {
                text: '<i class="fas fa-plus-circle" style="width: 15px; text-align: center;"></i>&nbsp;&nbsp;' + window.viewer_labels.add_stop_here,
                classname: 'bold context_directions_stop',
                callback: (object, map) => {
                    var coords = coordinates_contextmenu.split(', ');
                    window.route_waypoints.push({lat: parseFloat(coords[0]), lon: parseFloat(coords[1]), address: '...'});
                    window.positionToAddress_waypoint(parseFloat(coords[0]), parseFloat(coords[1]), window.route_waypoints.length - 1);
                }
            },
            {
                text: '<i class="fas fa-flag-checkered" style="width: 15px; text-align: center;"></i>&nbsp;&nbsp;' + window.viewer_labels.directions_to_here,
                classname: 'bold context_directions_to',
                callback: (object, map) => {
                    var coords = coordinates_contextmenu.split(', ');
                    window.custom_end_lat = parseFloat(coords[0]);
                    window.custom_end_lon = parseFloat(coords[1]);
                    window.positionToAddress_end_point(window.custom_end_lat, window.custom_end_lon);
                    $('#btn_reset_end_map').show();
                    window.trigger_route_recalc();
                }
            }
        ];
        var contextmenu = new ContextMenu({
            width: 'auto',
            defaultItems: false,
            items: contextmenuItems
        });
        document.body.addEventListener('click', function (event) {
            $('.list_block_featured').css('border','2px solid transparent');
            var copyButton = event.target.closest('.current_coordinates');
            if (copyButton) {
                event.stopPropagation();
                if(coordinates_contextmenu!=null) {
                    navigator.clipboard.writeText(coordinates_contextmenu).then(() => {
                        $('.current_coordinates').css('pointer-events','none');
                        var html = $('.current_coordinates span').html();
                        $('.current_coordinates span').html(window.viewer_labels.copied_clipboard);
                        setTimeout(function() {
                            $('.current_coordinates span').html(html);
                            $('.current_coordinates').css('pointer-events','initial');
                        },1000);
                    }).catch(err => {
                        console.error('Failed to copy:', err);
                    });
                }
            }
        }, true);
        contextmenu.on('beforeopen', function (evt) {
            $('.ol-ctx-menu-container li.feature_name').hide();
            const feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
                return ft;
            });
            var lat = null;
            var lon = null;
            if(window.enable_share_markers==0) {
                $('.share_location').addClass('hidden');
            } else {
                $('.share_location').removeClass('hidden');
            }
            if(window.enable_directions==0) {
                $('.context_directions').addClass('hidden');
                $('.context_directions_from').addClass('hidden');
                $('.context_directions_to').addClass('hidden');
                $('.context_directions_stop').addClass('hidden');
            } else {
                if ($('.direction_detail').hasClass('open')) {
                    $('.context_directions').addClass('hidden');
                    $('.context_directions_from').removeClass('hidden');
                    $('.context_directions_to').removeClass('hidden');
                    $('.context_directions_stop').removeClass('hidden');
                } else {
                    $('.context_directions').removeClass('hidden');
                    $('.context_directions_from').addClass('hidden');
                    $('.context_directions_to').addClass('hidden');
                    $('.context_directions_stop').addClass('hidden');
                }
            }
            if (feature) {
                if(feature.getProperties().features!==undefined) {
                    if(feature.getProperties().features.length==1) {
                        var name = feature.getProperties().features[0].values_.name;
                        lat = parseFloat(feature.getProperties().features[0].values_.latitude);
                        lon = parseFloat(feature.getProperties().features[0].values_.longitude);
                        $('.ol-ctx-menu-container li.feature_name').html(name);
                        $('.ol-ctx-menu-container li.feature_name').show();
                        share_location_id_marker = feature.getProperties().features[0].values_.id_db;
                    }
                }
            }
            if(lat!=null && lon!=null) {
                coordinates_contextmenu = lat.toFixed(6)+', '+lon.toFixed(6);
            } else {
                var coordinates = ol.proj.transform(map.getCoordinateFromPixel(evt.pixel),'EPSG:3857','EPSG:4326');
                coordinates_contextmenu = coordinates[1].toFixed(6)+', '+coordinates[0].toFixed(6);
            }
            $('.current_coordinates span').html(coordinates_contextmenu);
        });
        contextmenu.on('open', function (evt) {
            var width = $('.ol-ctx-menu-container').css('width');
            $('.ol-ctx-menu-container').css('min-width',width);
        });
        map.addControl(contextmenu);
        let touchTimeout;
        let longPressTriggered = false;
        let preventNextClick = false;
        const viewport = map.getViewport();
        viewport.addEventListener('touchstart', function (e) {
            if (e.touches.length !== 1) return;
            longPressTriggered = false;
            const touch = e.touches[0];
            touchTimeout = setTimeout(() => {
                longPressTriggered = true;
                preventNextClick = true;
                const simulatedEvent = new MouseEvent('contextmenu', {
                    bubbles: true,
                    cancelable: true,
                    view: window,
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                touch.target.dispatchEvent(simulatedEvent);
            }, 600);
        });
        viewport.addEventListener('touchend', (e) => {
            clearTimeout(touchTimeout);
            if (longPressTriggered) {
                e.preventDefault();
                e.stopImmediatePropagation();
            }
        });
        viewport.addEventListener('touchmove', () => clearTimeout(touchTimeout));
        viewport.addEventListener('click', function (e) {
            if (preventNextClick) {
                e.preventDefault();
                e.stopImmediatePropagation();
                preventNextClick = false;
            }
        }, true);
        $(".ol-ctx-menu-container").detach().appendTo('#context-menu');
        var progress = new ol.control.ProgressBar({
            className: 'progress_bar_map',
            label: '',
            layers: [default_style,satellite_style]
        });
        map.addControl(progress);
        var currZoom = parseInt(map.getView().getZoom());
        map.on('moveend', function(e) {
            var newZoom = parseInt(map.getView().getZoom());
            if (currZoom != newZoom) {
                currZoom = newZoom;
            }
            if(window.weather!='none') {
                clearTimeout(timeuot_change_coordinates);
                $('.weather #w_icon').css('opacity',0.7);
                $('.weather span').css('opacity',0.7);
                timeuot_change_coordinates = setTimeout(function() {
                    var centerPosArr = map.getView().getCenter();
                    var coords = ol.proj.toLonLat(centerPosArr, 'EPSG:3857');
                    current_lat = coords[1];
                    current_lon = coords[0];
                    get_weather(current_lat,current_lon,window.weather);
                },1000);
            }
        });
        map.on('movestart', function(e){
            if(!$('.popup').hasClass('remain_visible')) {
                $('.popup').hide();
            }
        });
        window.hoveredFeatures = [];
        map.on('pointermove', function(e){
            if (e.dragging) {
                return;
            }
            if(!$('.popup').hasClass('remain_visible')) {
                $('.popup').hide();
            }
            const target = e.originalEvent.target;
            if (target.tagName !== 'CANVAS') {
                return;
            }
            var pixel = map.getEventPixel(e.originalEvent);
            var currentHoveredFeatures = [];
            var hit = false;
            if(globe_mode) {
                try {
                    var pickedObject = ol3d.getCesiumScene().pick(new window.Cesium.Cartesian2(pixel[0], pixel[1]));
                    var feature = pickedObject.primitive.olFeature;
                    if(feature) {
                        let layer = null;
                        for (const l of layerGeodata) {
                            const source = l.getSource();
                            if (source && source.hasFeature && source.hasFeature(feature)) {
                                layer = l;
                                break;
                            }
                        }
                        const content = layer ? layer.get('popupContent') : null;
                        if (content) {
                            hit = true;
                        } else {
                            hit = false;
                        }
                        if(feature.getProperties().name!='connection_midpoint' && feature.getProperties().name!=null) {
                            if(window.map_mode=='default') {
                                var style_hover = feature.values_.style_hover;
                                var style_label = feature.values_.style_label;
                                if(style_hover!=null) {
                                    if(feature.values_.style !== style_hover) {
                                        if(style_label!=null) {
                                            feature.setStyle([style_hover,style_label]);
                                        } else {
                                            feature.setStyle(style_hover);
                                        }
                                        feature.values_.style=style_hover;
                                    }
                                    currentHoveredFeatures.push(feature);
                                }
                                if(feature.values_.active==0) {
                                    hit = false;
                                } else {
                                    hit = true;
                                    show_popup(feature,false);
                                }
                            }
                        }
                    }
                } catch (e) {}
            } else {
                hit = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
                    try {
                        if (layerGeodata.includes(layer)) {
                            const content = layer.get('popupContent');
                            if(content!='' && content!=null && content!=undefined) {
                                return true;
                            } else {
                                return false;
                            }
                        }
                        if (feature === positionFeature) {
                            return true;
                        }
                        if(feature.getProperties().name=='live_tracking') {
                            return true;
                        }
                        if(feature.getProperties().name=='connection_midpoint') {
                            return true;
                        }
                        if(feature.getProperties().features && feature.getProperties().features.length>=1) {
                            if(feature.getProperties().features.length==1) {
                                if(window.map_mode=='default') {
                                    var style_hover = feature.getProperties().features[0].values_.style_hover;
                                    var style_label = feature.getProperties().features[0].values_.style_label;
                                    if(feature.getProperties().features.length>1) {
                                        style_hover=null;
                                    }
                                    if(style_hover!=null) {
                                        if(feature.getProperties().features[0].values_.style !== style_hover) {
                                            if(style_label!=null) {
                                                feature.setStyle([style_hover,style_label]);
                                            } else {
                                                feature.setStyle(style_hover);
                                            }
                                            feature.getProperties().features[0].values_.style=style_hover;
                                        }
                                        currentHoveredFeatures.push(feature);
                                    }
                                }
                                if(feature.getProperties().features[0].values_.active==0) {
                                    return false;
                                }
                                show_popup(feature,false);
                            }
                            return true;
                        }
                    } catch (e) {}
                },{hitTolerance: hit_tolerance});
            }
            window.hoveredFeatures.forEach(function(feature) {
                if (!currentHoveredFeatures.includes(feature)) {
                    if(globe_mode) {
                        var id_db = feature.values_.id_db;
                        var current_style = feature.values_.style;
                        var style = feature.values_.style_default;
                        var style_hover = feature.values_.style_hover;
                        var style_label = feature.values_.style_label;
                    } else {
                        var id_db = feature.getProperties().features[0].values_.id_db;
                        var current_style = feature.getProperties().features[0].values_.style;
                        var style = feature.getProperties().features[0].values_.style_default;
                        var style_hover = feature.getProperties().features[0].values_.style_hover;
                        var style_label = feature.getProperties().features[0].values_.style_label;
                    }
                    if (style_hover!=null) {
                        if(parseInt(window.marker_current_id)!=parseInt(id_db)) {
                            if(style!==current_style) {
                                if(style_label!=null) {
                                    feature.setStyle([style,style_label]);
                                } else {
                                    feature.setStyle(style);
                                }
                            }
                            if(globe_mode) {
                                feature.values_.style=style;
                            } else {
                                feature.getProperties().features[0].values_.style=style;
                            }
                        } else {
                            if(current_style!==style_hover) {
                                if(style_label!=null) {
                                    feature.setStyle([style_hover,style_label]);
                                } else {
                                    feature.setStyle(style_hover);
                                }
                            }
                            if(globe_mode) {
                                feature.values_.style=style_hover;
                            } else {
                                feature.getProperties().features[0].values_.style=style_hover;
                            }
                        }
                    }
                }
            });
            window.hoveredFeatures = currentHoveredFeatures;
            if(!new_marker_mode && window.sheet_detail) map.getViewport().style.cursor = hit ? 'pointer' : '';
        });
        map.on('pointerdown', function(e){
            $('.popup_c').hide();
        });
        map.on('click', function(e){
            if (window.selecting_start_point) {
                var coords = ol.proj.toLonLat(e.coordinate);
                window.custom_start_lon = coords[0];
                window.custom_start_lat = coords[1];
                window.selecting_start_point = false;
                map.getTargetElement().style.cursor = '';
                window.positionToAddress_start_point(window.custom_start_lat, window.custom_start_lon);
                $('.direction_detail').show();
                $('#btn_reset_start_map').show();
                var profile = $('.direction_profile_active').attr('data-profile') || 'driving-car';
                open_ors_directions(profile, window.custom_start_lat, window.custom_start_lon);
                return false;
            }
            if (window.selecting_end_point) {
                var coords = ol.proj.toLonLat(e.coordinate);
                window.custom_end_lon = coords[0];
                window.custom_end_lat = coords[1];
                window.selecting_end_point = false;
                map.getTargetElement().style.cursor = '';
                window.positionToAddress_end_point(window.custom_end_lat, window.custom_end_lon);
                $('.direction_detail').show();
                $('#btn_reset_end_map').show();
                window.trigger_route_recalc();
                return false;
            }
            if (window.selecting_waypoint_index !== -1) {
                var coords = ol.proj.toLonLat(e.coordinate);
                var active_idx = window.selecting_waypoint_index;
                window.route_waypoints[active_idx].lon = coords[0];
                window.route_waypoints[active_idx].lat = coords[1];
                window.selecting_waypoint_index = -1;
                map.getTargetElement().style.cursor = '';
                $('.direction_detail').show();
                window.positionToAddress_waypoint(coords[1], coords[0], active_idx);
                return false;
            }
            $('.list_block_featured').css('border','2px solid transparent');
            if(new_marker_mode && !new_marker_clicked) {
                if (!isPointInAllowedBoundaries(e.coordinate)) {
                    alertify.error(window.viewer_labels.out_of_bounds);
                    return false;
                }
                new_marker_clicked = true;
                var coords = ol.proj.toLonLat(e.coordinate);
                var lat = coords[1];
                var lon = coords[0];
                new_marker_layer = new ol.layer.Vector({
                    zIndex: 11,
                    source: new ol.source.Vector({
                        features: [
                            new ol.Feature({
                                geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat]))
                            })
                        ],
                    }),
                    style: new ol.style.Style({
                        image: new ol.style.Circle({
                            anchor: [0.5, 0.5],
                            anchorXUnits: 'fraction',
                            anchorYUnits: 'fraction',
                            radius: 14,
                            stroke: new ol.style.Stroke({
                                color: '#ffffff',
                                opacity: 0.6,
                                width: 1,
                            }),
                            fill: new ol.style.Fill({
                                color: window.main_color_hex,
                                opacity: 1,
                                weight: 1
                            })
                        })
                    })
                });
                new_marker_layer.setZIndex(21);
                map.addLayer(new_marker_layer);
                let lastValidCoords;
                drag_interaction = new ol.interaction.Translate({layers: [new_marker_layer]});
                drag_interaction.on('translatestart', function(evt) {
                    lastValidCoords = evt.features.getArray()[0].getGeometry().getCoordinates();
                });
                drag_interaction.on('translateend', function(evt) {
                    const feature = evt.features.getArray()[0];
                    const newCoords = feature.getGeometry().getCoordinates();
                    if (!isPointInAllowedBoundaries(newCoords)) {
                        alertify.error(window.viewer_labels.out_of_bounds);
                        feature.getGeometry().setCoordinates(lastValidCoords);
                    } else {
                        var lat_lon = ol.proj.transform(newCoords, 'EPSG:3857', 'EPSG:4326');
                        $('#new_latitude').val(lat_lon[1].toFixed(6));
                        $('#new_longitude').val(lat_lon[0].toFixed(6));
                        position_to_address(lat_lon[1], lat_lon[0]);
                    }
                });
                map.addInteraction(drag_interaction);
                $('.new_marker_msg').hide();
                $('.drag_marker_msg').show();
                return false;
            } else {
                $('.popup_c').hide();
                var pixel = map.getEventPixel(e.originalEvent);
                if(globe_mode) {
                    var hit = false;
                    try {
                        var pickedObject = ol3d.getCesiumScene().pick(new window.Cesium.Cartesian2(pixel[0], pixel[1]));
                        var feature = pickedObject.primitive.olFeature;
                        if(feature) {
                            hit = true;
                            if(feature.getProperties().name=='connection_midpoint') {
                                show_popup_c(feature);
                            }
                        }
                    } catch (e) {}
                } else {
                    var hit = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
                        try {
                            if (feature === positionFeature || feature.getProperties().name=='live_tracking') {
                                const featureGeometry = feature.getGeometry();
                                const extent = featureGeometry.getExtent();
                                map.getView().fit(extent, {
                                    duration: 500,
                                    maxZoom: 18,
                                });
                            }
                        } catch (e) {}
                        try {
                            if(feature.getProperties().name=='connection_midpoint') {
                                show_popup_c(feature);
                            }
                            return true;
                        } catch (e) {}
                    },{hitTolerance: hit_tolerance});
                }
                if(!new_marker_mode && window.sheet_detail) map.getViewport().style.cursor = hit ? 'pointer' : '';
            }
        });
        geolocation = new ol.Geolocation({
            trackingOptions: {
                enableHighAccuracy: true,
                timeout: 30000,
                maximumAge: 10000
            },
            projection: map_view.getProjection()
        });
        geolocation.on('change', handleGeolocationUpdate);
        geolocation.on('change:position', handleGeolocationUpdate);
        geolocation.on('error', function (error) {
            console.warn('Geolocation error:', error);
            if (set_live_tracking_interval) {
                clearInterval(set_live_tracking_interval);
            }
            alertify.set('notifier','position', 'bottom-center');
            alertify.error(window.viewer_labels.error_location);
            $('.live_tracking_btn').removeClass('disabled');
            $('.live_tracking_btn').removeClass('hidden');
            $('.live_tracking_stop_btn').addClass('hidden');
            $('.my_position_icon').removeClass('disabled');
            $('.my_position_icon .geolocate_icon').show();
            $('.my_position_icon .geolocate_loading_icon').hide();
            $('.my_position_icon').removeClass('searching');
            geolocate_current_mode = 'off';
            geolocation.setTracking(false);
            syncWakeLock();
            geo_layer.setVisible(false);
            enablePan();
            $('.my_position_icon').removeClass('active_c');
            $('.nav_marker_prev').removeClass('disabled2');
            $('.nav_marker_next').removeClass('disabled2');
            $('.btn_story').removeClass('disabled2');
            $('.home_icon').removeClass('disabled2');
            $('.my_position_icon .geolocate_icon').addClass('fa-crosshairs').removeClass('fa-person-running');
            calculate_distance(false);
            first_geolocate = false;
            if(search_radius_enabled) {
                check_marker_in_radius(null,-1);
                remove_radius();
            }
        });
        geolocation.on('change:accuracyGeometry', function() {
            accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
        });
        positionFeature.setStyle(new ol.style.Style({
            image: new ol.style.Circle({
                radius: 9,
                fill: new ol.style.Fill({ color: '#0084ca' }),
                stroke: new ol.style.Stroke({
                    color: '#ffffff',
                    width: 3,
                }),
            }),
        }));
        window.addLabelToPositionFeature = function(labelText) {
            const currentStyle = positionFeature.getStyle();
            const imageStyle = currentStyle.getImage();
            positionFeature.setStyle(new ol.style.Style({
                image: imageStyle,
                text: new ol.style.Text({
                    text: labelText,
                    font: '12px Arial, sans-serif',
                    fill: new ol.style.Fill({ color: '#0084ca' }),
                    backgroundFill: new ol.style.Fill({ color: '#ffffff' }),
                    padding: [2, 4, 2, 4],
                    offsetY: -20,
                    scale: 1,
                }),
            }));
        }
        window.removeLabelFromPositionFeature = function() {
            const currentStyle = positionFeature.getStyle();
            const imageStyle = currentStyle.getImage();
            positionFeature.setStyle(new ol.style.Style({
                image: imageStyle,
            }));
        }
        window.delete_live_tracking_position = function() {
            $.ajax({
                url: "ajax/delete_live_tracking_position.php",
                type: "POST",
                data: {
                    id_map: window.id_map,
                    id: window.id_live_tracking,
                },
                async: true,
                success: function (json) {},
                error: function() {},
            });
        }
        window.set_live_tracking_position = function(coordinates) {
            if (set_live_tracking_position_running) return;
            set_live_tracking_position_running = true;
            var my_lat_lon = ol.proj.transform(coordinates, 'EPSG:3857', 'EPSG:4326');
            var lat = my_lat_lon[1];
            var lon = my_lat_lon[0];
            $.ajax({
                url: "ajax/set_live_tracking_position.php",
                type: "POST",
                data: {
                    id_map: window.id_map,
                    id: window.id_live_tracking,
                    lat: lat,
                    lon: lon,
                    name: live_tracking_name,
                    timeout: window.live_tracking_timeout,
                    hash: window.live_tracking_hash
                },
                async: true,
                success: function (json) {
                    var rsp = JSON.parse(json);
                    if(rsp.status==="auth_required") {
                        live_tracking_enabled = false;
                        alertify.message(window.viewer_labels.auth_required_msg);
                        open_viewer_login();
                        return;
                    }
                    var positions = rsp.positions;
                    updateLiveTrackingMarkers(positions);
                    $('#live_tracking_count b').html(positions.length+1);
                },
                error: function() {},
                complete: function() {
                    set_live_tracking_position_running = false;
                }
            });
        }
        window.get_live_tracking_positions = function() {
            if (get_live_tracking_positions_running) return;
            get_live_tracking_positions_running = true;
            $.ajax({
                url: "ajax/get_live_tracking_positions.php",
                type: "POST",
                data: {
                    id_map: window.id_map,
                    id: window.id_live_tracking,
                    timeout: window.live_tracking_timeout,
                    hash: window.live_tracking_hash
                },
                async: true,
                success: function (json) {
                    var rsp = JSON.parse(json);
                    var positions = rsp.positions;
                    updateLiveTrackingMarkers(positions);
                    $('#live_tracking_count b').html(positions.length);
                },
                error: function() {},
                complete: function() {
                    get_live_tracking_positions_running = false;
                }
            });
        }
        function handleGeolocationUpdate(evt) {
            $('.live_tracking_btn').removeClass('disabled');
            if (geolocate_current_mode === 'live_tracking' && live_tracking_enabled) {
                $('.live_tracking_btn').addClass('hidden');
                $('.live_tracking_stop_btn').removeClass('hidden');
            }
            $('.my_position_icon .geolocate_icon').show();
            $('.my_position_icon .geolocate_loading_icon').hide();
            $('.my_position_icon').removeClass('searching');
            const coordinates = geolocation.getPosition();
            const accuracy = geolocation.getAccuracy();
            if(live_tracking_enabled && accuracy<=40) {
                set_live_tracking_position(coordinates);
            }
            if (!first_geolocate && !clicked_featured && !$('.sheet_detail').is(':visible') && window.initial_coordinates=='') {
                if (window.my_location_zoom !== 0) {
                    map_view.setZoom(window.my_location_zoom);
                }
            }
            if (!first_geolocate || (my_location_follow_enabled && !clicked_featured)) {
                if (!$('.sheet_detail').is(':visible') && window.initial_coordinates=='') {
                    map_view.animate({
                        center: coordinates,
                        duration: 200,
                    });
                }
                if(window.lazy_loading==0 || window.markers_loaded) {
                    calculate_distance(coordinates);
                    if (search_radius_enabled) {
                        check_marker_in_radius(coordinates, window.search_radius_m);
                        show_search_radius_m();
                    }
                }
                first_geolocate = true;
            } else if (search_radius_enabled) {
                if(window.lazy_loading==0 || window.markers_loaded) {
                    check_marker_in_radius(coordinates, window.search_radius_m);
                }
            }
            positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null);
            map.render();
        }
        map_view.on('change:resolution', (event) => {
            clearTimeout(timeout_change_resolution);
            if(geolocation.getTracking() && my_location_follow_enabled && !clicked_featured) {
                timeout_change_resolution = setTimeout(function() {
                    if(!$('.sheet_detail').is(':visible') && window.initial_coordinates=='') {
                        var coordinates = geolocation.getPosition();
                        map_view.animate({
                            center: coordinates,
                            duration: 200
                        });
                    }
                },200);
            }
        });
        geo_layer = new ol.layer.Vector({
            zIndex: 1,
            source: new ol.source.Vector({
                features: [accuracyFeature, positionFeature]
            })
        });
        geo_layer.setZIndex(11);
        map.addLayer(geo_layer);
        map.on('click', function(evt) {
            if (window.selecting_start_point) return false;
            if (window.selecting_end_point) return false;
            let handled = false;
            map.removeLayer(pin_marker_layer);
            if (globe_mode) {
                const scene = ol3d.getCesiumScene();
                const picked = scene.pick(new Cesium.Cartesian2(evt.pixel[0], evt.pixel[1]));
                let feature = null;
                if (picked && picked.id) {
                    feature = picked.id.olFeature || null;
                } else if (picked && picked.primitive && picked.primitive.olFeature) {
                    feature = picked.primitive.olFeature;
                }
                if (feature) {
                    let layer = null;
                    for (const l of layerGeodata) {
                        const source = l.getSource();
                        if (source && source.hasFeature && source.hasFeature(feature)) {
                            layer = l;
                            break;
                        }
                    }
                    const content = layer ? layer.get('popupContent') : null;
                    if (content) {
                        $.fancybox.open(content);
                    }
                    const f_id = feature.get('id');
                    if (typeof f_id !== 'undefined') {
                        open_sheet_detail(f_id, true);
                    }
                }
                return false;
            } else {
                var feature = map.forEachFeatureAtPixel(evt.pixel,
                    function(feature, layer) {
                        if (layerGeodata.includes(layer)) {
                            if(!handled) {
                                handled = true;
                                const content = layer.get('popupContent');
                                if(content!='' && content!=null && content!=undefined) {
                                    $.fancybox.open(content);
                                }
                            }
                            return false;
                        }
                        if (typeof feature.values_.features !== 'undefined') {
                            var size = feature.values_.features.length;
                            if(size==1) {
                                return feature.values_.features[0];
                            } else {
                                var f_source = new ol.source.Vector({
                                    features: feature.values_.features
                                });
                                if($('#list_area').is(':visible')) {
                                    map.getView().fit(f_source.getExtent(), {duration: 800,padding: [100, 250, 100, 100], nearest: true});
                                } else {
                                    if($('#featured_container').css('opacity')=='1') {
                                        map.getView().fit(f_source.getExtent(), {duration: 800,padding: [100, 100, 225, 100], nearest: true});
                                    } else {
                                        map.getView().fit(f_source.getExtent(), {duration: 800,padding: [100, 100, 100, 100], nearest: true});
                                    }
                                }
                                return false;
                            }
                        }
                    },{ hitTolerance: hit_tolerance });
            }
            if (feature) {
                var f_id = feature.get('id');
                if(typeof f_id!=='undefined') {
                    open_sheet_detail(f_id,true);
                }
            }
        });
        resize_elements_ui();
        prepare_map_audio();
        if(window.lazy_loading>0) {
            set_markers_loading_state(true);
            if(window.default_zoom>0) {
                map_view.setZoom(window.default_zoom);
            } else if(map_view.getZoom()===undefined) {
                map_view.setZoom(1);
            }
            if(window.lazy_loading===2) {
                initialize_viewport_start_position();
            }
            draw_geometries();
            complete_map_startup();
            initialize_startup_overlays();
            setTimeout(function () {
                if(window.lazy_loading===2) {
                    viewport_loading_enabled = true;
                    load_viewport_markers(false);
                } else {
                    get_markers();
                }
            },0);
        } else {
            get_markers();
        }
        get_geoimages();
        get_geodata();
        get_story();
        switch(window.default_view) {
            case 'satellite':
                if(window.use_satellite_attributions==1) {
                    $('#map-attributions').removeClass('hidden');
                    $('.map-legal-footer').addClass('extra-padding');
                } else {
                    $('#map-attributions').addClass('hidden');
                    $('.map-legal-footer').removeClass('extra-padding');
                }
                break;
            case 'street':
                if(window.use_street_attributions==1) {
                    $('#map-attributions').removeClass('hidden');
                    $('.map-legal-footer').addClass('extra-padding');
                } else {
                    $('#map-attributions').addClass('hidden');
                    $('.map-legal-footer').removeClass('extra-padding');
                }
                break;
        }
        update_footer_visibility();
        map.on('precompose',function() {
            if(window.enable_map_satellite==1 && !change_first_time) {
                if(window.default_view=='satellite') {
                    change_first_time = true;
                    change_map_style('satellite_style');

                }
            }
        });
        switch(default_my_location) {
            case 1:
                setTimeout(function () {
                    geolocate();
                },2000);
                break;
            case 2:
                if(window.innerWidth > 600) {
                    setTimeout(function () {
                        geolocate();
                    },2000);
                }
                break;
            case 3:
                if(window.innerWidth <= 600) {
                    setTimeout(function () {
                        geolocate();
                    },2000);
                }
                break;
        }
    }

    window.geolocate = function () {
        if(live_tracking_enabled) {
            var my_location_mode = 'live_tracking';
        } else {
            var my_location_mode = window.my_location_mode;
        }
        switch(my_location_mode) {
            case 'disabled':
                break;
            case 'live_tracking':
                geolocate_current_mode = 'live_tracking';
                if(!geolocation.getTracking()) {
                    geolocation.setTracking(true);
                    my_location_follow_enabled = true;
                    syncWakeLock();
                    geo_layer.setVisible(true);
                    disablePan();
                    $('.my_position_icon').addClass('searching');
                    $('.my_position_icon .geolocate_icon').hide();
                    $('.my_position_icon .geolocate_loading_icon').show();
                    $('.my_position_icon').addClass('active_c');
                } else {
                    $('.live_tracking_btn').addClass('hidden');
                    $('.live_tracking_stop_btn').removeClass('hidden');
                }
                addLabelToPositionFeature(live_tracking_name);
                break;
            case 'geolocate':
                if(geolocation.getTracking()) {
                    geolocate_current_mode = 'off';
                    geolocation.setTracking(false);
                    syncWakeLock();
                    geo_layer.setVisible(false);
                    enablePan();
                    $('.my_position_icon').removeClass('active_c');
                    $('.nav_marker_prev').removeClass('disabled2');
                    $('.nav_marker_next').removeClass('disabled2');
                    $('.btn_story').removeClass('disabled2');
                    $('.home_icon').removeClass('disabled2');
                    $('.my_position_icon .geolocate_icon').addClass('fa-crosshairs').removeClass('fa-person-running');
                    calculate_distance(false);
                    first_geolocate = false;
                    if(search_radius_enabled) {
                        check_marker_in_radius(null,-1);
                        remove_radius();
                    }
                } else {
                    geolocate_current_mode = 'geolocate';
                    geolocation.setTracking(true);
                    syncWakeLock();
                    geo_layer.setVisible(true);
                    $('.my_position_icon').addClass('searching');
                    $('.my_position_icon .geolocate_icon').hide();
                    $('.my_position_icon .geolocate_loading_icon').show();
                    $('.my_position_icon').addClass('active_c');
                }
                break;
            case 'follow_geolocate':
                if(geolocation.getTracking()) {
                    if(geolocate_current_mode=='follow') {
                        geolocate_current_mode = 'geolocate';
                        my_location_follow_enabled = false;
                        syncWakeLock();
                        $('.my_position_icon .geolocate_icon').addClass('fa-crosshairs').removeClass('fa-person-running');
                        $('.nav_marker_prev').removeClass('disabled2');
                        $('.nav_marker_next').removeClass('disabled2');
                        $('.btn_story').removeClass('disabled2');
                        $('.home_icon').removeClass('disabled2');
                        enablePan();
                    } else {
                        geolocate_current_mode = 'off';
                        geolocation.setTracking(false);
                        syncWakeLock();
                        geo_layer.setVisible(false);
                        enablePan();
                        $('.my_position_icon').removeClass('active_c');
                        $('.nav_marker_prev').removeClass('disabled2');
                        $('.nav_marker_next').removeClass('disabled2');
                        $('.btn_story').removeClass('disabled2');
                        $('.home_icon').removeClass('disabled2');
                        $('.my_position_icon .geolocate_icon').addClass('fa-crosshairs').removeClass('fa-person-running');
                        calculate_distance(false);
                        first_geolocate = false;
                        if(search_radius_enabled) {
                            check_marker_in_radius(null,-1);
                            remove_radius();
                        }
                    }
                } else {
                    geolocate_current_mode = 'follow';
                    geolocation.setTracking(true);
                    my_location_follow_enabled = true;
                    syncWakeLock();
                    geo_layer.setVisible(true);
                    disablePan();
                    $('.my_position_icon').addClass('searching');
                    $('.my_position_icon .geolocate_icon').hide();
                    $('.my_position_icon .geolocate_loading_icon').show();
                    $('.nav_marker_prev').addClass('disabled2');
                    $('.nav_marker_next').addClass('disabled2');
                    $('.btn_story').addClass('disabled2');
                    $('.home_icon').addClass('disabled2');
                    $('.my_position_icon .geolocate_icon').removeClass('fa-crosshairs').addClass('fa-person-running');
                    $('.my_position_icon').addClass('active_c');
                }
                break;
            case 'geolocate_follow':
                if(geolocation.getTracking()) {
                    if(geolocate_current_mode=='geolocate') {
                        geolocate_current_mode = 'follow';
                        my_location_follow_enabled = true;
                        geolocation.setTracking(true);
                        syncWakeLock();
                        geo_layer.setVisible(true);
                        disablePan();
                        $('.nav_marker_prev').addClass('disabled2');
                        $('.nav_marker_next').addClass('disabled2');
                        $('.btn_story').addClass('disabled2');
                        $('.home_icon').addClass('disabled2');
                        $('.my_position_icon .geolocate_icon').removeClass('fa-crosshairs').addClass('fa-person-running');
                    } else {
                        geolocate_current_mode = 'off';
                        geolocation.setTracking(false);
                        syncWakeLock();
                        geo_layer.setVisible(false);
                        enablePan();
                        $('.my_position_icon').removeClass('active_c');
                        $('.nav_marker_prev').removeClass('disabled2');
                        $('.nav_marker_next').removeClass('disabled2');
                        $('.btn_story').removeClass('disabled2');
                        $('.home_icon').removeClass('disabled2');
                        $('.my_position_icon .geolocate_icon').addClass('fa-crosshairs').removeClass('fa-person-running');
                        calculate_distance(false);
                        first_geolocate = false;
                        if(search_radius_enabled) {
                            check_marker_in_radius(null,-1);
                            remove_radius();
                        }
                    }
                } else {
                    geolocate_current_mode = 'geolocate';
                    my_location_follow_enabled = false;
                    geolocation.setTracking(true);
                    syncWakeLock();
                    geo_layer.setVisible(true);
                    enablePan();
                    $('.my_position_icon').addClass('searching');
                    $('.my_position_icon .geolocate_icon').hide();
                    $('.my_position_icon .geolocate_loading_icon').show();
                    $('.my_position_icon').addClass('active_c');
                }
                break;
            case "follow":
                if(geolocation.getTracking()) {
                    geolocate_current_mode = 'off';
                    my_location_follow_enabled = false;
                    geolocation.setTracking(false);
                    syncWakeLock();
                    geo_layer.setVisible(false);
                    enablePan();
                    $('.my_position_icon').removeClass('active_c');
                    $('.nav_marker_prev').removeClass('disabled2');
                    $('.nav_marker_next').removeClass('disabled2');
                    $('.btn_story').removeClass('disabled2');
                    $('.home_icon').removeClass('disabled2');
                    $('.my_position_icon .geolocate_icon').addClass('fa-crosshairs').removeClass('fa-person-running');
                    calculate_distance(false);
                    first_geolocate = false;
                    if(search_radius_enabled) {
                        check_marker_in_radius(null,-1);
                        remove_radius();
                    }
                } else {
                    geolocate_current_mode = 'follow';
                    my_location_follow_enabled = true;
                    geolocation.setTracking(true);
                    syncWakeLock();
                    geo_layer.setVisible(true);
                    disablePan();
                    $('.my_position_icon').addClass('searching');
                    $('.my_position_icon .geolocate_icon').hide();
                    $('.my_position_icon .geolocate_loading_icon').show();
                    $('.nav_marker_prev').addClass('disabled2');
                    $('.nav_marker_next').addClass('disabled2');
                    $('.btn_story').addClass('disabled2');
                    $('.home_icon').addClass('disabled2');
                    $('.my_position_icon .geolocate_icon').removeClass('fa-crosshairs').addClass('fa-person-running');
                    $('.my_position_icon').addClass('active_c');
                }
                break;
        }
    }

    function disablePan() {
        map.getInteractions().forEach(function(interaction) {
            if (interaction instanceof ol.interaction.DragPan) {
                dragPanInteraction = interaction;
                map.removeInteraction(interaction);
            }
        });
    }

    function enablePan() {
        if (dragPanInteraction) {
            map.addInteraction(dragPanInteraction);
        }
    }

    window.open_radius_m = function() {
        if($('#search_radius_container').is(':visible')) {
            close_radius_m();
        } else {
            close_categories();
            close_list_detail();
            close_sheet_detail();
            $('#search_radius_container').show();
        }
    }

    window.close_radius_m = function() {
        $('#search_radius_container').hide();
    }

    window.change_radius_infinity = function() {
        var infinity = $('#search_radius_infinity').is(':checked') ? 1 : 0;
        if(infinity==1) {
            window.search_radius_m=-1;
            change_radius_m();
            remove_radius();
            search_radius_slider.update({
                disable: true
            });
            $('#search_radius_container .irs--round .irs-bar').css('background-color',window.main_color_hex);
            $('#search_radius_container .irs--round .irs-handle').css('border-color',window.main_color_hex);
        } else {
            window.search_radius_m=search_radius_slider.result.from;
            change_radius_m();
            search_radius_slider.update({
                disable: false
            });
            $('#search_radius_container .irs--round .irs-bar').css('background-color',window.main_color_hex);
            $('#search_radius_container .irs--round .irs-handle').css('border-color',window.main_color_hex);
        }
    }

    window.change_radius_m = function () {
        if(window.unit_map=='miles') {
            var search_icon_w = 80;
            var filter_icon_r = 90;
        } else {
            var search_icon_w = 80;
            var filter_icon_r = 90;
            if(window.search_radius_m>=1 && window.search_radius_m<1000) {
                search_icon_w = 70;
                filter_icon_r = 80;
            } else if(window.search_radius_m>=1000 && window.search_radius_m<10000) {
                search_icon_w = 65;
                filter_icon_r = 75;
            } else if(window.search_radius_m>=10000 && window.search_radius_m<100000) {
                search_icon_w = 70;
                filter_icon_r = 80;
            } else if(window.search_radius_m>=100000 && window.search_radius_m<1000000) {
                search_icon_w = 75;
                filter_icon_r = 85;
            } else if(window.search_radius_m==-1) {
                search_icon_w = 50;
                filter_icon_r = 60;
            }
        }
        if($(document).width()<600) {
            search_icon_w = search_icon_w + 4;
            filter_icon_r = filter_icon_r + 4;
        }
        $('.search_icon').css('width',search_icon_w+'px');
        $('.filter_icon').css('right',filter_icon_r+'px');
        if(window.search_radius_m==-1) {
            $('#search_radius_m').html('<i class="fa-solid fa-infinity"></i>');
            check_marker_in_radius(null,window.search_radius_m);
        } else {
            $('#search_radius_m').html(convertMetersToKm(window.search_radius_m));
            var coordinates = geolocation.getPosition();
            if (coordinates) {
                check_marker_in_radius(coordinates,window.search_radius_m);
            }
        }
        if(window.lazy_loading===2) {
            loaded_marker_bbox = null;
            schedule_viewport_markers_load();
        }
    }

    function show_search_radius_m() {
        if(geolocation.getTracking()) {
            var search_icon_w = 80;
            var filter_icon_r = 90;
            if(window.search_radius_m>=1 && window.search_radius_m<1000) {
                search_icon_w = 70;
                filter_icon_r = 80;
            } else if(window.search_radius_m>=1000 && window.search_radius_m<10000) {
                search_icon_w = 65;
                filter_icon_r = 75;
            } else if(window.search_radius_m>=10000 && window.search_radius_m<100000) {
                search_icon_w = 70;
                filter_icon_r = 80;
            } else if(window.search_radius_m>=100000 && window.search_radius_m<1000000) {
                search_icon_w = 75;
                filter_icon_r = 85;
            } else if(window.search_radius_m==-1) {
                search_icon_w = 50;
                filter_icon_r = 60;
            }
            if($(document).width()<600) {
                search_icon_w = search_icon_w + 4;
                filter_icon_r = filter_icon_r + 4;
            }
            $('.search_icon').css('width',search_icon_w+'px');
            $('.filter_icon').css('right',filter_icon_r+'px');
            $('.search_icon').css('text-align','right');
            $('.search_icon').css('padding-right','10px');
            if(window.search_radius_m==-1) {
                $('#search_radius_m').html('<i class="fa-solid fa-infinity"></i>');
            } else {
                $('#search_radius_m').html(convertMetersToKm(window.search_radius_m));
            }
            if(!$('.sheet_detail').is(':visible')) {
                $('#search_radius_m').show();
            }
        }
    }

    function hide_search_radius_m() {
        if($(document).width()>600) {
            $('.search_icon').css('width','32px');
            $('.filter_icon').css('right','34px');
        } else {
            $('.search_icon').css('width','36px');
            $('.filter_icon').css('right','36px');
        }
        $('.search_icon').css('text-align','center');
        $('.search_icon').css('padding-right','0px');
        $('#search_radius_m').hide();
    }

    window.enable_globe = function() {
        globe_mode = true;
        $('.measure-buttons').hide();
        $('#clear-btn').trigger('click');
        if(ol3d==null) {
            ol3d = new olcs.OLCesium({map: map,optimizeRendering: true});
            ol3d.getCesiumScene().fog.enabled = false;
            ol3d.getCesiumScene().skyAtmosphere.show = false;
            ol3d.getCesiumScene().globe.showGroundAtmosphere = false;
        }
        var empty_layer = new ol.layer.Vector({
            source: new ol.source.Vector({})
        });
        switch(current_map_style) {
            case 'default_style':
                map.getLayers().setAt(0, default_style_d);
                if(street_overlay_layer_d!==null) {
                    map.getLayers().setAt(1, street_overlay_layer_d);
                } else {
                    map.getLayers().setAt(1, empty_layer);
                }
                break;
            case 'satellite_style':
                map.getLayers().setAt(0, satellite_style_d);
                if(satellite_overlay_layer_d!==null) {
                    map.getLayers().setAt(1, satellite_overlay_layer_d);
                } else {
                    map.getLayers().setAt(1, empty_layer);
                }
                break;
        }
        ol3d.setEnabled(true);
        if(vector_geometries!=null) vector_geometries.setVisible(false);
        draw_geofence();
        $('.connections_icon').addClass('disabled2');
        jQuery.each(layerLines, function(index, layer) {
            if(layer!==undefined) layer.setVisible(false);
        });
        jQuery.each(layerMidpoint, function(index, layer) {
            if(layer!==undefined) layer.setVisible(false);
        });
        $('.globe_icon').addClass('active_c');
        $('.new_marker_btn').css({'opacity':0,'pointer-events':'none'});
        $('.live_tracking_btn').css({'opacity':0,'pointer-events':'none'});
        $('.live_tracking_stop_btn').css({'opacity':0,'pointer-events':'none'});
        $('#live_tracking_count').css({'opacity':0,'pointer-events':'none'});
    }

    window.disable_globe = function() {
        globe_mode = false;
        ol3d.setEnabled(false);
        $('.measure-buttons').show();
        var empty_layer = new ol.layer.Vector({
            source: new ol.source.Vector({})
        });
        switch(current_map_style) {
            case 'default_style':
                map.getLayers().setAt(0, default_style);
                if(street_overlay_layer!==null) {
                    map.getLayers().setAt(1, street_overlay_layer);
                } else {
                    map.getLayers().setAt(1, empty_layer);
                }
                map_view.setMaxZoom(window.street_maxzoom);
                map_view.setMinZoom(window.street_minzoom);
                break;
            case 'satellite_style':
                map.getLayers().setAt(0, satellite_style);
                if(satellite_overlay_layer!==null) {
                    map.getLayers().setAt(1, satellite_overlay_layer);
                } else {
                    map.getLayers().setAt(1, empty_layer);
                }
                map_view.setMaxZoom(window.satellite_maxzoom);
                map_view.setMinZoom(window.satellite_minzoom);
                break;
        }
        draw_geofence();
        if(vector_geometries!=null) vector_geometries.setVisible(true);
        if(connections_visible) {
            jQuery.each(layerLines, function (index, layer) {
                if(layer!==undefined) layer.setVisible(true);
            });
            jQuery.each(layerMidpoint, function (index, layer) {
                if(layer!==undefined) layer.setVisible(true);
            });
        }
        $('.connections_icon').removeClass('disabled2');
        $('.globe_icon').removeClass('active_c');
        $('.new_marker_btn').css({'opacity':1,'pointer-events':'initial'});
        $('.live_tracking_btn').css({'opacity':1,'pointer-events':'initial'});
        $('.live_tracking_stop_btn').css({'opacity':1,'pointer-events':'initial'});
        $('#live_tracking_count').css({'opacity':1,'pointer-events':'none'});
    }

    function get_weather(lat,lon,unit) {
        var url = 'https://api.open-meteo.com/v1/forecast?latitude='+lat+'&longitude='+lon+'&hourly=temperature_2m,weathercode&current_weather=true&temperature_unit='+unit;
        $.ajax({
            url: url,
            type: "GET",
            async: true,
            success: function (json) {
                try {
                    var current_weather = json.current_weather;
                    var temperature = current_weather.temperature;
                    var weathercode = current_weather.weathercode;
                    switch(unit) {
                        case 'celsius':
                            var symbol = '&#8451;';
                            break;
                        case 'fahrenheit':
                            var symbol = '&#8457;';
                            break;
                    }
                    $('.weather span').html(temperature+' '+symbol);
                    $('.weather #w_icon').css('background-image',"url('images/weather/"+weathercode+".svg')");
                    if(weathercode==0) {
                        $('.weather #w_icon').css('background-size','40px');
                        $('.weather #w_icon').css('background-position','3px 0');
                    } else {
                        $('.weather #w_icon').css('background-size','cover');
                        $('.weather #w_icon').css('background-position','unset');
                    }
                    $('.weather #w_icon').css('opacity',1);
                    $('.weather span').css('opacity',1);
                } catch (e) {}
            }
        });
    }

    window.alert_share_cookie_denied = function() {
        var alert_cookie = $.alert({
            theme: 'material',
            useBootstrap: false,
            boxWidth: '80%',
            type: 'dark',
            icon: 'fa-solid fa-cookie',
            title: window.viewer_labels.addtoany_social_share,
            content: window.viewer_labels.cookie_denied_msg,
            buttons: {
                cancel: {
                    text: window.viewer_labels.cancel,
                    action: function () {
                    }
                },
                accept: {
                    btnClass: 'btn-black',
                    text: window.viewer_labels.open_cookie_pref,
                    action: function () {
                        alert_cookie.close();
                        CookieConsent.showPreferences();
                    }
                }
            }
        });
    }

    window.toggle_share_map = function(force_open = false) {
        if($('.btn_share_map').hasClass('disabled_cookie')) {
            var alert_cookie = $.alert({
                theme: 'material',
                useBootstrap: false,
                boxWidth: '80%',
                type: 'dark',
                icon: 'fa-solid fa-cookie',
                title: window.viewer_labels.addtoany_social_share,
                content: window.viewer_labels.cookie_denied_msg,
                buttons: {
                    cancel: {
                        text: window.viewer_labels.cancel,
                        action: function () {
                        }
                    },
                    accept: {
                        btnClass: 'btn-black',
                        text: window.viewer_labels.open_cookie_pref,
                        action: function () {
                            alert_cookie.close();
                            CookieConsent.showPreferences();
                        }
                    }
                }
            });
        } else {
            if($('.btn_share_map').hasClass('open') && !force_open) {
                $('.btn_share_map').removeClass('open');
                $('.btn_share_map').removeClass('active_c');
                $('.share_popup').removeClass('show');
            } else {
                $('.btn_share_map').addClass('open');
                $('.btn_share_map').addClass('active_c');
                set_share_link();
                $('.share_popup').addClass('show');
            }
        }
        if(!force_open) {
            window.share_location_context = false;
            share_location_id_marker = null;
        }
    }

    window.set_share_link = function() {
        var url_map = removeURLParameters(location.href, ['nostat', 'ignore_embedded']);
        var url_base = location.href.split('/').slice(0, -1).join('/');
        if(window.friendly_url!=='') {
            if(share_location_id_marker!=null) {
                url_map = url_base+'/'+window.friendly_url+'?m='+share_location_id_marker;
            } else if(window.share_location_context) {
                url_map = url_base+'/'+window.friendly_url+'?coord='+coordinates_contextmenu.replace(' ','')+'&zoom='+share_location_zoom;
            } else if(window.marker_current_id!=0) {
                url_map = url_base+'/'+window.friendly_url+'?m='+window.marker_current_id;
            } else {
                url_map = url_base+'/'+window.friendly_url;
            }
        } else {
            if(share_location_id_marker!=null) {
                url_map = url_base+'/index.php?code='+window.code+'&m='+share_location_id_marker;
            } else if(window.share_location_context) {
                url_map = url_base+'/index.php?code='+window.code+'&coord='+coordinates_contextmenu.replace(' ','')+'&zoom='+share_location_zoom;
            } else if(window.marker_current_id!=0) {
                url_map = url_base+'/index.php?code='+window.code+'&m='+window.marker_current_id;
            } else {
                url_map = url_base+'/index.php?code='+window.code;
            }
        }
        $('#share_link').val(url_map);
        return url_map;
    }

    window.toggle_song = function() {
        if($('.btn_song_map').hasClass('open')) {
            $('.btn_song_map').removeClass('open');
            $('.btn_song_map').removeClass('active_c');
            $('.btn_song_map i').removeClass('fa-volume-down').addClass('fa-volume-mute');
            mute_audio();
        } else {
            $('.btn_song_map').addClass('open');
            $('.btn_song_map').addClass('active_c');
            $('.btn_song_map i').removeClass('fa-volume-mute').addClass('fa-volume-down');
            unmute_audio();
            if(first_song_play) {
                try {
                    audio_player.play().catch(function () {});
                } catch (e) {}
            }
        }
    }

    window.is_iOS = function() {
        return ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) || (navigator.userAgent.includes("Mac") && "ontouchend" in document)
    }

    function unmute_audio(duration=500) {
        if(selected_feature!==null) {
            var song = features[selected_feature].get('song');
            var song_volume = features[selected_feature].get('song_volume');
            var song_bg_volume = features[selected_feature].get('song_bg_volume');
            var song_play_bg = features[selected_feature].get('song_play_bg');
        } else {
            var song = '';
        }
        if(is_iOS()) {
            audio_player.muted = false;
            audio_player_marker.muted = false;
        }
        if(song!=null && song!='') {
            if(song_play_bg) {
                fadeVolume(audio_player_marker, song_volume, duration);
            } else {
                if($('.sheet_detail').is(':visible')) {
                    fadeVolume(audio_player, song_bg_volume, duration);
                    fadeVolume(audio_player_marker, song_volume, duration);
                } else {
                    fadeVolume(audio_player, main_song_bg_volume, duration);
                }
            }
        } else {
            fadeVolume(audio_player, main_song_bg_volume, duration);
        }
    }

    function mute_audio(duration=500) {
        if(is_iOS()) {
            fadeVolume(audio_player, 0, duration);
            fadeVolume(audio_player_marker, 0, duration);
            setTimeout(function() {
                audio_player.muted = true;
                audio_player_marker.muted = true;
            },duration)
        } else {
            fadeVolume(audio_player, 0, duration);
            fadeVolume(audio_player_marker, 0, duration);
        }
    }

    window.close_share_map = function() {
        if($('.btn_share_map').hasClass('open')) {
            $('.btn_share_map').removeClass('open');
            $('.btn_share_map').removeClass('active_c');
            $('.share_popup').removeClass('show');
            window.share_location_context = false;
            share_location_id_marker = null;
        }
    }

    document.addEventListener('click', function (event) {
        try {
            map.removeLayer(pin_marker_layer);
        } catch (e) {}
    });

    window.show_story = function () {
        if($('#story_container').hasClass('story_open')) {
            if(search_radius_enabled) {
                var coordinates = geolocation.getPosition();
                if (coordinates) {
                    check_marker_in_radius(coordinates,window.search_radius_m);
                }
            }
            $('.map_container').removeClass('map_story_open');
            $('#story_container').removeClass('story_open');
            $('.btn_story').removeClass('active_c');
            $('.new_marker_btn').css({'opacity':1,'pointer-events':'initial'});
            $('.live_tracking_btn').css({'opacity':1,'pointer-events':'initial'});
            $('.live_tracking_stop_btn').css({'opacity':1,'pointer-events':'initial'});
            $('#live_tracking_count').css({'opacity':1,'pointer-events':'none'});
            $('.nav_marker_prev').removeClass('disabled2');
            $('.nav_marker_next').removeClass('disabled2');
            if($('.featured_icon').hasClass('active_c')) {
                $('#featured_container').css('opacity',1);
                $('#featured_container .list_block_featured').css('pointer-events','initial');
            }
            $('#slider_categories_featured').css({'opacity':1,'pointer-events':'initial'});
            $('.featured_icon').removeClass('disabled');
            $('.popup').hide();
            $('.popup_c').hide();
            $('#story_container').html('<div id="story_content"></div>');
            map.removeControl(story);
            story_initialized = false;
        } else {
            if(search_radius_enabled) {
                check_marker_in_radius(null,-1);
                remove_radius();
            }
            $('.map_container').addClass('map_story_open');
            $('#story_container').addClass('story_open');
            $('.btn_story').addClass('active_c');
            $('.new_marker_btn').css({'opacity':0,'pointer-events':'none'});
            $('.live_tracking_btn').css({'opacity':0,'pointer-events':'none'});
            $('.live_tracking_stop_btn').css({'opacity':0,'pointer-events':'none'});
            $('#live_tracking_count').css({'opacity':0,'pointer-events':'none'});
            $('.nav_marker_prev').addClass('disabled2');
            $('.nav_marker_next').addClass('disabled2');
            $('.popup').hide();
            $('.popup_c').hide();
            $('#slider_categories_featured').css({'opacity':0,'pointer-events':'none'});
            close_sheet_detail();
            close_list_detail();
            close_categories();
            reset_categories();
            reset_search();
            if(!story_initialized) {
                initialize_story();
            } else {
                $('#featured_container').css('opacity',0);
                $('#featured_container .list_block_featured').css('pointer-events','none');
                $('.featured_icon').addClass('disabled');
                story.setChapter('start');
            }
        }
        var count_interval = 0;
        var interval_map_size = setInterval(function () {
            map.updateSize();
            if(count_interval==201) {
                clearInterval(interval_map_size);
            }
        },1);
    }

    function get_geoimages() {
        $.ajax({
            url: "ajax/get_geoimages.php",
            type: "POST",
            data: {
                id_map: window.id_map
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                var array_geoimages = rsp.geoimages;
                if (array_geoimages.length > 0) {
                    $.each(array_geoimages,function(index,geoimage) {
                        try {
                            var id = parseInt(geoimage.id);
                            var params = JSON.parse(geoimage.params);
                            var x = parseFloat(params.x);
                            var y = parseFloat(params.y);
                            var scale = parseFloat(params.scale);
                            var rotate = parseFloat(params.rotate);
                            var opacity = parseFloat(params.opacity);
                            var geoimg = new ol.layer.GeoImage({
                                name: "geoimage" + id,
                                opacity: opacity,
                                updateWhileAnimating: updateWhileAnimating,
                                updateWhileInteracting: updateWhileInteracting,
                                source: new ol.source.GeoImage({
                                    url: 'geoimages/' + geoimage.image,
                                    imageCenter: [x, y],
                                    imageScale: [scale, scale],
                                    imageRotate: rotate,
                                    projection: 'EPSG:3857',
                                })
                            });
                            geoimg.setZIndex(7);
                            map.addLayer(geoimg);
                        } catch (e) {
                            console.log(e);
                        }
                    });
                }
            }
        });
    }

    function convert_style_json(styleConfig) {
        try {
            styleConfig = JSON.parse(styleConfig);
        } catch (e) {
            return null;
        }
        const style_geodata = {};
        if('use_kml_style' in styleConfig) {
            style_geodata.use_kml_style = styleConfig.use_kml_style;
        } else {
            style_geodata.use_kml_style = 1;
        }
        for (const key in styleConfig) {
            const config = styleConfig[key];
            switch (config.type) {
                case 'Point':
                    style_geodata[key] = new ol.style.Style({
                        image: new ol.style.Circle({
                            fill: new ol.style.Fill({
                                color: config.style.fill.color,
                            }),
                            radius: config.style.radius,
                            stroke: new ol.style.Stroke({
                                color: config.style.stroke.color,
                                width: config.style.stroke.width,
                            }),
                        }),
                    });
                    break;
                case 'LineString':
                    style_geodata[key] = new ol.style.Style({
                        stroke: new ol.style.Stroke({
                            color: config.style.stroke.color,
                            width: config.style.stroke.width,
                        }),
                    });
                    break;
                case 'MultiLineString':
                    style_geodata[key] = new ol.style.Style({
                        stroke: new ol.style.Stroke({
                            color: config.style.stroke.color,
                            width: config.style.stroke.width,
                        }),
                    });
                    break;
                case 'Polygon':
                    style_geodata[key] = new ol.style.Style({
                        stroke: new ol.style.Stroke({
                            color: config.style.stroke.color,
                            width: config.style.stroke.width,
                        }),
                        fill: new ol.style.Fill({
                            color: config.style.fill.color,
                        }),
                    });
                    break;
                case 'MultiPolygon':
                    style_geodata[key] = new ol.style.Style({
                        stroke: new ol.style.Stroke({
                            color: config.style.stroke.color,
                            width: config.style.stroke.width,
                        }),
                        fill: new ol.style.Fill({
                            color: config.style.fill.color,
                        }),
                    });
                    break;
            }
        }
        return style_geodata;
    }

    window.geodataStyleCache = window.geodataStyleCache || {};
    function dynamicStyle(feature, style_geodata) {
        const geomType = feature.getGeometry().getType();
        const props = feature.getProperties();
        const radius = props['radius'] || '';
        const strokeColor = props['stroke'] || '';
        const strokeOpacity = props['stroke-opacity'] || '';
        const strokeWidth = props['stroke-width'] || '';
        const fillColor = props['fill'] || '';
        const fillOpacity = props['fill-opacity'] || '';
        const cacheKey = geomType + '_' + radius + '_' + strokeColor + '_' + strokeOpacity + '_' + strokeWidth + '_' + fillColor + '_' + fillOpacity;
        if (window.geodataStyleCache[cacheKey]) {
            return window.geodataStyleCache[cacheKey];
        }
        if (style_geodata === null) {
            style_geodata = {
                'Point': new ol.style.Style({
                    image: new ol.style.Circle({
                        fill: new ol.style.Fill({
                            color: 'rgba(255,255,0,0.4)',
                        }),
                        radius: 5,
                        stroke: new ol.style.Stroke({
                            color: 'rgb(255, 255, 0)',
                            width: 1,
                        }),
                    }),
                }),
                'LineString': new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: 'rgb(0,0,255)',
                        width: 3,
                    }),
                }),
                'MultiLineString': new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: 'rgb(0,255,0)',
                        width: 3,
                    }),
                }),
                'Polygon': new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: 'rgb(255, 0, 0)',
                        width: 3,
                    }),
                    fill: new ol.style.Fill({
                        color: 'rgba(255,0,0,0.1)',
                    }),
                }),
                'MultiPolygon': new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: 'rgb(255, 0, 0)',
                        width: 3,
                    }),
                    fill: new ol.style.Fill({
                        color: 'rgba(255,0,0,0.1)',
                    }),
                }),
            };
        }
        const defaultStyle = style_geodata[geomType];
        if (!defaultStyle) {
            console.warn(`No default style defined for geometry type: ${geomType}`);
            return new ol.style.Style();
        }
        let newStyle;
        if (geomType === 'Point') {
            newStyle = new ol.style.Style({
                image: new ol.style.Circle({
                    radius: props['radius'] || defaultStyle.getImage().getRadius(),
                    stroke: new ol.style.Stroke({
                        color: props['stroke'] ? hexToRgbA(props['stroke'], props['stroke-opacity'] || 0.5) : defaultStyle.getImage().getStroke().getColor(),
                        width: props['stroke-width'] || defaultStyle.getImage().getStroke().getWidth(),
                    }),
                    fill: new ol.style.Fill({
                        color: props['fill'] ? hexToRgbA(props['fill'], props['fill-opacity'] || 0.5) : defaultStyle.getImage().getFill().getColor(),
                    }),
                }),
            });
        } else if (geomType === 'LineString') {
            newStyle = new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: props['stroke'] ? hexToRgbA(props['stroke'], props['stroke-opacity'] || 0.5) : defaultStyle.getStroke().getColor(),
                    width: props['stroke-width'] || defaultStyle.getStroke().getWidth(),
                }),
            });
        } else if (geomType === 'Polygon' || geomType === 'MultiPolygon') {
            newStyle = new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: props['stroke'] ? hexToRgbA(props['stroke'], props['stroke-opacity'] || 0.5) : defaultStyle.getStroke().getColor(),
                    width: props['stroke-width'] || defaultStyle.getStroke().getWidth(),
                }),
                fill: new ol.style.Fill({
                    color: props['fill'] ? hexToRgbA(props['fill'], props['fill-opacity'] || 0.3) : defaultStyle.getFill().getColor(),
                }),
            });
        } else {
            newStyle = defaultStyle || new ol.style.Style();
        }
        window.geodataStyleCache[cacheKey] = newStyle;
        return newStyle;
    }

    function get_geodata() {
        $.ajax({
            url: "ajax/get_geodata.php",
            type: "POST",
            data: {
                language: window.language,
                id_map: window.id_map
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                geodatas = geodata_filter = rsp.geodata;
                if (geodatas.length > 0) {
                    draw_geodata(false);
                }
            }
        });
    }

    function draw_geodata(filter) {
        $('.loading_geodata').show();
        jQuery.each(layerGeodata, function(index, layer) {
            map.removeLayer(layer);
        });
        layerGeodata=[];
        if(geodata_filter.length==0) {
            $('.loading_geodata').hide();
        } else {
            $.each(geodata_filter,function(index,geodata) {
                if(geodata.style === '' || geodata.style === null || geodata.style === undefined) {
                    var style_geodata = null;
                    var use_kml_style = true;
                } else {
                    var style_geodata = convert_style_json(geodata.style);
                    if('use_kml_style' in style_geodata) {
                        var use_kml_style = (parseInt(style_geodata.use_kml_style)==1) ? true : false;
                    } else {
                        var use_kml_style = true;
                    }
                }
                try {
                    var extension = geodata.file.split('.').pop().toLowerCase();
                    switch(extension) {
                        case 'json':
                        case 'geojson':
                            layerGeodata[index] = new ol.layer.Vector({
                                updateWhileAnimating: updateWhileAnimating,
                                updateWhileInteracting: updateWhileInteracting,
                                renderBuffer: renderBuffer,
                                source: new ol.source.Vector({
                                    url: geodata.file,
                                    format: new ol.format.GeoJSON()
                                }),
                                style: function (feature) {
                                    return dynamicStyle(feature,style_geodata);
                                },
                                popupContent: geodata.content
                            });
                            add_geodata_to_map(index,filter);
                            break;
                        case 'kml':
                            layerGeodata[index] = new ol.layer.Vector({
                                updateWhileAnimating: updateWhileAnimating,
                                updateWhileInteracting: updateWhileInteracting,
                                renderBuffer: renderBuffer,
                                source: new ol.source.Vector({
                                    url: geodata.file,
                                    format: new KMLParser({ extractStyles: use_kml_style })
                                }),
                                style: function (feature) {
                                    return dynamicStyle(feature,style_geodata);
                                },
                                popupContent: geodata.content
                            });
                            add_geodata_to_map(index,filter);
                            break;
                        case 'kmz':
                            fetch(geodata.file)
                                .then(response => response.arrayBuffer())
                                .then(data => JSZip.loadAsync(data))
                                .then(async zip => {
                                    const kmlFiles = [];
                                    const assetMap = {};
                                    for (const relativePath in zip.files) {
                                        if (relativePath.toLowerCase().endsWith('.kml')) {
                                            kmlFiles.push(zip.files[relativePath]);
                                        } else {
                                            const file = zip.files[relativePath];
                                            if (!file.dir) {
                                                const blob = await file.async("blob");
                                                assetMap[relativePath] = URL.createObjectURL(blob);
                                            }
                                        }
                                    }
                                    if (kmlFiles.length === 0) {
                                        throw new Error("No .kml file found in the KMZ archive.");
                                    }
                                    const allFeatures = [];
                                    const kmlFormat = new KMLParser({ extractStyles: use_kml_style });
                                    for (const kmlFile of kmlFiles) {
                                        let kmlText = await kmlFile.async("string");
                                        for (const assetPath in assetMap) {
                                            const blobUrl = assetMap[assetPath];
                                            const regex = new RegExp(assetPath, 'gi');
                                            kmlText = kmlText.replace(regex, blobUrl);
                                        }
                                        const features = kmlFormat.readFeatures(kmlText, {
                                            dataProjection: 'EPSG:4326',
                                            featureProjection: map.getView().getProjection()
                                        });
                                        allFeatures.push(...features);
                                    }
                                    layerGeodata[index] = new ol.layer.Vector({
                                        updateWhileAnimating: updateWhileAnimating,
                                        updateWhileInteracting: updateWhileInteracting,
                                        renderBuffer: renderBuffer,
                                        source: new ol.source.Vector({
                                            features: allFeatures
                                        }),
                                        style: function (feature) {
                                            return dynamicStyle(feature, style_geodata);
                                        },
                                        popupContent: geodata.content
                                    });
                                    add_geodata_to_map(index,filter);
                                })
                                .catch(err => console.error("Error loading complex KMZ:", err));
                            break;
                        case 'gpx':
                            layerGeodata[index] = new ol.layer.Vector({
                                updateWhileAnimating: updateWhileAnimating,
                                updateWhileInteracting: updateWhileInteracting,
                                renderBuffer: renderBuffer,
                                source: new ol.source.Vector({
                                    url: geodata.file,
                                    format: new ol.format.GPX()
                                }),
                                style: function (feature) {
                                    return dynamicStyle(feature,style_geodata);
                                },
                                popupContent: geodata.content
                            });
                            add_geodata_to_map(index,filter);
                            break;
                        case 'zip':
                            loadshp({url: geodata.file, encoding: 'utf-8'}, function(geojson) {
                                const features = new ol.format.GeoJSON().readFeatures(
                                    geojson,
                                    {featureProjection: map.getView().getProjection()}
                                );
                                const vectorSource = new ol.source.Vector({
                                    features: features
                                });
                                layerGeodata[index] = new ol.layer.Vector({
                                    updateWhileAnimating: updateWhileAnimating,
                                    updateWhileInteracting: updateWhileInteracting,
                                    renderBuffer: renderBuffer,
                                    source: vectorSource,
                                    style: function (feature) {
                                        return dynamicStyle(feature,style_geodata);
                                    },
                                    popupContent: geodata.content
                                });
                                add_geodata_to_map(index,filter);
                            });
                            break;
                    }
                } catch (e) {
                    console.log(e);
                    $('.loading_geodata').hide();
                }
            });
        }
        if(globe_mode && geodata_filter.length>0) {
            ol3d.setEnabled(false);
            setTimeout(function() { ol3d.setEnabled(true); }, 10);
        }
    }

    function add_geodata_to_map(index,filter) {
        $('.loading_geodata').hide();
        layerGeodata[index].setZIndex(0);
        if(!filter && !map_initialized) layerGeodata[index].setOpacity(0);
        map.addLayer(layerGeodata[index]);
    }

    var html_story = '';
    function get_story() {
        $.ajax({
            url: "ajax/get_story.php",
            type: "POST",
            data: {
                language: window.language,
                id_map: window.id_map
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                var array_story = rsp.story;
                if(array_story.length>0) {
                    $('.btn_story').removeClass('hidden');
                    html_story = '<div class="chapter" name="start"><div class="ol-scroll-next"><span>'+window.viewer_labels.start_story+'</span></div></div>';
                    story_positions = {};
                    var first = true;
                    jQuery.each(array_story, function(index, story) {
                        var id_marker = story.id_marker;
                        var lat = story.lat;
                        var lon = story.lon;
                        var name = story.name;
                        var description = story.description;
                        var zoom = story.zoom;
                        var images = story.images;
                        var first_image = '';
                        if(images!='') {
                            var array_images = images.split(",");
                            if(array_images.length>0) {
                                first_image = array_images[0];
                            }
                        }
                        if(first) {
                            story_positions['start'] = { xy: ol.proj.fromLonLat([lon, lat]), z: zoom };
                            first = false;
                        }
                        story_positions[id_marker] = { xy: ol.proj.fromLonLat([lon, lat]), z: zoom };
                        if(first_image!='' && first_image!=null && first_image!=undefined) {
                            if (first_image.startsWith('media_')) {
                                var image = 'media/'+first_image;
                            } else {
                                var image = 'marker_images/'+first_image;
                            }
                            html_story += '<div class="chapter" name="'+id_marker+'"><h2>'+name+'</h2><img src="'+image+'"><p>'+description+'</p></div>';
                        } else {
                            html_story += '<div class="chapter" name="'+id_marker+'"><h2>'+name+'</h2><p>'+description+'</p></div>';
                        }
                    });
                    html_story += '<div class="ol-scroll-top"><span>'+window.viewer_labels.end_story+'</span></div>';
                    $('.btn_story').removeClass('disabled');
                }
            }
        });
    }

    function initialize_story() {
        $('#story_content').html(html_story).promise().done(function () {
            $('#story_container').addClass('force_display');
            story = new ol.control.Storymap({
                target: document.getElementById('story_container'),
                minibar: false
            });
            story.on('scrollto', function(e){
                $('.popup').hide();
                $('.popup_c').hide();
                close_sheet_detail();
                close_list_detail();
                close_categories();
                reset_categories();
                reset_search();
                $('#featured_container').css('opacity',0);
                $('#featured_container .list_block_featured').css('pointer-events','none');
                $('#slider_categories_featured').css({'opacity':0,'pointer-events':'none'});
                $('.featured_icon').addClass('disabled');
                $('#story_container .chapter').removeClass('select');
                $(e.element).addClass('select');
                map.getView().cancelAnimations();
                if (e.name==='start') {} else {
                    var duration = 1500;
                    map.getView().animate ({
                        center: story_positions[e.name].xy,
                        duration: duration
                    });
                    map.getView().animate ({
                        zoom: story_positions[e.name].z-1,
                        duration: duration/2
                    },{
                        zoom: story_positions[e.name].z,
                        duration: duration/2
                    });
                    setTimeout(function () {
                        var show_story_marker = function () {
                            for(var i=0;i<features.length;i++) {
                                var id = features[i].get('id_db');
                                if(id==e.name) {
                                    show_popup(features[i],true);
                                    return true;
                                }
                            }
                            return false;
                        };
                        if(!show_story_marker() && window.lazy_loading===2) {
                            $(window).off('sml:markers-loaded.story').one('sml:markers-loaded.story',show_story_marker);
                        }
                    },(duration+100));
                }
            });
            map.addControl(story);
            setTimeout(function () {
                $('#story_container').removeClass('force_display');
            },500);
            story_initialized = true;
        });
    }

    function show_popup(feature,one) {
        if(!window.ebable_popup) return;
        if(new_marker_mode) return;
        var coordinates = feature.getGeometry().getCoordinates();
        var position = map.getPixelFromCoordinate(coordinates);
        var x = position[0];
        var y = position[1];
        if(!$('.sheet_detail').is(':visible')) {
            if(one || globe_mode) {
                var description = feature.values_.description;
                var image = feature.values_.image;
                var title = feature.values_.name;
                var rating = feature.values_.rating;
                var num_reviews = feature.values_.num_reviews;
                var address = feature.values_.address;
                var view_directions = parseInt(feature.values_.view_directions);
                var view_review = parseInt(feature.values_.view_review);
                var view_share = parseInt(feature.values_.view_share);
                var view_popup = parseInt(feature.values_.view_popup);
                var popup_image_height = feature.values_.popup_image_height;
                var popup_background = feature.values_.popup_background;
                var popup_color = feature.values_.popup_color;
                var size = feature.values_.size;
                var id_categories = feature.values_.id_categories;
            } else {
                var description = feature.getProperties().features[0].values_.description;
                var image = feature.getProperties().features[0].values_.image;
                var title = feature.getProperties().features[0].values_.name;
                var rating = feature.getProperties().features[0].values_.rating;
                var num_reviews = feature.getProperties().features[0].values_.num_reviews;
                var address = feature.getProperties().features[0].values_.address;
                var view_directions = parseInt(feature.getProperties().features[0].values_.view_directions);
                var view_review = parseInt(feature.getProperties().features[0].values_.view_review);
                var view_share = parseInt(feature.getProperties().features[0].values_.view_share);
                var view_popup = parseInt(feature.getProperties().features[0].values_.view_popup);
                var popup_image_height = feature.getProperties().features[0].values_.popup_image_height;
                var popup_background = feature.getProperties().features[0].values_.popup_background;
                var popup_color = feature.getProperties().features[0].values_.popup_color;
                var size = feature.getProperties().features[0].values_.size;
                var id_categories = feature.getProperties().features[0].values_.id_categories;
            }
            if(!view_popup) return;
            $('.popup').css('background',hexToRgbA(popup_background,0.92));
            $('.popup').css('color',popup_color);
            $('.popup_icon .btn_direction_p').css('background',popup_color);
            $('.popup_icon .btn_direction_p').css('color',popup_background);
            if(image!='images/placeholder.jpg') {
                $('.popup_image').css('height',popup_image_height+'px');
                switch(getMediaType(image)) {
                    case 'image':
                        $('.popup_video').hide();
                        $('.popup_image').show();
                        if($('.popup_image').attr('src')!==image) {
                            $('.popup_image').attr('src',image);
                        }
                        break;
                    case 'video':
                        $('.popup_video').show();
                        $('.popup_image').hide();
                        image = image+'#t=2';
                        if($('.popup_video').attr('src')!==image) {
                            $('.popup_video').attr('src',image);
                            $('.popup_video')[0].load();
                        }
                        break;
                    case 'youtube':
                        $('.popup_video').hide();
                        $('.popup_image').show();
                        const ytId = getYouTubeId(image);
                        if (ytId) {
                            var thumb = `https://img.youtube.com/vi/${ytId}/hqdefault.jpg`;
                            if($('.popup_image').attr('src')!==thumb) {
                                $('.popup_image').attr('src',thumb);
                            }
                        }
                        break;
                    case 'vimeo':
                        $('.popup_video').hide();
                        $('.popup_image').show();
                        videoPromises.push(
                            new Promise((resolve) => {
                                fetch(`https://vimeo.com/api/oembed.json?url=${encodeURIComponent(image)}`)
                                    .then(r => r.json())
                                    .then(data => {
                                        if($('.popup_image').attr('src')!==data.thumbnail_url) {
                                            $('.popup_image').attr('src',data.thumbnail_url);
                                        }
                                        resolve();
                                    })
                                    .catch(() => resolve());
                            })
                        );
                        break;
                }
                $('.popup_title').css('margin-top',0);
                $('.popup_icon .btn_direction_p').css('margin-top','-2px');
            } else {
                $('.popup_image').hide();
                $('.popup_video').hide();
                $('.popup_title').css('margin-top','5px');
                $('.popup_icon .btn_direction_p').css('margin-top','1px');
            }
            $('.popup_title').html(title);
            $('.popup_description').html(htmlToText(description));
            var category_icons_html = parse_category_icons(id_categories);
            if(view_directions==1 && window.enable_popup_directions==1) {
                var coordinates = feature.getGeometry().getCoordinates();
                var lat_lon = ol.proj.transform(coordinates, 'EPSG:3857', 'EPSG:4326');
                $('.btn_direction_p').show();
                $('.btn_direction_p').attr('onclick','open_directions('+lat_lon[1]+','+lat_lon[0]+');');
                $('.popup_title').addClass('popup_title_w_d');
            } else {
                $('.btn_direction_p').hide();
                $('.popup_title').removeClass('popup_title_w_d');
            }
            if(view_review==1) {
                $('.popup_rating').show();
                var rating_html = '<span style="color: '+popup_color+'">'+rating.toFixed(1)+'</span>&nbsp;'+parse_stars(rating)+'&nbsp;<span>('+num_reviews+')&nbsp;&nbsp;'+category_icons_html+'</span>';
                var currentHTML = $('<div>').html($('.popup_rating').html()).html();
                var newHTML = $('<div>').html(rating_html).html();
                if (currentHTML !== newHTML) {
                    $('.popup_rating').html(rating_html);
                }
            } else {
                if(category_icons_html!='') {
                    $('.popup_rating').show();
                    var currentHTML = $('<div>').html($('.popup_rating').html()).html();
                    var newHTML = $('<div>').html(category_icons_html).html();
                    if (currentHTML !== newHTML) {
                        $('.popup_rating').html(category_icons_html);
                    }
                } else {
                    $('.popup_rating').hide();
                    $('.popup_rating').html('');
                }
            }
            if(view_share==1) {
                $('.share_section').show();
            } else {
                $('.share_section').hide();
            }
            $('.popup_address').html(address);
            if(one) {
                $('.popup').addClass('remain_visible');
                $('.popup').fadeIn(100);
            } else {
                $('.popup').removeClass('remain_visible');
                $('.popup').show();
            }
        }
        var w = $('.popup').width();
        var h = $('.popup').height();
        var m_size = size || window.markers_size || 1;
        var offset = 15 * m_size;
        if(y<=h+40) {
            $('.popup').css({'left':(x - (w/2))+'px','top':(y+offset)+'px'});
        } else {
            $('.popup').css({'left':(x - (w/2))+'px','top':(y-h-offset)+'px'});
        }
        manageCategoryOverflow('popup_rating');
    }

    function htmlToText(html) {
        var temp = document.createElement('div');
        temp.innerHTML = html;
        return temp.textContent;
    }

    function show_popup_c(feature) {
        if(new_marker_mode) return;
        var coordinates = feature.getGeometry().getCoordinates();
        var position = map.getPixelFromCoordinate(coordinates);
        var x = position[0];
        var y = position[1];
        if(!$('.sheet_detail').is(':visible')) {
            var title = feature.getProperties().title;
            var description = feature.getProperties().description;
            if(title=='' && description=='') return;
            $('.popup_c_title').html(title);
            $('.popup_c_description').html(description);
            $('.popup_c').show();
        }
        var w = $('.popup_c').width();
        var h = $('.popup_c').height();
        if(y<=h+40) {
            $('.popup_c').css({'left':(x - (w/2))+'px','top':(y+30)+'px'});
        } else {
            $('.popup_c').css({'left':(x - (w/2))+'px','top':(y-h-30)+'px'});
        }
    }

    function createCircle(center, radius) {
        var view = map.getView();
        var projection = view.getProjection();
        var resolutionAtEquator = view.getResolution();
        var pointResolution = ol.proj.getPointResolution(projection, resolutionAtEquator, center);
        var metersPerUnit = projection.getMetersPerUnit();
        var resolutionFactor = resolutionAtEquator / pointResolution;
        radius = (radius / metersPerUnit) * resolutionFactor;
        const circle = new ol.geom.Circle(center, radius);
        const circleFeature = new ol.Feature(circle);
        const circleStyle = new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'rgba(0, 0, 0, 0)',
            }),
            stroke: new ol.style.Stroke({
                color: 'blue',
                width: 1,
            }),
        });
        circleFeature.setStyle(circleStyle);
        return circleFeature;
    }

    function change_circle(center, radius) {
        if (radiusLayer && radiusLayer.getSource().getFeatures().length > 0) {
            var view = map.getView();
            var projection = view.getProjection();
            var resolutionAtEquator = view.getResolution();
            var pointResolution = ol.proj.getPointResolution(projection, resolutionAtEquator, center);
            var metersPerUnit = projection.getMetersPerUnit();
            var resolutionFactor = resolutionAtEquator / pointResolution;
            radius = (radius / metersPerUnit) * resolutionFactor;
            const circle = new ol.geom.Circle(center, radius);
            const circleFeature = radiusLayer.getSource().getFeatures()[0];
            circleFeature.setGeometry(circle);
            radiusLayer.getSource().changed();
        }
    }

    function create_radius(my_coords, radius_m) {
        if(radiusLayer==null) {
            const radiusFeature = createCircle(my_coords, radius_m);
            const radiusSource = new ol.source.Vector({
                features: [radiusFeature],
            });
            radiusLayer = new ol.layer.Vector({
                source: radiusSource,
            });
            radiusLayer.setZIndex(19);
            map.addLayer(radiusLayer);
        } else {
            change_circle(my_coords, radius_m);
        }
    }

    function remove_radius() {
        map.removeLayer(radiusLayer);
        radiusLayer=null;
    }

    function convertMetersToKm(meters) {
        if(window.unit_map=='miles') {
            return ((meters/1000)/1.609).toFixed(2) + ' ml';
        } else {
            if (meters >= 1000) {
                return (meters / 1000).toFixed(0) + ' km';
            } else {
                return meters + ' m';
            }
        }
    }

    function calculate_distance(my_position) {
        if(my_position!=false) {
            for(var i=0;i<features.length;i++) {
                var f_coord = features[i].getGeometry().getCoordinates();
                var line = new ol.geom.LineString([my_position, f_coord]);
                var distance = Math.round(line.getLength() * 100) / 100;
                features[i].values_.distance = distance;
            }
            adjust_distances();
            parse_html_list(true);
            $('.list_distance').show();
        } else {
            for(var i=0;i<features.length;i++) {
                features[i].values_.distance_html = '';
            }
            parse_html_list(true);
            $('.list_distance').hide();
        }
        if($('.list_detail').css('opacity')==0) {
            $('.list_detail').hide();
        }
    }

    function formatDistance(length) {
        if(window.unit_map=='miles') {
            return (Math.round(length / 1609.34 * 100) / 100) + ' miles';
        } else {
            if (length >= 1000) {
                length = (Math.round(length / 1000 * 100) / 100) + ' ' + 'km';
            } else {
                length = Math.round(length) + ' ' + 'm';
            }
            return length;
        }
    }

    window.toggle_categories = function () {
        close_list_detail();
        if($('.categories_div').is(':visible')) {
            $('.categories_div').hide();
            $('.categories_div').removeClass('open');
            $('.search_div').removeClass('open');
        } else {
            if(search_radius_enabled) {
                close_radius_m();
            }
            $('.categories_div').show();
            $('.categories_div').addClass('open');
            $('.search_div').addClass('open');
        }
    }

    window.close_categories = function () {
        $('.categories_div').hide();
        $('.categories_div').removeClass('open');
        $('.search_div').removeClass('open');
    }

    window.toggle_globe = function () {
        if($('.globe_icon').hasClass('active_c')) {
            disable_globe();
        } else {
            enable_globe();
        }
    }

    window.toggle_connections = function () {
        if($('.connections_icon').hasClass('active_c')) {
            connections_visible = false;
            $('.connections_icon').removeClass('active_c');
            jQuery.each(layerLines, function(index, layer) {
                if(layer!==undefined) layer.setVisible(false);
            });
            jQuery.each(layerMidpoint, function(index, layer) {
                if(layer!==undefined) layer.setVisible(false);
            });
        } else {
            connections_visible = true;
            $('.connections_icon').addClass('active_c');
            jQuery.each(layerLines, function(index, layer) {
                if(layer!==undefined) layer.setVisible(true);
            });
            jQuery.each(layerMidpoint, function(index, layer) {
                if(layer!==undefined) layer.setVisible(true);
            });
        }
    }

    window.toggle_featured = function () {
        if($('.featured_icon').hasClass('active_c')) {
            $('#featured_container').css('opacity',0);
            $('#featured_container .list_block_featured').css('pointer-events','none');
            $('.featured_icon').removeClass('active_c');
        } else {
            $('#featured_container').css('opacity',1);
            $('#featured_container .list_block_featured').css('pointer-events','initial');
            $('.featured_icon').addClass('active_c');
        }
    }

    window.hide_connections = function () {
        if($('.connections_icon').hasClass('active_c')) {
            $('.connections_icon').removeClass('active_c');
            jQuery.each(layerLines, function(index, layer) {
                if(layer!==undefined) layer.setVisible(false);
            });
            jQuery.each(layerMidpoint, function(index, layer) {
                if(layer!==undefined) layer.setVisible(false);
            });
        }
    }

    window.open_list_detail = function () {
        if(new_marker_mode) return;
        reset_selected_marker();
        $('.popup').removeClass('remain_visible');
        $('.filter_icon').css({'opacity':1,'pointer-events':'initial'});
        $('.categories_div').css({'opacity':1,'pointer-events':'initial'});
        $('.list_icon i').addClass('fa-bars').removeClass('fa-arrow-left');
        $('.list_detail').show();
        $('.list_detail').css('opacity',1);
        $('#list').show();
        $('.list_detail').addClass('open');
        $('.search_div').addClass('open');
        $('.sheet_detail').hide();
        $('.search_icon i').removeClass('fa-search').addClass('fa-times');
        $('.search_icon i').css('vertical-align','middle');
        $('.search_icon i').css('cursor','pointer');
        $('.search_icon i').attr('onclick','reset_search()');
        $('#searchbox').prop('disabled',false);
        $('#searchbox').removeClass('hide_p');
        $('.nav_marker_prev').removeClass('disabled');
        $('.nav_marker_next').removeClass('disabled');
        $('.popup').removeClass('remain_visible');
        $('.popup').hide();
        $('.popup_c').hide();
        $('#featured_container').css('opacity',0);
        $('#featured_container .list_block_featured').css('pointer-events','none');
        $('.featured_icon').addClass('disabled');
        if(song_selected_feature!==null) {
            var song_play_bg = features[song_selected_feature].get('song_play_bg');
        } else {
            var song_play_bg = 0;
        }
        if(!song_play_bg) {
            fadeVolume(audio_player_marker,0,500);
            if($('.btn_song_map').hasClass('open')) {
                fadeVolume(audio_player,main_song_bg_volume,500);
            }
        }
        if(window.tts_enable>0) {
            if(speechSynthesis!=undefined) speechSynthesis.cancel();
        }
        if(search_radius_enabled) {
            close_radius_m();
            show_search_radius_m();
        }
        setTimeout(function () {
            $('.categories_div').hide();
            $('.categories_div').removeClass('open');
            $('.list_icon').attr('onclick','close_list_detail();');
        },100);
        manageCategoryOverflow('list_rating');
        setTimeout(function () {
            $(window).trigger('resize');
            try {
                clusterize_list.refresh(true);
            } catch (e) {}
        },250);
    }

    window.open_sheet_detail = function (id_sel,click=false) {
        clearTimeout(timeout_change_resolution);
        map.removeLayer(pin_marker_layer);
        $('.list_block_featured').css('border','2px solid transparent');
        close_directions();
        if(new_marker_mode) return;
        if(!window.sheet_detail) return;
        $('.popup').removeClass('remain_visible');
        $('.popup').hide();
        $('.popup_c').hide();
        if(search_radius_enabled) {
            close_radius_m();
            hide_search_radius_m();
        }
        if(window.tts_enable>0) {
            if(speechSynthesis!=undefined) speechSynthesis.cancel();
        }
        for(var i=0;i<features.length;i++) {
            var id = features[i].get('id');
            features[i].set('selected',false);
            if(id==id_sel) {
                var id_db = features[i].get('id_db');
                window.marker_current_id = id_db;
                selected_feature = i;
                features[i].set('selected',true);
                break;
            }
        }
        get_tripadvisor_info(selected_feature);
        var active = features[selected_feature].get('active');
        var open_sheet = features[selected_feature].get('open_sheet');
        var type = features[selected_feature].get('type');
        var link = features[selected_feature].get('link');
        var song = features[selected_feature].get('song');
        var song_volume = features[selected_feature].get('song_volume');
        var song_bg_volume = features[selected_feature].get('song_bg_volume');
        if(link!='') {
            if (!link.startsWith('http')) {
                link = 'https://' + link;
            }
        } else {
            type = 'default';
        }
        var exit_f = false;
        if(active) {
            var id_db = features[selected_feature].get('id_db');
            $.ajax({
                url: "ajax/set_statistics.php",
                type: "POST",
                data: {
                    id: id_db
                },
                async: true
            });
            switch(type) {
                case 'link':
                    exit_f = true;
                    if(click) window.open(link, '_blank');
                    break;
                case 'link_same':
                    exit_f = true;
                    if(click) window.open(link, '_top');
                    break;
                case 'iframe':
                    exit_f = true;
                    var type = getMediaType(link);
                    switch(type) {
                        case 'youtube':
                            let ytConfig = {
                                src  : link,
                                touch: false,
                                smallBtn: false,
                                clickOutside: false
                            };
                            let ytStart = getYouTubeStartTime(link);
                            if (ytStart) {
                                ytConfig.youtube = { start: ytStart };
                            }
                            $.fancybox.open(ytConfig);
                            break;
                        case 'vimeo':
                            let vmConfig = {
                                src  : link,
                                touch: false,
                                smallBtn: false,
                                clickOutside: false
                            };
                            let vmStart = getVimeoStartTime(link);
                            if (vmStart) {
                                let vimeoIdMatch = link.match(/vimeo\.com\/(?:video\/)?(\d+)/);
                                if (vimeoIdMatch && vimeoIdMatch[1]) {
                                    vmConfig.src = 'https://player.vimeo.com/video/' + vimeoIdMatch[1] + '?autoplay=1#t=' + vmStart + 's';
                                    vmConfig.type = 'iframe';
                                }
                            }
                            $.fancybox.open(vmConfig);
                            break;
                        default:
                            $.fancybox.open({
                                src  : link,
                                type : 'iframe',
                                opts: {
                                    iframe: {
                                        attr: {
                                            allow: 'accelerometer; camera; display-capture; fullscreen; geolocation; gyroscope; magnetometer; microphone; midi; xr-spatial-tracking;'
                                        }
                                    }
                                },
                                touch: false,
                                smallBtn: false,
                                clickOutside: false
                            });
                            break;
                    }
            }
            if(globe_mode) {
                var source_layer = markers_source;
            } else {
                var source_layer = markers_source_cluster;
            }
            try {
                if(source_layer!==undefined) {
                    var all_features = source_layer.getFeatures();
                } else {
                    var all_features = [];
                }
            } catch (e) {
                var all_features = [];
            }
            for (var i = 0; i < all_features.length; i++) {
                var feature = all_features[i];
                if(globe_mode) {
                    var id_db = feature.values_.id_db;
                    var current_style = feature.values_.style;
                    var style_hover = feature.values_.style_hover;
                    var style_label = feature.values_.style_label;
                } else {
                    var id_db = feature.getProperties().features[0].values_.id_db;
                    var current_style = feature.getProperties().features[0].values_.style;
                    var style_hover = feature.getProperties().features[0].values_.style_hover;
                    var style_label = feature.getProperties().features[0].values_.style_label;
                }
                if(parseInt(id_db)==parseInt(window.marker_current_id)) {
                    if (style_hover!=null) {
                        if(current_style!==style_hover) {
                            if(style_label!=null) {
                                feature.setStyle([style_hover,style_label]);
                            } else {
                                feature.setStyle(style_hover);
                            }
                        }
                        if(globe_mode) {
                            feature.values_.style=style_hover;
                        } else {
                            feature.getProperties().features[0].values_.style=style_hover;
                        }
                    }
                    break;
                }
            }
            var open_b1 = features[selected_feature].get('open_b1');
            if(open_b1==1) {
                open_b1_content(selected_feature);
            }
            var coordinates = features[selected_feature].getGeometry().getCoordinates();
            var size = map.getSize();
            if(exit_f) {
                var w = size[0]/2;
                var h = size[1]/2;
            } else {
                if((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)){
                    var w = size[0]/2;
                    var h = size[1]/2-120;
                } else {
                    var w = size[0]/2+180;
                    var h = size[1]/2;
                }
            }
            const currentZoom = parseInt(map_view.getZoom());
            const featureZoom = features[selected_feature].get('selected_zoom');
            let durationZoom = features[selected_feature].get('duration_zoom');
            if(durationZoom==-1) durationZoom = window.duration_zoom;
            var targetZoom = currentZoom;
            if (featureZoom === -1 && window.selected_zoom !== 0 && currentZoom <= window.selected_zoom) {
                targetZoom = window.selected_zoom;
            } else if (featureZoom > 0 && currentZoom <= featureZoom) {
                targetZoom = featureZoom;
            }
            const resolution = map_view.getResolutionForZoom(targetZoom);
            const offsetX = w - size[0] / 2;
            const offsetY = h - size[1] / 2;
            const newCenter = [
                coordinates[0] - offsetX * resolution,
                coordinates[1] - offsetY * resolution
            ];
            map_view.animate({
                center: newCenter,
                zoom: targetZoom,
                duration: durationZoom,
                easing: ol.easing.easeOut
            });
            var song_play_bg = features[selected_feature].get('song_play_bg');
            if(song!=null && song!='') {
                if(audio_player_marker.src!==undefined && audio_player_marker.src!=='') {
                    var currentFile = audio_player_marker.src.split('/').pop().split('?')[0];
                } else {
                    var currentFile = "";
                }
                if (song !== currentFile) {
                    if (song.startsWith("song_")) {
                        audio_player_marker.src = "content/" + song;
                    } else {
                        audio_player_marker.src = song;
                    }
                    audio_player_marker.volume = 0;
                    audio_player_marker.loop = false;
                    if($('.btn_song_map').hasClass('open')) {
                        audio_player_marker.volume = song_volume;
                    }
                    audio_player_marker.onplay = function() {
                        if($('.btn_song_map').hasClass('open')) {
                            fadeVolume(audio_player,song_bg_volume,500);
                        }
                    }
                    audio_player_marker.addEventListener('ended', function() {
                        if($('.btn_song_map').hasClass('open')) {
                            fadeVolume(audio_player, main_song_bg_volume, 500);
                        }
                    }, false);
                    audio_player_marker.play().catch(function(error) {});
                } else {
                    if($('.btn_song_map').hasClass('open')) {
                        if(!song_play_bg) {
                            audio_player_marker.currentTime = 0;
                            audio_player_marker.play().catch(function(error) {});
                            fadeVolume(audio_player,song_bg_volume,500);
                        }
                        fadeVolume(audio_player_marker,song_volume,500);
                    }
                }
                if(song_play_bg) song_selected_feature = selected_feature;
            } else {
                if(song_selected_feature!==null) {
                    song_play_bg = features[song_selected_feature].get('song_play_bg');
                } else {
                    song_play_bg = 0;
                }
                if(!song_play_bg) {
                    fadeVolume(audio_player_marker,0,500);
                    if($('.btn_song_map').hasClass('open')) {
                        fadeVolume(audio_player,main_song_bg_volume,500);
                    }
                }
            }
            if(exit_f) {
                features[selected_feature].set('selected',false);
                reset_selected_marker();
                return;
            }
            if(open_sheet==1 && open_b1==0) {
                $('#searchbox').prop('disabled',true);
                $('#searchbox').addClass('hide_p');
                $('.nav_marker_prev').addClass('disabled');
                $('.nav_marker_next').addClass('disabled');
                $('.filter_icon').css({'opacity':0,'pointer-events':'none'});
                $('.categories_div').css({'opacity':0,'pointer-events':'none'});
                $('#featured_container').css('opacity',0);
                $('#featured_container .list_block_featured').css('pointer-events','none');
                $('.featured_icon').addClass('disabled');
                $('.list_icon i').removeClass('fa-bars').addClass('fa-arrow-left');
                $('.list_detail').hide();
                parse_html_sheet(selected_feature);
                if((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)){
                    if(window.sheet_mobile=='opened') {
                        resize_sheet_detail('down');
                    } else {
                        resize_sheet_detail('up');
                    }
                }
                $('.sheet_detail_container').animate({ scrollTop: 0 }, 'fast');
                $('.sheet_detail').animate({ scrollTop: 0 }, 'fast');
                $('.sheet_detail').show();
                $('.sheet_detail').addClass('open');
                $('.search_div').addClass('open');
                $('.search_icon i').removeClass('fa-search').addClass('fa-times');
                $('.search_icon i').css('vertical-align','middle');
                $('.search_icon i').css('cursor','pointer');
                $('.search_icon i').attr('onclick','reset_search()');
                hide_directions();
                setTimeout(function () {
                    $('.categories_div').hide();
                    $('.categories_div').removeClass('open');
                    $('.list_icon').attr('onclick','open_list_detail();');
                    markerSlider.reset();
                    adjust_minimized_image_height();
                },100);
            }
        }
    };

    function getYouTubeId(url) {
        if (!url || typeof url !== 'string') return null;
        const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
        const match = url.match(regExp);
        return (match && match[2].length === 11) ? match[2] : null;
    }

    function getVimeoId(url) {
        if (!url || typeof url !== 'string') return null;
        const regExp = /vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^\/]*)\/videos\/|album\/(?:\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/;
        const match = url.match(regExp);
        return match ? match[1] : null;
    }

    function getYouTubeStartTime(url) {
        try {
            let safeUrl = url.startsWith('http') ? url : 'https://' + url;
            let urlObj = new URL(safeUrl);
            let timeStr = urlObj.searchParams.get('t') || urlObj.searchParams.get('start');
            if (!timeStr) return null;
            let h = timeStr.match(/(\d+)h/) ? parseInt(timeStr.match(/(\d+)h/)[1], 10) * 3600 : 0;
            let m = timeStr.match(/(\d+)m/) ? parseInt(timeStr.match(/(\d+)m/)[1], 10) * 60 : 0;
            let s = timeStr.match(/(\d+)s/) ? parseInt(timeStr.match(/(\d+)s/)[1], 10) : 0;
            if (h > 0 || m > 0 || s > 0) {
                return h + m + s;
            }
            let parsedSeconds = parseInt(timeStr, 10);
            return isNaN(parsedSeconds) ? null : parsedSeconds;
        } catch (e) {
            return null;
        }
    }

    function getVimeoStartTime(url) {
        try {
            let safeUrl = url.startsWith('http') ? url : 'https://' + url;
            let urlObj = new URL(safeUrl);
            let timeStr = null;
            if (urlObj.hash && urlObj.hash.includes('t=')) {
                timeStr = urlObj.hash.split('t=')[1].split('&')[0];
            } else if (urlObj.searchParams.has('t')) {
                timeStr = urlObj.searchParams.get('t');
            }
            if (!timeStr) return null;
            let h = timeStr.match(/(\d+)h/) ? parseInt(timeStr.match(/(\d+)h/)[1], 10) * 3600 : 0;
            let m = timeStr.match(/(\d+)m/) ? parseInt(timeStr.match(/(\d+)m/)[1], 10) * 60 : 0;
            let s = timeStr.match(/(\d+)s/) ? parseInt(timeStr.match(/(\d+)s/)[1], 10) : 0;
            if (h > 0 || m > 0 || s > 0) {
                return h + m + s;
            }
            let parsedSeconds = parseInt(timeStr, 10);
            return isNaN(parsedSeconds) ? null : parsedSeconds;
        } catch (e) {
            return null;
        }
    }

    function getMediaType(resource) {
        if (!resource || typeof resource !== 'string') return 'unknown';
        if (getYouTubeId(resource)) return 'youtube';
        if (getVimeoId(resource)) return 'vimeo';
        const parts = resource.split('.');
        if (parts.length === 1) return 'unknown';
        const extension = parts.pop().toLowerCase().split('?')[0];
        const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
        const videoExtensions = ['mp4', 'avi', 'mov', 'mkv', 'flv', 'wmv', 'webm'];
        if (imageExtensions.includes(extension)) return 'image';
        if (videoExtensions.includes(extension)) return 'video';
        return 'unknown';
    }

    $(document.body).on('click', 'a.gallery-link', function (event) {
        if (blueimp.Gallery($('a.gallery-link'), {index: this})) {
            event.preventDefault();
        }
    });

    function parse_html_sheet(id) {
        window.id_marker_sel = features[id].get('id_db');
        var update_date = features[id].get('update_date');
        var name = features[id].get('name');
        var address = features[id].get('address');
        var image = features[id].get('image');
        var website = features[id].get('website');
        var website_caption = features[id].get('website_caption');
        var email = features[id].get('email');
        var phone = features[id].get('phone');
        var whatsapp = features[id].get('whatsapp');
        var hours = features[id].get('hours');
        var description = features[id].get('description');
        var images = features[id].get('images');
        var icon_b1 = features[id].get('icon_b1');
        var title_b1 = features[id].get('title_b1');
        var value_b1 = features[id].get('value_b1');
        var view_directions = parseInt(features[id].get('view_directions'));
        var view_street_view = parseInt(features[id].get('view_street_view'));
        var view_review = parseInt(features[id].get('view_review'));
        var view_add_photo = parseInt(features[id].get('view_add_photo'));
        var view_share = parseInt(features[id].get('view_share'));
        var can_edit_pending = parseInt(features[id].get('can_edit_pending'))===1;
        var distance_html = features[id].get('distance_html');
        var id_categories = features[id].get('id_categories');
        var box_warning = features[id].get('box_warning');
        try {
            $('#sheet_images').nanogallery2('destroy');
        } catch (e) {}
        var gallery_items = [];
        videoPromises = [];
        if (typeof images !== 'undefined' && Array.isArray(images)) {
            for (let i = 0; i < images.length; i++) {
                let img = images[i];
                if (!img) continue;
                let type = getMediaType(img);
                let tmp = {
                    ID: i,
                    kind: 'image',
                    type: type,
                    src: img,
                    srct: 'images/placeholder_video.jpg',
                };
                if (type === 'image') {
                    tmp.srct = img.replace("marker_images/", "marker_images/thumb/").replace("media/", "media/thumb/");
                } else if (type === 'youtube') {
                    const ytId = getYouTubeId(img);
                    if (ytId) {
                        tmp.srct = `https://img.youtube.com/vi/${ytId}/hqdefault.jpg`;
                    }
                    let startTime = getYouTubeStartTime(img);
                    if (startTime) {
                        tmp.customData = { provider: 'youtube',start: startTime };
                    }
                } else if (type === 'vimeo') {
                    let startTime = getVimeoStartTime(img);
                    if (startTime) {
                        tmp.customData = { provider: 'vimeo', start: startTime };
                    }
                    let vimeoIdMatch = img.match(/vimeo\.com\/(?:video\/)?(\d+)/);
                    if (vimeoIdMatch && vimeoIdMatch[1]) {
                        tmp.src = 'https://vimeo.com/' + vimeoIdMatch[1];
                    }
                    videoPromises.push(
                        new Promise((resolve) => {
                            fetch(`https://vimeo.com/api/oembed.json?url=${encodeURIComponent(img)}`)
                                .then(r => r.json())
                                .then(data => { tmp.srct = data.thumbnail_url; resolve(); })
                                .catch(() => resolve());
                        })
                    );
                } else if (type === 'video') {
                    videoPromises.push(
                        new Promise((resolve) => {
                            let video = document.createElement('video');
                            video.src = img;
                            video.muted = true;
                            video.playsInline = true;
                            video.crossOrigin = "anonymous";
                            video.style.display = "none";
                            document.body.appendChild(video);
                            video.onerror = function() {
                                video.remove();
                                resolve();
                            };
                            video.addEventListener('loadeddata', function() {
                                video.currentTime = 1;
                            });
                            video.addEventListener('seeked', function() {
                                let canvas = document.createElement('canvas');
                                let context = canvas.getContext('2d');
                                let aspect_ratio = video.videoWidth / video.videoHeight;
                                let minSize = 58;
                                if (aspect_ratio > 1) {
                                    canvas.width = minSize * aspect_ratio;
                                    canvas.height = minSize;
                                } else {
                                    canvas.width = minSize;
                                    canvas.height = minSize / aspect_ratio;
                                }
                                context.drawImage(video, 0, 0, canvas.width, canvas.height);
                                tmp.srct = canvas.toDataURL('image/jpeg');
                                video.remove();
                                canvas.remove();
                                resolve();
                            });
                            video.load();
                        })
                    );
                }
                gallery_items.push(tmp);
            }
            Promise.all(videoPromises).then(() => {});
        }
        if(image=='images/placeholder.jpg') {
            $('.sheet_detail_image').hide();
            $('.sheet_detail_video').hide();
        } else {
            switch(getMediaType(image)) {
                case 'image':
                    $('.sheet_detail_image').css('background-image','url("'+image+'")');
                    $('.sheet_detail_image').show();
                    $('.sheet_detail_video').hide();
                    break;
                case 'video':
                    $('.sheet_detail_video').attr('src',image);
                    $('.sheet_detail_image').hide();
                    $('.sheet_detail_video').show();
                    $('.sheet_detail_video')[0].currentTime = 0;
                    $('.sheet_detail_video')[0].play();
                    break;
                case 'youtube':
                    const ytId = getYouTubeId(image);
                    if (ytId) {
                        var thumb = `https://img.youtube.com/vi/${ytId}/hqdefault.jpg`;
                        $('.sheet_detail_image').css('background-image','url("'+thumb+'")');
                        $('.sheet_detail_image').show();
                        $('.sheet_detail_video').hide();
                    }
                    break;
                case 'vimeo':
                    videoPromises.push(
                        new Promise((resolve) => {
                            fetch(`https://vimeo.com/api/oembed.json?url=${encodeURIComponent(image)}`)
                                .then(r => r.json())
                                .then(data => {
                                    $('.sheet_detail_image').css('background-image','url("'+data.thumbnail_url+'")');
                                    $('.sheet_detail_image').show();
                                    $('.sheet_detail_video').hide();
                                    resolve();
                                })
                                .catch(() => resolve());
                        })
                    );
                    break;
            }
        }
        if(update_date=='') {
            $('#last_update_date').html('--');
            $('#last_update_container').hide();
        } else {
            $('#last_update_date').html(update_date);
            $('#last_update_container').show();
        }
        $('#store_name').html(name.toUpperCase());
        $('#box_warning').html(box_warning);
        if(box_warning=='') {
            $('#box_warning_container').hide();
        } else {
            $('#box_warning_container').css('display','flex');
        }
        if(id_categories=='' || (window.enable_categories==0 || window.enable_categories==3) || window.show_categories_marker==0) {
            $('#sheet_categories').hide();
            $('.sheet_detail_name').css('margin-top','10px');
        } else {
            $('#sheet_categories').show();
            var array_id_categories = id_categories.split(",");
            var html_categories = '';
            $.each(array_id_categories,function(index_category,id_category) {
                id_category = parseInt(id_category);
                var icon = mapping_categories_icon[id_category];
                var name = mapping_categories_name[id_category];
                if(icon!='') {
                    html_categories+='<div class="category_detail category-chip" style="display:inline-block">'+icon+' <span>'+name+'</span></div>';
                } else {
                    html_categories+='<div class="category_detail category-chip" style="display:inline-block"><span>'+name+'</span></div>';
                }
            });
            $('.sheet_detail_name').css('margin-top','5px');
            $('#sheet_categories').html(html_categories).promise().done(function() {});
        }
        if(address=='') {
            $('#store_address').parent().hide();
        } else {
            $('#store_address').parent().show();
            $('#store_address').html(address);
        }
        if(distance_html=='') {
            $('#store_distance').parent().hide();
        } else {
            $('#store_distance').parent().show();
            $('#store_distance').html(distance_html);
        }
        if(website=='') {
            $('#store_website').parent().hide();
        } else {
            $('#store_website').parent().show();
            if(website_caption=='') {
                $('#store_website').html('<a target="_blank" href="'+website+'">'+website+'</a>');
            } else {
                $('#store_website').html('<a target="_blank" href="'+website+'">'+website_caption+'</a>');
            }
        }
        if(email=='') {
            $('#store_email').parent().hide();
        } else {
            $('#store_email').parent().show();
            $('#store_email').html('<a target="_parent" href="mailto:'+email+'">'+email+'</a>');
        }
        if(phone=='') {
            $('#store_phone').parent().hide();
        } else {
            $('#store_phone').parent().show();
            $('#store_phone').html('<a target="_parent" href="tel:'+phone+'">'+phone+'</a>');
        }
        if(whatsapp=='' || whatsapp==null) {
            $('#store_whatsapp').parent().hide();
        } else {
            $('#store_whatsapp').parent().show();
            $('#store_whatsapp').html('<a target="_blank" href="https://wa.me/'+whatsapp.replace('+','')+'">'+whatsapp+'</a>');
        }
        if(hours=='') {
            $('#store_hours').parent().hide();
        } else {
            $('#store_hours').parent().show();
            $('#store_hours').html(hours);
        }
        if(description=='') {
            $('#store_description').parent().hide();
        } else {
            $('#store_description').parent().show();
            if(window.tts_enable>0) {
                var html_tts = '<div class="btn_tts btn_tts_control noselect" style="display: inline-grid; align-items: center; justify-items: center; min-width: 70px; padding: 2px 10px; margin-right: 5px; grid-template-columns: 1fr;">' +
                    '<div class="tts_action_start" style="grid-row: 1; grid-column: 1; width: 100%; text-align: center; transition: opacity 0.2s;"><i class="fa-solid fa-headphones"></i>  '+window.viewer_labels.listen+'</div>' +
                    '<div class="tts_state_playing" style="grid-row: 1; grid-column: 1; width: 100%; display: flex; justify-content: space-evenly; align-items: center; opacity: 0; pointer-events: none; transition: opacity 0.2s;">' +
                    '<div class="tts_action_pause" style="flex-grow: 1; text-align: center;"><i class="fa-solid fa-pause"></i></div>' +
                    '<div style="border-left: 1px solid rgba(255,255,255,0.4); height: 14px;"></div>' +
                    '<div class="tts_action_stop" style="flex-grow: 1; text-align: center;"><i class="fa-solid fa-stop"></i></div>' +
                    '</div>' +
                    '</div>';
            } else {
                var html_tts = '';
            }
            $('#store_description').html(description).promise().done(function() {
                $('#store_description p:first-child').prepend(html_tts);
                if(speechSynthesis!=undefined) {
                    var restoreAudio = function() {
                        if($('.btn_song_map').hasClass('open')) {
                            var song = features[selected_feature].get('song');
                            var song_volume = features[selected_feature].get('song_volume');
                            var song_bg_volume = features[selected_feature].get('song_bg_volume');
                            if(song!='' && song!=null) {
                                fadeVolume(audio_player,song_bg_volume,500);
                                fadeVolume(audio_player_marker,song_volume,500);
                            } else {
                                fadeVolume(audio_player,window.main_song_bg_volume,500);
                            }
                        }
                    };
                    var resetTTSUI = function() {
                        $('.tts_action_start').css({ 'opacity': '1', 'pointer-events': 'auto' });
                        $('.tts_state_playing').css({ 'opacity': '0', 'pointer-events': 'none' });
                        $('.tts_action_pause i').removeClass('fa-play').addClass('fa-pause');
                    };
                    $('.tts_action_start').on('click', function () {
                        speechSynthesis.cancel();
                        var utterance = new SpeechSynthesisUtterance(extractContent(description));
                        var voices = speechSynthesis.getVoices();
                        var selectedVoice = voices.find(voice => voice.lang.toLowerCase() === window.lang_code_2.toLowerCase());
                        if (selectedVoice) {
                            utterance.voice = selectedVoice;
                        } else {
                            utterance.voice = voices[0];
                        }
                        utterance.onend = function() {
                            restoreAudio();
                            resetTTSUI();
                        };
                        utterance.onerror = function(e) {
                            if (e.error !== 'canceled') {
                                restoreAudio();
                                resetTTSUI();
                            }
                        };
                        if($('.btn_song_map').hasClass('open')) {
                            fadeVolume(audio_player,0.01,500);
                            fadeVolume(audio_player_marker,0,500);
                        }
                        speechSynthesis.speak(utterance);
                        $('.tts_action_start').css({ 'opacity': '0', 'pointer-events': 'none' });
                        $('.tts_state_playing').css({ 'opacity': '1', 'pointer-events': 'auto' });
                    });
                    $('.tts_action_pause').on('click', function() {
                        if (speechSynthesis.speaking) {
                            if (speechSynthesis.paused) {
                                speechSynthesis.resume();
                                $(this).find('i').removeClass('fa-play').addClass('fa-pause');
                            } else {
                                speechSynthesis.pause();
                                $(this).find('i').removeClass('fa-pause').addClass('fa-play');
                            }
                        }
                    });
                    $('.tts_action_stop').on('click', function() {
                        speechSynthesis.cancel();
                        restoreAudio();
                        resetTTSUI();
                    });
                }
            });
        }
        try {
            var placeholders = JSON.parse(window.field_placeholders);
        } catch (e) {
            var placeholders = [];
        }
        for(var k=1; k<=20; k++) {
            var icon_e = features[id].get('icon_e'+k);
            var name_e = features[id].get('name_e'+k);
            var field_e = features[id].get('field_e'+k);
            if(field_e=='' || field_e==undefined || field_e==null) {
                $('#field_e'+k).parent().hide();
            } else {
                $('#field_e'+k).parent().show();
                $('#icon_e'+k+' i').removeClass().addClass(icon_e);
                $('#field_e'+k).html(field_e);
            }
            if(name_e=='' || name_e==undefined || name_e==null) {
                if(placeholders[k]!==undefined) {
                    $('#icon_e'+k+' i').attr('title',placeholders[k]);
                }
            } else {
                $('#icon_e'+k+' i').attr('title',name_e);
            }
        }
        $('.btn_add_photo_small').addClass('hide');
        if(gallery_items.length==0) {
            if(view_add_photo==1) {
                $('#sheet_images').parent().parent().show();
                $('.btn_add_photo_small').removeClass('hide');
            } else {
                $('#sheet_images').parent().parent().hide();
            }
        } else {
            $('#sheet_images').html('<i class="fas fa-spin fa-circle-notch"></i>');
            $('#sheet_images').parent().parent().show();
            if(videoPromises.length==0) {
                $('#sheet_images').nanogallery2({
                    imageTransition: 'swipe',
                    thumbnailAlignment: (window.rtl==1) ? 'right' : 'left',
                    thumbnailHeight: 58,
                    thumbnailWidth: 58,
                    thumbnailBorderVertical: 0,
                    thumbnailBorderHorizontal: 0,
                    thumbnailGutterWidth: 5,
                    thumbnailGutterHeight: 5,
                    galleryDisplayMode: 'rows',
                    galleryMaxRows: 2,
                    items: gallery_items,
                    viewerHideToolsDelay: 30000,
                    viewerToolbar: {
                        display: true,
                        autoMinimize: false,
                        standard: 'label'
                    },
                    viewerTools: {
                        topLeft: 'pageCounter, playPauseButton',
                        topRight: 'zoomButton, closeButton'
                    },
                    fnGalleryRenderEnd: function() {
                        if(view_add_photo==1) {
                            $('.btn_add_photo_small').removeClass('hide');
                        }
                    },
                    fnImgDisplayed: function(item) {
                        if (item && item.customData && item.customData.start && item.customData.provider) {
                            var $iframe = $('iframe.nGY2ViewerMedia');
                            if ($iframe.length > 0) {
                                var currentSrc = $iframe.attr('src');
                                if (item.customData.provider === 'youtube') {
                                    if (currentSrc.indexOf('start=') === -1) {
                                        var ytSeparator = currentSrc.indexOf('?') === -1 ? '?' : '&';
                                        $iframe.attr('src', currentSrc + ytSeparator + 'start=' + item.customData.start);
                                    }
                                }
                                else if (item.customData.provider === 'vimeo') {
                                    if (currentSrc.indexOf('#t=') === -1) {
                                        currentSrc = currentSrc.split('#')[0];
                                        var vmSeparator = currentSrc.indexOf('?') === -1 ? '?' : '&';
                                        var newSrc = currentSrc + vmSeparator + 'forceReload=1#t=' + item.customData.start + 's';
                                        $iframe.attr('src', newSrc);
                                    }
                                }
                            }
                        }
                    }
                });
            } else {
                Promise.all(videoPromises).then(() => {
                    $('#sheet_images').nanogallery2({
                        imageTransition: 'swipe',
                        thumbnailAlignment: (window.rtl==1) ? 'right' : 'left',
                        thumbnailHeight: 58,
                        thumbnailWidth: 58,
                        thumbnailBorderVertical: 0,
                        thumbnailBorderHorizontal: 0,
                        thumbnailGutterWidth: 5,
                        thumbnailGutterHeight: 5,
                        galleryDisplayMode: 'rows',
                        galleryMaxRows: 2,
                        items: gallery_items,
                        viewerHideToolsDelay: 30000,
                        viewerToolbar: {
                            display: true,
                            autoMinimize: false,
                            standard: 'label'
                        },
                        viewerTools: {
                            topLeft: 'pageCounter, playPauseButton',
                            topRight: 'zoomButton, closeButton'
                        },
                        fnGalleryRenderEnd: function() {
                            if(view_add_photo==1) {
                                $('.btn_add_photo_small').removeClass('hide');
                            }
                        },
                        fnImgDisplayed: function(item) {
                            if (item && item.customData && item.customData.start && item.customData.provider) {
                                var $iframe = $('iframe.nGY2ViewerMedia');
                                if ($iframe.length > 0) {
                                    var currentSrc = $iframe.attr('src');
                                    if (item.customData.provider === 'youtube') {
                                        if (currentSrc.indexOf('start=') === -1) {
                                            var ytSeparator = currentSrc.indexOf('?') === -1 ? '?' : '&';
                                            $iframe.attr('src', currentSrc + ytSeparator + 'start=' + item.customData.start);
                                        }
                                    }
                                    else if (item.customData.provider === 'vimeo') {
                                        if (currentSrc.indexOf('#t=') === -1) {
                                            currentSrc = currentSrc.split('#')[0];
                                            var vmSeparator = currentSrc.indexOf('?') === -1 ? '?' : '&';
                                            var newSrc = currentSrc + vmSeparator + 'forceReload=1#t=' + item.customData.start + 's';
                                            $iframe.attr('src', newSrc);
                                        }
                                    }
                                }
                            }
                        }
                    });
                });
            }
        }
        var coordinates = features[id].getGeometry().getCoordinates();
        var lat_lon = ol.proj.transform(coordinates, 'EPSG:3857', 'EPSG:4326');
        if(!can_edit_pending && view_directions==1) {
            $('.btn_direction').show();
            $('.btn_direction').attr('onclick','open_directions('+lat_lon[1]+','+lat_lon[0]+');');
        } else {
            $('.btn_direction').hide();
        }
        if(!can_edit_pending && view_street_view==1) {
            $('.btn_streetview').show();
            $('.btn_streetview').attr('onclick','open_streetview('+lat_lon[1]+','+lat_lon[0]+');');
        } else {
            $('.btn_streetview').hide();
        }
        if(!can_edit_pending && view_review==1) {
            $('.btn_review').show();
            $('.review-section').show();
            get_reviews();
        } else {
            $('.btn_review').hide();
            $('.review-section').hide();
        }
        if(can_edit_pending) {
            $('.btn_edit_own_marker').show();
            $('.btn_delete_own_marker').show();
            $('#report_issue_div').hide();
        } else {
            $('.btn_edit_own_marker').hide();
            $('.btn_delete_own_marker').hide();
            if(!$('#report_issue_div').hasClass('hidden')) {
                $('#report_issue_div').show();
            }
        }
        if(!can_edit_pending && view_add_photo == 1) {
            $('.btn_add_photo').show();
            $('.btn_add_photo_small').show();
        } else {
            $('.btn_add_photo').hide();
            $('.btn_add_photo_small').hide();
        }
        var current_total = features[id].get('total_images') || 0;
        var can_add_photo = false;
        if (!can_edit_pending && view_add_photo === 1) {
            if (window.marker_images_num === -1) {
                can_add_photo = true;
            } else if (window.marker_images_num > 0 && current_total < window.marker_images_num) {
                can_add_photo = true;
            }
        }
        if (can_add_photo) {
            $('.btn_add_photo').show();
            $('.btn_add_photo_small').show();
        } else {
            $('.btn_add_photo').hide();
            $('.btn_add_photo_small').hide();
        }
        if(!can_edit_pending && view_share==1) {
            $('.share_section').show();
        } else {
            $('.share_section').hide();
        }
        try {
            $('.btn_custom_1').tooltipster('destroy');
        } catch (e) {}
        if(!can_edit_pending && value_b1!='') {
            if(title_b1!='') {
                if(title_b1.includes('[button_title]')) {
                    title_b1 = title_b1.replace('[button_title]','');
                    $('.btn_custom_1').html(title_b1);
                } else {
                    $('.btn_custom_1').attr('title',title_b1);
                    $('.btn_custom_1').tooltipster({
                        delay: 10,
                        hideOnClick: true,
                        position: 'bottom',
                        theme: 'tooltipster-borderless'
                    });
                }
            }
            $('.btn_custom_1 i').removeClass().addClass(icon_b1);
            if(value_b1.includes('[function]')) {
                value_b1 = value_b1.replace('[function]','');
                $('.btn_custom_1').attr('onclick',value_b1);
            } else {
                $('.btn_custom_1').attr('onclick','open_modal_custom_content('+id+')');
            }
            $('.btn_custom_1').show();
        } else {
            $('.btn_custom_1').hide();
        }
        try {
            $('.features_icon_e i').tooltipster('destroy');
        } catch (e) {}
        $('.features_icon i').tooltipster({
            delay: 10,
            hideOnClick: true,
            position: 'top',
            theme: 'tooltipster-borderless'
        });
    }

    function extractContent(s) {
        var span = document.createElement('span');
        span.innerHTML = s;
        return span.textContent || span.innerText;
    };

    window.open_b1_content = function(id) {
        open_modal_custom_content(id);
    }

    window.open_modal_custom_content = function (id) {
        var value_b1 = features[id].get('value_b1');
        if (value_b1.startsWith("http")) {
            window.open(value_b1, "_blank");
        } else {
            if(value_b1.includes('iframe')) {
                var style = "padding:0 !important;width:calc(100% - 80px);height:calc(100% - 80px);";
            } else {
                var style = '';
            }
            value_b1 = '<div style="'+style+'" class="custom_content_b1">' + value_b1 + '</div>';
            $.fancybox.open({
                src  : value_b1,
                type : 'html',
                touch: false,
                smallBtn: false,
                clickOutside: false
            });
        }
    }

    window.open_directions = function(lat,lon) {
        window.directions_dest_lat = lat;
        window.directions_dest_lon = lon;
        window.custom_end_lat = null;
        window.custom_end_lon = null;
        window.route_waypoints = [];
        window.render_waypoints();
        $('#btn_reset_end_map').hide();
        $('#direction_end_point').val('');
        switch(window.direction_map) {
            case 'google':
                const userAgent = navigator.userAgent || navigator.vendor || window.opera;
                if (/android/i.test(userAgent)) {
                    const geoUri = `geo:0,0?q=${lat},${lon}`;
                    window.location.assign(geoUri);
                } else {
                    try {
                        if(geolocation.getTracking()) {
                            var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
                            window.open('https://www.google.com/maps/dir/' + my_lat_lon[1] + ',' + my_lat_lon[0] + '/' + lat + ',' + lon, '_blank');
                        } else {
                            window.open('https://www.google.com/maps/dir/?api=1&destination=' + lat + ',' + lon, '_blank');
                        }
                    } catch (e) {
                        window.open('https://www.google.com/maps/dir/?api=1&destination=' + lat + ',' + lon, '_blank');
                    }
                }
                break;
            case 'bing':
                try {
                    if(geolocation.getTracking()) {
                        var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
                        window.open('https://bing.com/maps/default.aspx?Rtp=pos.'+my_lat_lon[1]+'_'+my_lat_lon[0]+'~pos.'+lat+'_'+lon, '_blank');
                    } else {
                        if (navigator.geolocation) {
                            navigator.geolocation.getCurrentPosition(function(position) {
                                var my_lat = position.coords.latitude;
                                var my_lon = position.coords.longitude;
                                window.open('https://bing.com/maps/default.aspx?Rtp=pos.'+my_lat+'_'+my_lon+'~pos.'+lat+'_'+lon, '_blank');
                            });
                        } else {
                            window.open('https://bing.com/maps/default.aspx?Rtp=~pos.'+lat+'_'+lon, '_blank');
                        }
                    }
                } catch (e) {
                    window.open('https://bing.com/maps/default.aspx?Rtp=~pos.'+lat+'_'+lon, '_blank');
                }
                break;
            case 'baidu':
                try {
                    if(geolocation.getTracking()) {
                        var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
                        window.open('http://api.map.baidu.com/direction?origin=latlng:'+my_lat_lon[1]+','+my_lat_lon[0]+'|name:'+my_lat_lon[1]+','+my_lat_lon[0]+'&destination=latlng:'+lat+','+lon+'|name:'+lat+','+lon+'&mode=driving&region=none&output=html', '_blank');
                    } else {
                        if (navigator.geolocation) {
                            navigator.geolocation.getCurrentPosition(function(position) {
                                var my_lat = position.coords.latitude;
                                var my_lon = position.coords.longitude;
                                window.open('http://api.map.baidu.com/direction?origin=latlng:'+my_lat+','+my_lon+'|name:'+my_lat+','+my_lon+'&destination=latlng:'+lat+','+lon+'|name:'+lat+','+lon+'&mode=driving&region=none&output=html', '_blank');
                            });
                        } else {
                            window.open('http://api.map.baidu.com/direction?destination=latlng:'+lat+','+lon+'|name:'+lat+','+lon+'&mode=driving&region=none&output=html', '_blank');
                        }
                    }
                } catch (e) {
                    window.open('http://api.map.baidu.com/direction?destination=latlng:'+lat+','+lon+'|name:'+lat+','+lon+'&mode=driving&region=none&output=html', '_blank');
                }
                break;
            case 'yandex':
                try {
                    if(geolocation.getTracking()) {
                        var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
                        window.open('https://yandex.ru/maps/?rtext='+my_lat_lon[1]+','+my_lat_lon[0]+'~'+lat+','+lon, '_blank');
                    } else {
                        if (navigator.geolocation) {
                            navigator.geolocation.getCurrentPosition(function(position) {
                                var my_lat = position.coords.latitude;
                                var my_lon = position.coords.longitude;
                                window.open('https://yandex.ru/maps/?rtext='+my_lat+','+my_lon+'~'+lat+','+lon, '_blank');
                            });
                        } else {
                            window.open('https://yandex.ru/maps/?rtext=~'+lat+','+lon, '_blank');
                        }
                    }
                } catch (e) {
                    window.open('https://yandex.ru/maps/?rtext=~'+lat+','+lon, '_blank');
                }
                break;
            case 'openrouteservice':
                var profile = 'driving-car';
                $('.direction_profile').removeClass('direction_profile_active');
                $('.direction_profile[data-profile="'+profile+'"]').addClass('direction_profile_active');
                $('.sheet_detail').hide();
                if(song_selected_feature!==null) {
                    var song_play_bg = features[song_selected_feature].get('song_play_bg');
                } else {
                    var song_play_bg = 0;
                }
                if(!song_play_bg) {
                    fadeVolume(audio_player_marker,0,500);
                    if($('.btn_song_map').hasClass('open')) {
                        fadeVolume(audio_player,main_song_bg_volume,500);
                    }
                    if(window.tts_enable>0) {
                        if(speechSynthesis!=undefined) speechSynthesis.cancel();
                    }
                }
                close_categories();
                $('.direction_detail').show();
                $('.direction_detail').addClass('open');
                if ((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)) {
                    resize_direction_detail('up');
                }
                $('.search_icon i').removeClass('fa-search').addClass('fa-times');
                $('.search_icon i').css('vertical-align','middle');
                $('.search_icon i').css('cursor','pointer');
                $('.search_icon i').attr('onclick','close_directions()');
                $('.list_icon').css({'opacity':0,'pointer-events':'none'});
                $('#searchbox').prop('disabled', true);
                $('#searchbox').addClass('hide_p');
                $('.btn_story').addClass('disabled');
                $('.nav_marker_prev').addClass('disabled');
                $('.nav_marker_next').addClass('disabled');
                $('.filter_icon').css({'opacity':0,'pointer-events':'none'});
                $('#direction_loading').show();
                $('.search_div').addClass('open');
                $('#direction_detail_div').hide();
                if (window.custom_start_lat != null && window.custom_start_lon != null) {
                    open_ors_directions(profile, window.custom_start_lat, window.custom_start_lon);
                } else if(geolocation.getTracking()) {
                    var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
                    open_ors_directions(profile, my_lat_lon[1], my_lat_lon[0]);
                } else {
                    if (navigator.geolocation) {
                        navigator.geolocation.getCurrentPosition(function(position) {
                            open_ors_directions(profile, position.coords.latitude, position.coords.longitude);
                        });
                    }
                }
                break;
        }
    }

    function open_ors_directions(profile,s_lat,s_lon) {
        var actual_s_lat = (window.custom_start_lat != null) ? window.custom_start_lat : s_lat;
        var actual_s_lon = (window.custom_start_lon != null) ? window.custom_start_lon : s_lon;
        if (window.custom_end_lat != null && window.custom_end_lon != null) {
            get_ors_directions(profile, actual_s_lat, actual_s_lon, window.custom_end_lat, window.custom_end_lon);
            return;
        }
        var marker_found = false;
        for(var i=0;i<features.length;i++) {
            var id = features[i].get('id_db');
            if(id==window.marker_current_id && window.marker_current_id != 0 && window.marker_current_id != null) {
                var name_marker = features[i].get('name');
                var address_marker = features[i].get('address');
                var d_lat = parseFloat(features[i].get('latitude'));
                var d_lon = parseFloat(features[i].get('longitude'));
                if ($('#direction_end_point').val() == '') {
                    if(address_marker=='') {
                        $('#direction_end_point').val(name_marker);
                    } else {
                        $('#direction_end_point').val(name_marker+', '+address_marker);
                    }
                }
                get_ors_directions(profile, actual_s_lat, actual_s_lon, d_lat, d_lon);
                marker_found = true;
                break;
            }
        }
        if (!marker_found && window.directions_dest_lat != null && window.directions_dest_lon != null) {
            if ($('#direction_end_point').val() == '') {
                window.positionToAddress_end_point(window.directions_dest_lat, window.directions_dest_lon);
            }
            get_ors_directions(profile, actual_s_lat, actual_s_lon, window.directions_dest_lat, window.directions_dest_lon);
        }
    }

    window.change_ors_direction = function(profile) {
        try {
            ajax_directions.abort();
        } catch (e) {}
        $('.direction_profile').removeClass('direction_profile_active');
        $('.direction_profile[data-profile="'+profile+'"]').addClass('direction_profile_active');
        try {
            map.removeLayer(direction_layer);
        } catch (e) {}
        if(geolocation.getTracking()) {
            var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
            var my_lat = my_lat_lon[1];
            var my_lon = my_lat_lon[0];
            open_ors_directions(profile,my_lat,my_lon);
        } else {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function(position) {
                    var my_lat = position.coords.latitude;
                    var my_lon = position.coords.longitude;
                    open_ors_directions(profile,my_lat,my_lon);
                });
            }
        }
    }

    var ajax_directions;
    function get_ors_directions(profile, s_lat, s_lon, d_lat, d_lon) {
        $('#direction_loading').hide();
        $('#direction_detail_div').show();
        try { map.removeLayer(direction_layer); } catch (e) {}
        try { map.removeLayer(window.stepHighlightLayer); } catch (e) {}
        $('#direction_duration').html('<i class="fas fa-spin fa-circle-notch"></i>');
        $('#direction_length').html('<i class="fas fa-spin fa-circle-notch"></i>');
        $('#direction_steps').empty();
        const requestData = {
            profile: profile,
            s_lat: s_lat,
            s_lon: s_lon,
            d_lat: d_lat,
            d_lon: d_lon,
            language: window.language.substring(0, 2),
            waypoints: (window.route_waypoints || []).filter(wp => wp.lat != null && wp.lon != null)
        };
        ajax_directions = new AbortController();
        var signal = ajax_directions.signal;
        fetch('ajax/get_directions.php', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(requestData),
            signal: signal
        }).then(response => response.json()).then(data => {
            if (data && data.error) {
                $('#direction_duration').html(data.error.message);
                $('#direction_length').html('--');
            } else {
                var routeCoordinates = data.features[0].geometry.coordinates;
                var transformedCoordinates = routeCoordinates.map(coord =>
                    ol.proj.transform(coord, 'EPSG:4326', 'EPSG:3857')
                );
                window.currentRouteCoords = transformedCoordinates;
                var way_points_indices = data.features[0].properties.way_points;
                var total_points = way_points_indices.length;

                var startStyle = new ol.style.Style({
                    image: new ol.style.Circle({ radius: 10, fill: new ol.style.Fill({ color: 'green' }), stroke: new ol.style.Stroke({ color: 'white', width: 2 }) }),
                    text: new ol.style.Text({ text: 'A', font: 'bold 10px Arial', fill: new ol.style.Fill({ color: 'white' }) })
                });
                var endStyle = new ol.style.Style({
                    image: new ol.style.Circle({ radius: 10, fill: new ol.style.Fill({ color: 'red' }), stroke: new ol.style.Stroke({ color: 'white', width: 2 }) }),
                    text: new ol.style.Text({ text: String.fromCharCode(64 + total_points), font: 'bold 10px Arial', fill: new ol.style.Fill({ color: 'white' }) })
                });
                var startPoint = new ol.Feature({ geometry: new ol.geom.Point(transformedCoordinates[way_points_indices[0]]) });
                var endPoint = new ol.Feature({ geometry: new ol.geom.Point(transformedCoordinates[way_points_indices[total_points - 1]]) });
                startPoint.setStyle(startStyle);
                endPoint.setStyle(endStyle);
                var routeBorderStyle = new ol.style.Style({
                    stroke: new ol.style.Stroke({ color: 'white', width: 9 })
                });
                var routeLineStyle = new ol.style.Style({
                    stroke: new ol.style.Stroke({ color: 'blue', width: 5 })
                });
                var route = new ol.Feature({ geometry: new ol.geom.LineString(transformedCoordinates) });
                route.setStyle([routeBorderStyle, routeLineStyle]);
                var features_to_add = [route, startPoint, endPoint];
                for(var i = 1; i < total_points - 1; i++) {
                    var wp_coord = transformedCoordinates[way_points_indices[i]];
                    var wpStyle = new ol.style.Style({
                        image: new ol.style.Circle({ radius: 9, fill: new ol.style.Fill({ color: 'orange' }), stroke: new ol.style.Stroke({ color: 'white', width: 2 }) }),
                        text: new ol.style.Text({ text: String.fromCharCode(65 + i), font: 'bold 10px Arial', fill: new ol.style.Fill({ color: 'white' }) })
                    });
                    var wpFeature = new ol.Feature({ geometry: new ol.geom.Point(wp_coord) });
                    wpFeature.setStyle(wpStyle);
                    features_to_add.push(wpFeature);
                }
                direction_layer = new ol.layer.Vector({
                    source: new ol.source.Vector({ features: features_to_add })
                });
                direction_layer.setZIndex(30);
                map.addLayer(direction_layer);
                var totalDuration = data.features[0].properties.summary.duration;
                var totalDistance = data.features[0].properties.summary.distance;
                var hours = Math.floor(totalDuration / 3600);
                var minutes = Math.floor((totalDuration % 3600) / 60);
                var formattedDuration = hours > 0 ? `${hours} h ${minutes} min` : `${minutes} min`;
                var formattedLength = '';
                if (window.unit_map === 'miles') {
                    formattedLength = (totalDistance / 1609.34).toFixed(1) + ' mi';
                } else {
                    formattedLength = (totalDistance / 1000).toFixed(1) + ' km';
                }
                $('#direction_duration').html(formattedDuration);
                $('#direction_length').html(formattedLength);
                var segments = data.features[0].properties.segments;
                var steps_html = '';
                segments.forEach(function(segment, seg_idx) {
                    var start_letter = String.fromCharCode(65 + seg_idx);
                    var end_letter = String.fromCharCode(66 + seg_idx);
                    var steps = segment.steps;
                    if(steps && steps.length > 0) {
                        steps.forEach(function(step) {
                            var dist = step.distance;
                            var dist_str = '';
                            if(dist > 0) {
                                if (window.unit_map === 'miles') {
                                    var dist_miles = dist / 1609.34;
                                    dist_str = dist_miles < 0.1 ? Math.round(dist * 3.28084) + ' ft' : dist_miles.toFixed(1) + ' mi';
                                } else {
                                    dist_str = dist >= 1000 ? (dist / 1000).toFixed(1) + ' km' : Math.round(dist) + ' m';
                                }
                            }
                            var icon_class = 'fas fa-arrow-up';
                            switch(step.type) {
                                case 0: icon_class = 'fas fa-arrow-left'; break;
                                case 1: icon_class = 'fas fa-arrow-right'; break;
                                case 2: icon_class = 'fas fa-reply'; break;
                                case 3: icon_class = 'fas fa-share'; break;
                                case 4: icon_class = 'fas fa-angle-left'; break;
                                case 5: icon_class = 'fas fa-angle-right'; break;
                                case 6: icon_class = 'fas fa-arrow-up'; break;
                                case 7: case 8: icon_class = 'fas fa-arrows-rotate'; break;
                                case 9: case 14: icon_class = 'fas fa-arrow-rotate-left'; break;
                                case 10: icon_class = 'fas fa-flag-checkered'; break;
                                case 11: icon_class = 'fas fa-chevron-up'; break;
                                case 12: icon_class = 'fas fa-chevron-left'; break;
                                case 13: icon_class = 'fas fa-chevron-right'; break;
                            }
                            var icon_html = '<i class="'+icon_class+'"></i>';
                            if (step.type === 11) {
                                if (seg_idx === 0) {
                                    icon_html = '<div style="background-color:green; color:white; width:20px; height:20px; border-radius:50%; line-height:20px; margin: 0 auto; font-weight:bold; font-size:12px;">' + start_letter + '</div>';
                                }
                            } else if (step.type === 10) {
                                var bg_color = (seg_idx === segments.length - 1) ? 'red' : 'orange';
                                icon_html = '<div style="background-color:'+bg_color+'; color:white; width:20px; height:20px; border-radius:50%; line-height:20px; margin: 0 auto; font-weight:bold; font-size:12px;">' + end_letter + '</div>';
                            }
                            var start_idx = step.way_points[0];
                            var end_idx = step.way_points[1];
                            steps_html += '<div class="direction_step" onclick="highlight_step(' + start_idx + ', ' + end_idx + ')">';
                            steps_html += '<div class="step_icon">' + icon_html + '</div>';
                            steps_html += '<div class="step_instruction">' + step.instruction + '</div>';
                            if(dist_str != '') {
                                steps_html += '<div class="step_distance">' + dist_str + '</div>';
                            }
                            steps_html += '</div>';
                        });
                    }
                });
                $('#direction_steps').html(steps_html);
                var padding_fit = [50, 50, 50, 50];
                if ((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)) {
                    padding_fit = [360, 50, 50, 50];
                } else {
                    padding_fit = [50, 50, 50, 420];
                }
                map.getView().fit(route.getGeometry(), { padding: padding_fit, duration: 500 });
            }
        }).catch(error => {
            if (error.name !== 'AbortError') {
                $('#direction_duration').html('Error');
                $('#direction_length').html('--');
            }
        });
    }

    window.highlight_step = function(start_idx, end_idx) {
        if (!window.currentRouteCoords) return;
        var segmentCoords = window.currentRouteCoords.slice(start_idx, end_idx + 1);
        if (segmentCoords.length === 0) return;
        if (segmentCoords.length === 1) {
            segmentCoords.push(segmentCoords[0]);
        }
        var line = new ol.geom.LineString(segmentCoords);
        try { map.removeLayer(window.stepHighlightLayer); } catch(e) {}
        window.stepHighlightLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [new ol.Feature({ geometry: line })]
            }),
            style: new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: '#00D61D',
                    width: 7
                })
            }),
            zIndex: 35
        });
        map.addLayer(window.stepHighlightLayer);
        var padding_fit = [50, 50, 50, 50];
        if ((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)) {
            if ($('.direction_detail').hasClass('direction_detail_maximized')) {
                resize_direction_detail('up');
            }
            padding_fit = [360, 50, 50, 50];
        } else {
            padding_fit = [50, 50, 50, 420];
        }
        map.getView().fit(line.getExtent(), {
            padding: padding_fit,
            duration: 500,
            maxZoom: 18
        });
    };

    window.close_directions = function() {
        try {
            ajax_directions.abort();
        } catch (e) {}
        try {
            map.removeLayer(direction_layer);
        } catch (e) {}
        hide_directions();
    }

    function hide_directions() {
        $('.direction_detail').hide();
        $('.direction_detail').removeClass('open');
        $('.btn_story').removeClass('disabled');
        $('.nav_marker_prev').removeClass('disabled');
        $('.nav_marker_next').removeClass('disabled');
        $('.list_icon').css({'opacity':1,'pointer-events':'initial'});
        if (window.marker_current_id != 0 && window.marker_current_id != null) {
            $('.sheet_detail').show();
            $('.search_icon i').attr('onclick','reset_search()');
        } else {
            $('.sheet_detail').hide();
            $('.search_div').removeClass('open');
            $('#searchbox').prop('disabled', false);
            $('#searchbox').removeClass('hide_p');
            $('.filter_icon').css({'opacity':1,'pointer-events':'initial'});
            if ($('#searchbox').val() == '') {
                $('.search_icon i').removeClass('fa-times').addClass('fa-search');
                $('.search_icon i').css('vertical-align','unset');
                $('.search_icon i').css('cursor','default');
                $('.search_icon i').attr('onclick','');
            } else {
                $('.search_icon i').attr('onclick','reset_search()');
            }
        }
        try { map.removeLayer(window.stepHighlightLayer); } catch(e) {}
    }

    window.open_streetview = function (lat,lon) {
        switch(window.streetview_map) {
            case 'google':
                window.open('https://www.google.com/maps/@?api=1&map_action=pano&viewpoint='+lat+','+lon+'&heading=0&pitch=0&fov=80','_blank');
                break;
            case 'bing':
                window.open('https://www.bing.com/mapspreview?cp='+lat+'~'+lon+'&lvl=17&dir=0&pi=-0&style=x&v=2&sV=1','_blank');
                break;
            case 'yandex':
                window.open('https://yandex.ru/maps/?panorama[point]='+lat+','+lon,'_blank');
                break;
        }
    }

    window.close_list_detail = function () {
        $('.list_icon i').addClass('fa-bars').removeClass('fa-arrow-left');
        $('.list_icon').attr('onclick','open_list_detail();');
        $('.list_detail').hide();
        $('.list_detail').removeClass('open');
        $('.search_div').removeClass('open');
        if($('#searchbox').val()=='') {
            $('.search_icon i').removeClass('fa-times').addClass('fa-search');
            $('.search_icon i').css('vertical-align','unset');
            $('.search_icon i').css('cursor','default');
            $('.search_icon i').attr('onclick','');
        }
        if($('.featured_icon').hasClass('active_c')) {
            $('#featured_container').css('opacity',1);
            $('#featured_container .list_block_featured').css('pointer-events','initial');
        }
        $('.featured_icon').removeClass('disabled');
    }

    window.close_sheet_detail = function () {
        var reload_without_selected_marker = false;
        if(window.lazy_loading===2 && selected_feature!==null && features[selected_feature]) {
            var current_bbox = get_marker_viewport_bbox(false);
            var selected_lon = parseFloat(features[selected_feature].get('longitude'));
            var selected_lat = parseFloat(features[selected_feature].get('latitude'));
            reload_without_selected_marker = current_bbox && (
                selected_lon<current_bbox.min_lon || selected_lon>current_bbox.max_lon ||
                selected_lat<current_bbox.min_lat || selected_lat>current_bbox.max_lat
            );
        }
        $('.filter_icon').css({'opacity':1,'pointer-events':'initial'});
        $('.categories_div').css({'opacity':1,'pointer-events':'initial'});
        $('.list_icon i').addClass('fa-bars').removeClass('fa-arrow-left');
        $('.sheet_detail').hide();
        $('.sheet_detail').removeClass('open');
        $('.search_div').removeClass('open');
        $('#searchbox').prop('disabled',false);
        $('#searchbox').removeClass('hide_p');
        $('.nav_marker_prev').removeClass('disabled');
        $('.nav_marker_next').removeClass('disabled');
        if($('.featured_icon').hasClass('active_c')) {
            $('#featured_container').css('opacity',1);
            $('#featured_container .list_block_featured').css('pointer-events','initial');
        }
        $('.featured_icon').removeClass('disabled');
        if(search_radius_enabled) show_search_radius_m();
        if(song_selected_feature!==null) {
            var song_play_bg = features[song_selected_feature].get('song_play_bg');
        } else {
            var song_play_bg = 0;
        }
        if(!song_play_bg) {
            fadeVolume(audio_player_marker,0,500);
            if($('.btn_song_map').hasClass('open')) {
                fadeVolume(audio_player,main_song_bg_volume,500);
            }
        }
        if(window.tts_enable>0) {
            if(speechSynthesis!=undefined) speechSynthesis.cancel();
        }
        window.marker_current_id = 0;
        reset_selected_marker();
        if(reload_without_selected_marker) {
            loaded_marker_bbox = null;
            schedule_viewport_markers_load();
        }
    }

    function reset_selected_marker() {
        window.marker_current_id = 0;
        if(window.map_mode=='default') {
            if(globe_mode) {
                var source_layer = markers_source;
            } else {
                var source_layer = markers_source_cluster;
            }
            try {
                if(source_layer!==undefined) {
                    var all_features = source_layer.getFeatures();
                } else {
                    var all_features = [];
                }
            } catch (e) {
                var all_features = [];
            }
            all_features.forEach(feature => {
                if(globe_mode) {
                    var current_style = feature.values_.style;
                    var style = feature.values_.style_default;
                    var style_hover = feature.values_.style_hover;
                    var style_label = feature.values_.style_label;
                } else {
                    var current_style = feature.getProperties().features[0].values_.style;
                    var style = feature.getProperties().features[0].values_.style_default;
                    var style_hover = feature.getProperties().features[0].values_.style_hover;
                    var style_label = feature.getProperties().features[0].values_.style_label;
                    if(feature.getProperties().features.length>1) {
                        style_hover=null;
                    }
                }
                if (style_hover!=null) {
                    if(style!==current_style) {
                        if(style_label!=null) {
                            feature.setStyle([style,style_label]);
                        } else {
                            feature.setStyle(style);
                        }
                    }
                    if(globe_mode) {
                        feature.values_.style=style;
                    } else {
                        feature.getProperties().features[0].values_.style=style;
                    }
                }
            });
        }
    }

    window.fix_feature_pos = function () {
        if(selected_feature != null) {
            var coordinates = features[selected_feature].getGeometry().getCoordinates();
            var size = map.getSize();
            if((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)){
                var w = size[0]/2;
                var h = size[1]/2+120;
            } else {
                var w = size[0]/2+180;
                var h = size[1]/2;
            }
            const currentZoom = parseInt(map_view.getZoom());
            const featureZoom = features[selected_feature].get('selected_zoom');
            if (featureZoom === -1 && window.selected_zoom !== 0 && currentZoom <= window.selected_zoom) {
                map_view.setZoom(window.selected_zoom);
            } else if (featureZoom > 0 && currentZoom <= featureZoom) {
                map_view.setZoom(featureZoom);
            }
            map_view.centerOn(coordinates, size, [w,h]);
        }
    }

    var search_timer;
    function parse_html_list(update=false) {
        var tmp_list = features;
        array_list = [];
        for(var i=0;i<tmp_list.length;i++) {
            if(parseInt(tmp_list[i].get('visible_search'))==0) continue;
            var id = tmp_list[i].get('id');
            var id_db = tmp_list[i].get('id_db');
            var name = tmp_list[i].get('name');
            var address = tmp_list[i].get('address');
            var image = tmp_list[i].get('image');
            var image_thumb = image.replace('marker_images/','marker_images/thumb/').replace('media/','media/thumb/');
            var active = tmp_list[i].get('active');
            var id_categories = tmp_list[i].get('id_categories');
            var description = features[id].get('description');
            var rating = tmp_list[id].get('rating');
            var num_reviews = tmp_list[id].get('num_reviews');
            var view_review = tmp_list[id].get('view_review');
            var distance_html = tmp_list[id].get('distance_html');
            var website = tmp_list[id].get('website');
            var website_caption = tmp_list[id].get('website_caption');
            var email = tmp_list[id].get('email');
            var phone = tmp_list[id].get('phone');
            var whatsapp = tmp_list[id].get('whatsapp');
            var hours = tmp_list[id].get('hours');
            var distance = tmp_list[id].get('distance');
            var can_edit_pending = parseInt(tmp_list[id].get('can_edit_pending') || 0)===1;
            var pending_badge_html = can_edit_pending ? '<span class="list_pending_badge"><i class="fas fa-clock"></i> '+viewer_escape_html(window.viewer_labels.pending_validation)+'</span>' : '';
            var list_block_class = can_edit_pending ? 'list_block own_pending_marker_list' : 'list_block';
            if(active) {
                var opacity = 1.0;
            } else {
                var opacity = 0.4;
            }
            switch(getMediaType(image_thumb)) {
                case 'image':
                    var background = 'background-image:url('+image_thumb+');';
                    var video_bg = '';
                    break;
                case 'video':
                    var background = '';
                    var video_bg = '<video playsinline muted src="'+image+'#t=2" />';
                    break;
                case 'youtube':
                    const ytId = getYouTubeId(image);
                    if (ytId) {
                        var thumb = `https://img.youtube.com/vi/${ytId}/hqdefault.jpg`;
                        var background = 'background-image:url('+thumb+');';
                        var video_bg = '';
                    }
                    break;
                case 'vimeo':
                    videoPromises.push(
                        new Promise((resolve) => {
                            fetch(`https://vimeo.com/api/oembed.json?url=${encodeURIComponent(image)}`)
                                .then(r => r.json())
                                .then(data => {
                                    var background = 'background-image:url('+data.thumbnail_url+');';
                                    var video_bg = '';
                                    resolve();
                                })
                                .catch(() => resolve());
                        })
                    );
                    break;
            }
            var category_icons_html = parse_category_icons(id_categories);
            if(window.enable_reviews && view_review==1) {
                var star_html = '<span>'+rating.toFixed(1)+'</span>&nbsp;'+parse_stars(rating)+'&nbsp;<span>('+num_reviews+')</span>';
                var list_elem = '<div id="list_block_'+id+'" data-id_categories="'+id_categories+'" style="opacity: '+opacity+'" onmouseenter="highlight_marker('+id+')" onclick="open_sheet_detail('+id+',true);" class="'+list_block_class+'">\n' +
                    '            <div class="list_image noselect" style="'+background+';">'+video_bg+'</div>\n' +
                    '            <div class="list_name noselect">'+name+pending_badge_html+'</div>\n' +
                    '            <div id="list_rating_'+id_db+'" class="list_rating noselect">'+star_html+'&nbsp;&nbsp;'+category_icons_html+'</div>\n' +
                    '            <div class="list_address noselect">'+address+'</div>\n' +
                    '            <div style="color:'+window.darker_color_hex+';" class="list_distance noselect"><i id="distance_'+id+'">'+distance_html+'</i></div>\n' +
                    '        </div>';
            } else {
                var list_elem = '<div id="list_block_'+id+'" data-id_categories="'+id_categories+'" style="opacity: '+opacity+'" onmouseenter="highlight_marker('+id+')" onclick="open_sheet_detail('+id+',true);" class="'+list_block_class+'">\n' +
                    '            <div class="list_image noselect" style="'+background+';">'+video_bg+'</div>\n' +
                    '            <div class="list_name noselect">'+name+pending_badge_html+'</div>\n' +
                    ((category_icons_html!='') ? '<div class="list_rating noselect">'+category_icons_html+'</div>\n' : '') +
                    '            <div class="list_address noselect">'+address+'</div>\n' +
                    '            <div style="color:'+window.darker_color_hex+';" class="list_distance noselect"><i id="distance_'+id+'">'+distance_html+'</i></div>\n' +
                    '        </div>';
            }
            var values = [
                (name || '').toString().toLowerCase(),
                (address || '').toString().toLowerCase(),
                (description || '').toString().toLowerCase(),
                (website || '').toString().toLowerCase(),
                (website_caption || '').toString().toLowerCase(),
                (email || '').toString().toLowerCase(),
                (phone || '').toString().toLowerCase(),
                (whatsapp || '').toString().toLowerCase(),
                (hours || '').toString().toLowerCase()
            ];
            for(var k=1; k<=20; k++) {
                var field_e = features[id].get('field_e'+k);
                if(field_e != null && field_e !== '') {
                    values.push(field_e.toString().toLowerCase());
                }
            }
            var mapping_categories = {};
            if(categories.length>0) {
                $.each(categories,function(index_c,cat_c) {
                    mapping_categories[cat_c.id] = cat_c.name;
                });
                $.each(id_categories.split(","),function(index_c,id_cat_c) {
                    if(id_cat_c!==undefined && id_cat_c!==null && id_cat_c!=='') {
                        values.push(mapping_categories[parseInt(id_cat_c)].toLowerCase());
                    }
                });
            }
            array_list.push({
                id: id,
                force: false,
                values: values,
                id_categories: id_categories,
                cat_active: true,
                markup: list_elem,
                distance: distance,
                active: true,
                visible: true
            });
        }
        var list_visible = true;
        if(!update) {
            $('.list_detail').css('opacity',0).show();
        } else {
            if(!$('.list_detail').is(':visible')) {
                $('.list_detail').css('opacity',0).show();
                list_visible = false;
            }
        }
        if(window.order_by_distance==1 && update && geolocation.getTracking()) {
            array_list.sort((a, b) => a.distance - b.distance);
        }
        clusterize_list = new Clusterize({
            rows: filterRows(array_list,true),
            scrollId: 'list_area',
            contentId: 'list',
            rows_in_block: 20
        });
        var search = document.getElementById('searchbox');
        var onSearch = function() {
            var count=0;
            for(var i = 0, ii = array_list.length; i < ii; i++) {
                if(array_list[i].force && search.value.length>=3)  {
                    suitable=true;
                } else {
                    var suitable = false;
                    for(var j = 0, jj = array_list[i].values.length; j < jj; j++) {
                        if(array_list[i].values[j].toString().indexOf(search.value.toLowerCase()) + 1) {
                            suitable = true;
                        }
                    }
                }
                array_list[i].active = suitable;
                if((array_list[i].active && array_list[i].cat_active) || array_list[i].force) count++;
            }
            if(count>0 && search.value!='') {
                if(!$('.list_detail').is(':visible')) {
                    open_list_detail();
                }
            } else {
                close_list_detail();
                $('.search_div').removeClass('open');
                $('.list_icon').attr('onclick','open_list_detail();');
                $('.search_div').removeClass('open');
            }
            if(search.value=='') {
                $('.search_icon i').removeClass('fa-times').addClass('fa-search');
                $('.search_icon i').css('vertical-align','unset');
                $('.search_icon i').css('cursor','default');
                $('.search_icon i').attr('onclick','');
                var rows_filtered = filterRows(array_list,true);
                clusterize_list.update(rows_filtered);
            } else {
                $('.search_icon i').removeClass('fa-search').addClass('fa-times');
                $('.search_icon i').css('vertical-align','middle');
                $('.search_icon i').css('cursor','pointer');
                $('.search_icon i').attr('onclick','reset_search()');
                var rows_filtered = filterRows(array_list,false);
                if(search.value.length>=3) {
                    var html_search_location = '<div id="list_block_location" class="search_q_container list_block"><div style="padding: 10px;"><i class="fas fa-circle-notch fa-spin"></i> '+window.viewer_labels.searching+' ...</div></div>';
                    rows_filtered.unshift(html_search_location);
                }
                clusterize_list.update(rows_filtered);
            }
            if(window.enable_search_location) {
                if(search.value.length>=3) {
                    if(!$('.list_detail').is(':visible')) {
                        open_list_detail();
                    }
                    clearTimeout(search_timer);
                    search_timer = setTimeout(search_location.bind(this), 1000);
                }
            }
            $('.list_detail').animate({ scrollTop: 0 }, 'fast');
        }
        search.oninput = onSearch;
        if(!update) {
            $('.list_detail').css('opacity',1).hide();
        } else {
            if(!list_visible) {
                $('.list_detail').css('opacity',0).show();
            }
        }
        $('.list_icon').removeClass("disabled");
        $('.nav_marker_next').removeClass("disabled");
        $('.nav_marker_prev').removeClass("disabled");
    }

    var filterRows = function(rows,initial=false) {
        var results = [];
        for(var i = 0, ii = rows.length; i < ii; i++) {
            if((rows[i].active && rows[i].cat_active && rows[i].visible) || rows[i].force) {
                if(window.limit_list!=-1 && initial) {
                    if(i<=window.limit_list) {
                        results.push(rows[i].markup);
                    }
                } else {
                    results.push(rows[i].markup);
                }
            }
        }
        return results;
    }

    window.highlight_marker = function(id_marker) {
        for(var i=0;i<features.length;i++) {
            var id = features[i].get('id');
            if(id==id_marker) {
                selected_feature = i;
                break;
            }
        }
        if(window.search_highlight!=-1) {
            var active = features[selected_feature].get('active');
            if(active) {
                var coordinates = features[selected_feature].getGeometry().getCoordinates();
                var size = map.getSize();
                if((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)){
                    var w = size[0]/2;
                    var h = size[1]/2+120;
                } else {
                    var w = size[0]/2+180;
                    var h = size[1]/2;
                }
                if(window.search_highlight>0) {
                    map_view.setZoom(window.search_highlight);
                }
                map_view.centerOn(coordinates, size, [w,h]);
            }
        }
        pin_active_marker(features[selected_feature].get('latitude'),features[selected_feature].get('longitude'));
    }

    window.highlight_marker_featured = function(id_marker) {
        for(var i=0;i<features.length;i++) {
            var id = features[i].get('id');
            if(id==id_marker) {
                selected_feature = i;
                break;
            }
        }
        pin_active_marker(features[selected_feature].get('latitude'),features[selected_feature].get('longitude'));
    }

    window.reset_search = function () {
        $('#searchbox').val('');
        close_list_detail();
        close_sheet_detail();
        close_categories();
        $('#searchbox').trigger('input');
    }

    function adjust_distances() {
        if(geolocation.getTracking()) {
            for(var i=0;i<features.length;i++) {
                var length = features[i].get('distance');
                var id = features[i].get('id');
                if(length>-1) {
                    var distance = formatDistance(length);
                    var time = length / 1.11111 / 60;
                    if(time>=1440) {
                        time = time / 1440;
                        time = time.toFixed(1);
                        time = time +' '+window.viewer_labels.day;
                    } else if(time>= 60) {
                        time = time / 60;
                        time = Math.round(time);
                        time = time +' '+window.viewer_labels.hour;
                    } else {
                        time = Math.round(time);
                        time = time +' '+window.viewer_labels.minute;
                    }
                    features[i].values_.distance_html = distance+' - '+time+' '+window.viewer_labels.walk;
                }
            }
        }
    }

    function compare( a, b ) {
        if ( a.get('distance') < b.get('distance') ){
            return -1;
        }
        if ( a.get('distance') > b.get('distance') ){
            return 1;
        }
        return 0;
    }

    function search_location() {
        var q = $('#searchbox').val();
        if(q.length>=3) {
            $.ajax({
                url: "https://nominatim.openstreetmap.org/search",
                type: "GET",
                data: {
                    q: q,
                    limit: 5,
                    addressdetails: 1,
                    format: 'json'
                },
                async: true,
                success: function (json) {
                    var html = '';
                    var array_result = [];
                    $.each(json, function (index,value) {
                        var display_name = value.display_name;
                        var boundingbox = value.boundingbox;
                        if(window.extent!==null && window.extent!='' && window.extent!='null' && window.extent!=undefined) {
                            if(isBoundingBoxInsideExtent(boundingbox,JSON.parse(window.extent))) {
                                if(!array_result.includes(display_name)) {
                                    array_result.push(display_name);
                                    html += '<div onclick="go_to('+boundingbox+')" style="height:auto;" class="list_block">'+display_name+'</div>';
                                }
                            }
                        } else {
                            if(!array_result.includes(display_name)) {
                                array_result.push(display_name);
                                html += '<div onclick="go_to('+boundingbox+')" style="height:auto;" class="list_block">'+display_name+'</div>';
                            }
                        }
                    });
                    if(array_result.length>0) {
                        $('.search_q_container').html(html);
                    } else {
                        $('.search_q_container').html('<div style="height:auto;" class="list_block">'+window.viewer_labels.no_result+'</div>');
                    }
                }
            });
        }
    }

    window.go_to = function(x1,x2,y1,y2) {
        map.getView().fit(ol.proj.transformExtent([y1, x1, y2, x2], 'EPSG:4326', map.getView().getProjection()), { size: map.getSize(), padding: [100, 100, 100, 100], duration: 500, nearest: true, maxZoom:16 });
    }

    function isBoundingBoxInsideExtent(bbox, extent) {
        const minCorner = ol.proj.transform([bbox[2], bbox[0]], 'EPSG:4326', 'EPSG:3857');
        const maxCorner = ol.proj.transform([bbox[3], bbox[1]], 'EPSG:4326', 'EPSG:3857');
        return (
            minCorner[0] >= extent[0] &&
            maxCorner[0] <= extent[2] &&
            minCorner[1] >= extent[1] &&
            maxCorner[1] <= extent[3]
        );
    }

    function parse_featured() {
        var html = '<div id="featured_slider" class="owl-carousel owl-theme">';
        var num_featured = 0;
        for(var i=0;i<features.length;i++) {
            var featured = features[i].get('featured');
            if(featured) {
                num_featured++;
                var id = features[i].get('id');
                var id_db = features[i].get('id_db');
                var name = features[i].get('name');
                var address = features[i].get('address');
                var image = features[i].get('image');
                var image_thumb = image.replace('marker_images/','marker_images/thumb/').replace('media/','media/thumb/');
                var rating = features[id].get('rating');
                var num_reviews = features[id].get('num_reviews');
                var view_review = features[id].get('view_review');
                var id_categories = features[id].get('id_categories');
                switch(getMediaType(image_thumb)) {
                    case 'image':
                        var background = 'background-image:url('+image_thumb+');';
                        var video_bg = '';
                        break;
                    case 'video':
                        var background = '';
                        var video_bg = '<video class="animated-background" playsinline muted src="'+image+'#t=2" />';
                        break;
                    case 'youtube':
                        const ytId = getYouTubeId(image);
                        if (ytId) {
                            var thumb = `https://img.youtube.com/vi/${ytId}/hqdefault.jpg`;
                            var background = 'background-image:url('+thumb+');';
                            var video_bg = '';
                        }
                        break;
                    case 'vimeo':
                        videoPromises.push(
                            new Promise((resolve) => {
                                fetch(`https://vimeo.com/api/oembed.json?url=${encodeURIComponent(image)}`)
                                    .then(r => r.json())
                                    .then(data => {
                                        var background = 'background-image:url('+data.thumbnail_url+');';
                                        var video_bg = '';
                                        resolve();
                                    })
                                    .catch(() => resolve());
                            })
                        );
                        break;
                }
                var category_icons_html = parse_category_icons(id_categories);
                if(window.enable_reviews && view_review==1) {
                    var star_html = '<span>'+rating.toFixed(1)+'</span>&nbsp;'+parse_stars(rating)+'&nbsp;<span>('+num_reviews+')</span>';
                    html += '<div onmouseenter="highlight_marker_featured('+id+')" id="list_block_f_'+id+'" onclick="click_featured('+i+');" class="list_block_featured">\n' +
                        '            <div class="list_image noselect" style="'+background+';">'+video_bg+'</div>\n' +
                        '            <div class="list_name noselect">'+name+'</div>\n' +
                        '            <div id="list_rating_'+id_db+'" class="list_rating noselect">'+star_html+'&nbsp;&nbsp;'+category_icons_html+'</div>\n' +
                        '            <div class="list_address noselect">'+address+'</div>\n' +
                        '        </div>';
                } else {
                    html += '<div onmouseenter="highlight_marker_featured('+id+')" id="list_block_f_'+id+'" onclick="click_featured('+i+');" class="list_block_featured">\n' +
                        '            <div class="list_image noselect" style="'+background+';">'+video_bg+'</div>\n' +
                        '            <div class="list_name noselect">'+name+'</div>\n' +
                        ((category_icons_html!='') ? '<div class="list_rating noselect">'+category_icons_html+'</div>\n' : '') +
                        '            <div class="list_address noselect">'+address+'</div>\n' +
                        '        </div>';
                }
            }
        }
        html += '</div>';
        if(num_featured>0) {
            $('#featured_container').css('opacity',1);
            $('#featured_container').html(html).promise().done(function () {
                $('#featured_slider').owlCarousel({
                    margin:6,
                    center:false,
                    loop:false,
                    autoWidth:true,
                    items:1,
                    rewind:false,
                    dots:false,
                    rtl:($('html').attr('dir')=='rtl')?true:false
                });
                $('#featured_slider').on('drag.owl.carousel', function(event) {
                    featured_slider_drag=true;
                });
                $('#featured_slider').on('dragged.owl.carousel', function(event) {
                    setTimeout(function () {
                        featured_slider_drag=false;
                    },50);
                });
                manageCategoryOverflow('list_rating');
            });
            $('.featured_icon').removeClass('hidden');
        } else {
            $('#featured_container').css('opacity',0).empty();
            $('.featured_icon').addClass('hidden');
        }
    }

    var clicked_featured = false;
    window.click_featured = function(index_marker) {
        if(!featured_slider_drag) {
            clicked_featured = true;
            setTimeout(function() {
                clicked_featured = false;
            },10000);
            $('.list_block_featured').css('border','2px solid transparent');
            var coordinates = features[selected_feature].getGeometry().getCoordinates();
            var size = map.getSize();
            var w = size[0]/2;
            var h = size[1]/2-70;
            const currentZoom = parseInt(map_view.getZoom());
            const featureZoom = features[selected_feature].get('selected_zoom');
            let durationZoom = features[selected_feature].get('duration_zoom');
            if(durationZoom==-1) durationZoom = window.duration_zoom;
            var targetZoom = currentZoom;
            if (featureZoom === -1 && window.selected_zoom !== 0 && currentZoom <= window.selected_zoom) {
                targetZoom = window.selected_zoom;
            } else if (featureZoom > 0 && currentZoom <= featureZoom) {
                targetZoom = featureZoom;
            }
            const resolution = map_view.getResolutionForZoom(targetZoom);
            const offsetX = w - size[0] / 2;
            const offsetY = h - size[1] / 2;
            const newCenter = [
                coordinates[0] - offsetX * resolution,
                coordinates[1] - offsetY * resolution
            ];
            map_view.animate({
                center: newCenter,
                zoom: targetZoom,
                duration: durationZoom,
                easing: ol.easing.easeOut
            });
            $('#list_block_f_'+index_marker).css('border','2px solid '+window.main_color_hex);
        }
    }

    function prepare_map_audio() {
        if(window.song_bg!=='') {
            $('.btn_song_map').show();
            if (window.song_bg.startsWith("song_")) {
                audio_player.src = "content/" + window.song_bg;
            } else {
                audio_player.src = window.song_bg;
            }
        }
    }

    function initialize_viewport_start_position() {
        if(window.lazy_loading!==2 || window.initial_coordinates!=='') return;
        map.updateSize();
        if(window.marker_sel!=0 && window.selected_marker_coordinates) {
            map_view.setCenter(ol.proj.fromLonLat([
                window.selected_marker_coordinates.lon,
                window.selected_marker_coordinates.lat
            ]));
            map_view.setZoom(window.default_zoom>0 ? window.default_zoom : 14);
            return;
        }
        if(window.centered_marker_coordinates) {
            map_view.setCenter(ol.proj.fromLonLat([
                window.centered_marker_coordinates.lon,
                window.centered_marker_coordinates.lat
            ]));
            map_view.setZoom(window.default_zoom>0 ? window.default_zoom : 10);
        }
    }

    function get_marker_viewport_bbox(include_buffer) {
        if(!map || !map.getSize() || !map_view.getProjection()) return null;
        var extent = map_view.calculateExtent(map.getSize());
        var bbox = ol.proj.transformExtent(extent,map_view.getProjection(),'EPSG:4326');
        var viewport_center = ol.proj.toLonLat(map_view.getCenter(),map_view.getProjection());
        var lon_buffer = include_buffer ? Math.max((bbox[2]-bbox[0])*0.3,0.0005) : 0;
        var lat_buffer = include_buffer ? Math.max((bbox[3]-bbox[1])*0.3,0.0005) : 0;
        var result = {
            min_lon: Math.max(-180,bbox[0]-lon_buffer),
            min_lat: Math.max(-90,bbox[1]-lat_buffer),
            max_lon: Math.min(180,bbox[2]+lon_buffer),
            max_lat: Math.min(90,bbox[3]+lat_buffer),
            center_lon: Math.max(-180,Math.min(180,viewport_center[0])),
            center_lat: Math.max(-90,Math.min(90,viewport_center[1]))
        };
        if(include_buffer && window.search_radius_enabled && window.search_radius_m>0 && geolocation && geolocation.getTracking()) {
            var position = geolocation.getPosition();
            if(position) {
                var lon_lat = ol.proj.toLonLat(position);
                var lat_delta = window.search_radius_m/111320;
                var lon_delta = lat_delta/Math.max(Math.cos(lon_lat[1]*Math.PI/180),0.1);
                result.min_lon = Math.max(-180,Math.min(result.min_lon,lon_lat[0]-lon_delta));
                result.max_lon = Math.min(180,Math.max(result.max_lon,lon_lat[0]+lon_delta));
                result.min_lat = Math.max(-90,Math.min(result.min_lat,lon_lat[1]-lat_delta));
                result.max_lat = Math.min(90,Math.max(result.max_lat,lon_lat[1]+lat_delta));
            }
        }
        return result;
    }

    function is_current_viewport_loaded() {
        if(!loaded_marker_bbox || loaded_marker_bbox_truncated) return false;
        var bbox = get_marker_viewport_bbox(false);
        if(!bbox) return false;
        return bbox.min_lon>=loaded_marker_bbox.min_lon &&
            bbox.max_lon<=loaded_marker_bbox.max_lon &&
            bbox.min_lat>=loaded_marker_bbox.min_lat &&
            bbox.max_lat<=loaded_marker_bbox.max_lat;
    }

    function schedule_viewport_markers_load() {
        if(window.lazy_loading!==2 || !viewport_loading_enabled || new_marker_mode) return;
        clearTimeout(viewport_load_timer);
        viewport_load_timer = setTimeout(function () {
            if(!is_current_viewport_loaded()) {
                load_viewport_markers(true);
            }
        },350);
    }

    function load_viewport_markers(is_reload) {
        var bbox = get_marker_viewport_bbox(true);
        if(!bbox) return;
        var bbox_key = [bbox.min_lon,bbox.min_lat,bbox.max_lon,bbox.max_lat]
            .map(function (value) { return value.toFixed(5); }).join(':');
        if(bbox_key===requested_marker_bbox_key && markers_ajax_request && markers_ajax_request.readyState!==4) return;
        requested_marker_bbox_key = bbox_key;
        get_markers(is_reload,bbox);
    }

    var markers_status_timeout = null;
    function set_markers_loading_state(is_loading,keep_loaded,is_truncated) {
        if(!keep_loaded) {
            window.markers_loaded = !is_loading;
        }
        if(window.lazy_loading==0) return;
        var status = $('#markers_loading_status');
        clearTimeout(markers_status_timeout);
        status.stop(true,true).removeClass('success error');
        if(is_loading) {
            status.find('i').attr('class','fas fa-spin fa-circle-notch');
            status.find('span').text(window.viewer_labels.preparing_map);
            status.fadeIn(150);
        } else if(is_truncated) {
            status.addClass('success');
            status.find('i').attr('class','fas fa-magnifying-glass-plus');
            status.find('span').text(window.viewer_labels.zoom_in_for_content);
            status.show();
            markers_status_timeout = setTimeout(function () {
                status.fadeOut(250);
            },2500);
        } else {
            status.addClass('success');
            status.find('i').attr('class','fas fa-check');
            status.find('span').text(window.viewer_labels.map_ready);
            status.show();
            markers_status_timeout = setTimeout(function () {
                status.fadeOut(250);
            },1200);
        }
        var marker_controls = $('.filter_icon, .search_icon');
        if(!is_loading && features.length==0) {
            marker_controls.addClass('disabled2');
            $('#searchbox').prop('disabled',true).attr('aria-busy','false');
            return;
        }
        marker_controls.toggleClass('disabled2',is_loading);
        $('#searchbox').prop('disabled',is_loading).attr('aria-busy',is_loading ? 'true' : 'false');
    }

    function set_markers_load_error_state() {
        if(window.lazy_loading==0) return;
        clearTimeout(markers_status_timeout);
        var status = $('#markers_loading_status');
        status.stop(true,true).removeClass('success').addClass('error');
        status.find('i').attr('class','fas fa-triangle-exclamation');
        status.find('span').text(window.viewer_labels.map_load_error);
        status.fadeIn(150);
    }

    function complete_map_startup() {
        if(map_runtime_initialized) return;
        map_runtime_initialized = true;
        map_initialized = true;
        if(initialCenter===null) {
            initialCenter = map_view.getCenter();
            initialZoom = map_view.getZoom();
        }
        $('#background_loading').hide();
        $('.map_render').css('opacity',1);
        $('.loading').fadeOut(function () {
            $('.loading').css('z-index',0);
            $('.loading').hide();
        });
        $('html').css('pointer-events','initial');
        $('body').css('pointer-events','initial');
        switch(window.globe) {
            case 1:
                if(ol3d==null) {
                    ol3d = new olcs.OLCesium({map: map,optimizeRendering: true});
                    ol3d.getCesiumScene().fog.enabled = false;
                    ol3d.getCesiumScene().skyAtmosphere.show = false;
                    ol3d.getCesiumScene().globe.showGroundAtmosphere = false;
                }
                break;
            case 2:
                enable_globe();
                break;
        }
        if(window.enable_add_marker==1) {
            get_add_marker_boundaries();
        }
        if(window.live_tracking!=0) {
            liveTrackingSource = new ol.source.Vector();
            liveTrackingLayer = new ol.layer.Vector({
                source: liveTrackingSource,
            });
            map.addLayer(liveTrackingLayer);
            initialize_get_live_tracking();
            if(window.live_tracking==2) {
                open_live_tracking();
            }
        }
        $('#custom_html').show();
        if(clusters_layer!=undefined) {
            clusters_layer.setOpacity(1);
        }
        jQuery.each(layerGeodata, function(index, layer) {
            layer.setOpacity(1);
        });
        $(window).trigger('sml:map-ready');
    }

    function initialize_startup_overlays() {
        if(startup_overlays_initialized) return;
        startup_overlays_initialized = true;
        if(window.enable_intro==1) {
            $('.intro').fadeIn();
        } else {
            init_audio_player();
            switch(info_auto_open) {
                case 1:
                    $('.info_icon').trigger('click');
                    break;
                case 2:
                    if(window.innerWidth > 600) {
                        $('.info_icon').trigger('click');
                    }
                    break;
                case 3:
                    if(window.innerWidth <= 600) {
                        $('.info_icon').trigger('click');
                    }
                    break;
            }
        }
    }

    function refresh_markers_after_lazy_load() {
        if(window.lazy_loading==0 || features.length==0 || !geolocation || !geolocation.getTracking()) return;
        var coordinates = geolocation.getPosition();
        if(!coordinates) return;
        setTimeout(function () {
            calculate_distance(coordinates);
            if(search_radius_enabled) {
                check_marker_in_radius(coordinates,window.search_radius_m);
                show_search_radius_m();
            }
        },30);
    }

    var interval_progress;
    var animate_value = 0.2;
    function get_markers(viewport_reload,bbox) {
        viewport_reload = viewport_reload===true;
        if(window.lazy_loading===2) {
            if(markers_ajax_request && markers_ajax_request.readyState!==4) {
                markers_ajax_request.abort();
            }
            clearInterval(interval_progress);
            set_markers_loading_state(true,viewport_reload);
        }
        var current_request_sequence = ++marker_request_sequence;
        progress_circle.animate(0.2);
        interval_progress = setInterval(function () {
            animate_value = animate_value+0.01;
            if(animate_value>=0.99) {
                progress_circle.animate(0.99);
                clearInterval(interval_progress);
            } else {
                progress_circle.animate(animate_value);
            }
        },500);
        var request_includes_metadata = window.lazy_loading===2 ? !marker_metadata_loaded : true;
        var request_data = {
            language: window.language,
            id_map: window.id_map,
            id_marker_sel: window.lazy_loading===2
                ? (window.marker_current_id!=0 ? window.marker_current_id : (direct_marker_pending ? window.marker_sel : 0))
                : window.marker_sel,
            order_by: window.order_by,
            preview: window.preview,
            viewport_mode: window.lazy_loading===2 ? 1 : 0,
            include_metadata: request_includes_metadata ? 1 : 0,
            track_access: request_includes_metadata ? 1 : 0
        };
        if(window.lazy_loading===2 && bbox) {
            request_data.min_lat = bbox.min_lat;
            request_data.max_lat = bbox.max_lat;
            request_data.min_lon = bbox.min_lon;
            request_data.max_lon = bbox.max_lon;
            request_data.center_lat = bbox.center_lat;
            request_data.center_lon = bbox.center_lon;
        }
        markers_ajax_request = $.ajax({
            url: "ajax/get_markers.php",
            type: "POST",
            data: request_data,
            async: true,
            success: function (json) {
                if(current_request_sequence!==marker_request_sequence) return;
                clearInterval(interval_progress);
                window.markers_load_failed = false;
                progress_circle.animate(0.99);
                var rsp = JSON.parse(json);
                var markers = rsp.markers;
                if(window.lazy_loading===2) {
                    direct_marker_pending = false;
                }
                if(request_includes_metadata) {
                    marker_metadata_loaded = true;
                }
                if(window.lazy_loading===2 && bbox) {
                    loaded_marker_bbox = bbox;
                    loaded_marker_bbox_truncated = rsp.truncated===true;
                    features = [];
                    features_filter = [];
                    selected_feature = null;
                }
                if(markers.length==0 && window.lazy_loading!==2) {
                    $('.list_icon').addClass('hidden');
                    $('.btn_story').addClass('hidden');
                }
                if(markers.length<2) {
                    if(window.lazy_loading===2) {
                        $('.nav_marker_prev, .nav_marker_next').not('.hidden').addClass('hidden viewport-hidden');
                    } else {
                        $('.nav_marker_prev').addClass('hidden');
                        $('.nav_marker_next').addClass('hidden');
                    }
                } else if(window.lazy_loading===2) {
                    $('.nav_marker_prev.viewport-hidden, .nav_marker_next.viewport-hidden').removeClass('hidden viewport-hidden');
                }
                var has_metadata = request_includes_metadata;
                if(has_metadata) {
                    categories = rsp.categories || [];
                    mapping_categories_icon = {};
                    mapping_categories_name = {};
                }
                var id_categories_featured = [];
                if(has_metadata && categories.length>0) {
                    $.each(categories,function(index_c,cat_c) {
                        mapping_categories_icon[cat_c.id] = parse_category_icon(cat_c);
                        mapping_categories_name[cat_c.id] = cat_c.name;
                        if(parseInt(cat_c.featured) && parseInt(cat_c.child_count)==0) {
                            id_categories_featured.push(cat_c.id);
                        }
                    });
                }
                if(has_metadata && id_categories_featured.length>0) {
                    parse_category_featured(id_categories_featured);
                    featuredSlider = initCategorySlider('slider_categories_featured', 'featured_categories');
                } else if(has_metadata) {
                    $('#slider_categories_featured').hide();
                }
                markers_connections = rsp.markers_connections;
                if(has_metadata) {
                    pin_marker = rsp.pin_marker;
                }
                resize_elements_ui();
                if(has_metadata) {
                    parse_html_categories();
                }
                lat_center = null;
                lon_center = null;
                var is_marker_audio = false;
                window.markerStyleCache = window.markerStyleCache || {};
                window.markerHoverStyleCache = window.markerHoverStyleCache || {};
                window.markerLabelStyleCache = window.markerLabelStyleCache || {};
                for (var m_idx = 0, m_len = markers.length; m_idx < m_len; m_idx++) {
                    var marker = markers[m_idx];
                    var index = m_idx;
                    marker.name = marker.name || '';
                    marker.description = marker.description || '';
                    marker.address = marker.address || '';
                    marker.website = marker.website || '';
                    marker.website_caption = marker.website_caption || '';
                    marker.email = marker.email || '';
                    marker.phone = marker.phone || '';
                    marker.whatsapp = marker.whatsapp || '';
                    marker.hours = marker.hours || '';
                    marker.link = marker.link || '';
                    marker.color_hex = marker.color_hex || '';
                    marker.darker_color_hex = marker.darker_color_hex || '';
                    marker.icon_color_hex = marker.icon_color_hex || '';
                    marker.color_hex_hover = marker.color_hex_hover || '';
                    marker.darker_color_hex_hover = marker.darker_color_hex_hover || '';
                    marker.icon_color_hex_hover = marker.icon_color_hex_hover || '';
                    marker.icon_label = marker.icon_label || '';
                    marker.icon = marker.icon || '';
                    marker.icon_image = marker.icon_image || '';
                    marker.icon_base64 = marker.icon_base64 || '';
                    marker.tripadvisor_location_id = marker.tripadvisor_location_id || '';
                    marker.box_warning = marker.box_warning || '';
                    marker.id_categories = marker.id_categories ? String(marker.id_categories) : '';
                    marker.update_date = marker.update_date || '';
                    marker.song = marker.song || '';
                    marker.rating = marker.rating || 0;
                    marker.num_reviews = marker.num_reviews || 0;
                    if(parseInt(marker.id)==parseInt(window.marker_sel)) {
                        marker.visible_map = 1;
                    }
                    if(marker.song!=='' && marker.song!==null && marker.song!==undefined) {
                        is_marker_audio = true;
                    }
                    for(var i=1;i<=20;i++) {
                        if(!("extra_field_value_"+i in marker)) {
                            marker['extra_field_value_'+i]='';
                        }
                        if(!("extra_field_icon_"+i in marker)) {
                            marker['extra_field_icon_'+i]='fa-circle';
                        }
                    }
                    if(!("extra_button_value_1" in marker)) {
                        marker['extra_button_value_1']='';
                    }
                    if(!("extra_button_icon_1" in marker)) {
                        marker['extra_button_icon_1']='fa-circle';
                    }
                    if(marker.main_image=='' || marker.main_image==null || marker.main_image==undefined) {
                        var image = 'images/placeholder.jpg';
                    } else {
                        if (!marker.main_image.startsWith('http')) {
                            if (marker.main_image.startsWith('media_')) {
                                var image = 'media/'+marker.main_image;
                            } else {
                                var image = 'marker_images/'+marker.main_image;
                            }
                        } else {
                            var image = marker.main_image;
                        }
                    }
                    var k=0;
                    if(parseInt(marker.centered)==1 && lat_center==null) {
                        lat_center = marker.lat;
                        lon_center = marker.lon;
                    }
                    var style = null;
                    var style_label = null;
                    var style_hover = null;
                    if(marker.id==window.marker_sel) {
                        if(marker.marker_size!=0) {
                            marker.marker_size = marker.marker_size * window.marker_sel_zoom;
                        } else {
                            marker.marker_size = window.markers_size * window.marker_sel_zoom;
                        }
                    }
                    if(marker.marker_size==0) {
                        var scale_text = window.markers_size;
                    } else {
                        var scale_text = marker.marker_size;
                    }
                    if(marker.icon_image=='') {
                        if(marker.marker_size==0) {
                            var scale = window.markers_size/10;
                        } else {
                            var scale = marker.marker_size/10;
                        }
                        var radius = 140*scale;
                        var font_size = 120*scale;
                        if(marker.active==1) {
                            var opacity = 1;
                        } else {
                            var opacity = 0.4;
                        }
                        var styleKey = marker.color_hex + '_' + marker.icon_color_hex + '_' + marker.darker_color_hex + '_' + opacity + '_' + scale + '_' + marker.icon + '_' + marker.color_hex_hover;
                        if(!window.markerStyleCache[styleKey]) {
                            if(marker.color_hex!='') {
                                var darker_color_rgb = hexToRgbA(marker.darker_color_hex,opacity);
                                var main_color_rgb = hexToRgbA(marker.color_hex,opacity);
                            } else {
                                var darker_color_rgb = hexToRgbA('#000000',0);
                                var main_color_rgb = hexToRgbA('#000000',0);
                            }
                            if(marker.icon_color_hex!='') {
                                var icon_color_rgb = hexToRgbA(marker.icon_color_hex,opacity);
                            } else {
                                var icon_color_rgb = hexToRgbA('#ffffff',opacity);
                            }
                            var style_hover_cache = null;
                            if(marker.color_hex_hover!='' || marker.icon_color_hex_hover!='') {
                                if(marker.color_hex_hover!='') {
                                    var darker_color_rgb_hover = hexToRgbA(marker.darker_color_hex_hover,1);
                                    var main_color_rgb_hover = hexToRgbA(marker.color_hex_hover,1);
                                } else {
                                    var darker_color_rgb_hover = darker_color_rgb;
                                    var main_color_rgb_hover = main_color_rgb;
                                }
                                if(marker.icon_color_hex_hover!='') {
                                    var icon_color_rgb_hover = hexToRgbA(marker.icon_color_hex_hover,1);
                                } else {
                                    var icon_color_rgb_hover = icon_color_rgb;
                                }
                                var text_icon_hover = '';
                                if(marker.icon != null && marker.icon != undefined && marker.icon != '') {
                                    text_icon_hover = new ol.style.Text({
                                        text: String.fromCharCode("0x" + marker.icon),
                                        textAlign: "center",
                                        textBaseline: "middle",
                                        font: '900 '+font_size+'px "Font Awesome 7 Free"',
                                        fill: new ol.style.Fill({
                                            color: icon_color_rgb_hover
                                        })
                                    });
                                }
                                style_hover_cache = new ol.style.Style({
                                    image: new ol.style.Circle({
                                        radius: radius,
                                        stroke: new ol.style.Stroke({
                                            color: darker_color_rgb_hover,
                                            width: 3
                                        }),
                                        fill: new ol.style.Fill({
                                            color: main_color_rgb_hover,
                                            weight: 1
                                        })
                                    }),
                                    text: text_icon_hover
                                });
                            }
                            var text_icon = '';
                            if(marker.icon != null && marker.icon != undefined && marker.icon != '') {
                                text_icon = new ol.style.Text({
                                    text: String.fromCharCode("0x" + marker.icon),
                                    textAlign: "center",
                                    textBaseline: "middle",
                                    font: '900 '+font_size+'px "Font Awesome 7 Free"',
                                    fill: new ol.style.Fill({
                                        color: icon_color_rgb
                                    })
                                });
                            }
                            window.markerStyleCache[styleKey] = new ol.style.Style({
                                image: new ol.style.Circle({
                                    radius: radius,
                                    stroke: new ol.style.Stroke({
                                        color: darker_color_rgb,
                                        width: 3
                                    }),
                                    fill: new ol.style.Fill({
                                        color: main_color_rgb,
                                        weight: 1
                                    })
                                }),
                                text: text_icon
                            });
                            window.markerHoverStyleCache[styleKey] = style_hover_cache;
                        }
                        style = window.markerStyleCache[styleKey];
                        style_hover = window.markerHoverStyleCache[styleKey];
                    }
                    var icon_color_label = marker.icon_label_color || '#000000';
                    var icon_label_size = marker.icon_label_size || 12;
                    var labelKey = marker.icon_label + '_' + icon_color_label + '_' + icon_label_size + '_' + scale_text;
                    if(!window.markerLabelStyleCache[labelKey] && marker.icon_label != '') {
                        window.markerLabelStyleCache[labelKey] = new ol.style.Style({
                            text: new ol.style.Text({
                                text: marker.icon_label.replace(/\\n/g, '\n'),
                                font: 'bold '+((scale_text<=1) ? icon_label_size : (icon_label_size*scale_text))+'px/1.2 Calibri,sans-serif',
                                fill: new ol.style.Fill({ color: icon_color_label }),
                                stroke: new ol.style.Stroke({ color: '#ffffff', width: 1 }),
                                textAlign: 'center',
                                textBaseline: 'top',
                                offsetY: 20*scale_text
                            })
                        });
                    }
                    style_label = marker.icon_label != '' ? window.markerLabelStyleCache[labelKey] : null;
                    if(parseInt(marker.visible_map)==0) {
                        marker.featured=0;
                        style=null;
                        style_label=null;
                        style_hover=null;
                    }
                    var feature = new ol.Feature({
                        id: index,
                        initial_index: k,
                        update_date: marker.update_date,
                        id_db: marker.id,
                        selected: false,
                        visible: true,
                        type: marker.type,
                        link: marker.link,
                        visible_map: parseInt(marker.visible_map),
                        visible_search: parseInt(marker.visible_search),
                        featured: parseInt(marker.featured),
                        open_sheet: parseInt(marker.open_sheet),
                        view_popup: parseInt(marker.view_popup),
                        popup_background: marker.popup_background,
                        popup_color: marker.popup_color,
                        popup_image_height: parseInt(marker.popup_image_height),
                        song: marker.song,
                        song_bg_volume: parseFloat(marker.song_bg_volume),
                        song_volume: parseFloat(marker.song_volume),
                        song_play_bg: parseInt(marker.song_play_bg),
                        latitude: marker.lat,
                        longitude: marker.lon,
                        selected_zoom: parseInt(marker.selected_zoom),
                        duration_zoom: parseInt(marker.duration_zoom),
                        geofence_radius: parseInt(marker.geofence_radius),
                        geofence_color: marker.geofence_color,
                        id_categories: marker.id_categories,
                        active: parseInt(marker.active),
                        centered: parseInt(marker.centered),
                        view_directions: parseInt(marker.view_directions),
                        view_street_view: parseInt(marker.view_street_view),
                        view_review: parseInt(marker.view_review),
                        view_add_photo: parseInt(marker.view_add_photo),
                        view_share: parseInt(marker.view_share),
                        color_hex: marker.color_hex,
                        style: style,
                        style_label: style_label,
                        style_default: style,
                        style_hover: style_hover,
                        darker_color_hex: marker.darker_color_hex,
                        icon_color_hex: marker.icon_color_hex,
                        color_hex_hover: marker.color_hex_hover,
                        darker_color_hex_hover: marker.darker_color_hex_hover,
                        icon_color_hex_hover: marker.icon_color_hex_hover,
                        size: parseFloat(marker.marker_size),
                        icon: marker.icon,
                        gif: null,
                        icon_image: marker.icon_image,
                        icon_base64: marker.icon_base64,
                        name: marker.name,
                        image: image,
                        address: marker.address,
                        website: marker.website,
                        website_caption: marker.website_caption,
                        email: marker.email,
                        phone: marker.phone,
                        whatsapp: marker.whatsapp,
                        hours: marker.hours,
                        description: marker.description,
                        images: marker.images,
                        icon_e1: marker.extra_field_icon_1,
                        icon_e2: marker.extra_field_icon_2,
                        icon_e3: marker.extra_field_icon_3,
                        icon_e4: marker.extra_field_icon_4,
                        icon_e5: marker.extra_field_icon_5,
                        icon_e6: marker.extra_field_icon_6,
                        icon_e7: marker.extra_field_icon_7,
                        icon_e8: marker.extra_field_icon_8,
                        icon_e9: marker.extra_field_icon_9,
                        icon_e10: marker.extra_field_icon_10,
                        icon_e11: marker.extra_field_icon_11,
                        icon_e12: marker.extra_field_icon_12,
                        icon_e13: marker.extra_field_icon_13,
                        icon_e14: marker.extra_field_icon_14,
                        icon_e15: marker.extra_field_icon_15,
                        icon_e16: marker.extra_field_icon_16,
                        icon_e17: marker.extra_field_icon_17,
                        icon_e18: marker.extra_field_icon_18,
                        icon_e19: marker.extra_field_icon_19,
                        icon_e20: marker.extra_field_icon_20,
                        field_e1: marker.extra_field_value_1,
                        field_e2: marker.extra_field_value_2,
                        field_e3: marker.extra_field_value_3,
                        field_e4: marker.extra_field_value_4,
                        field_e5: marker.extra_field_value_5,
                        field_e6: marker.extra_field_value_6,
                        field_e7: marker.extra_field_value_7,
                        field_e8: marker.extra_field_value_8,
                        field_e9: marker.extra_field_value_9,
                        field_e10: marker.extra_field_value_10,
                        field_e11: marker.extra_field_value_11,
                        field_e12: marker.extra_field_value_12,
                        field_e13: marker.extra_field_value_13,
                        field_e14: marker.extra_field_value_14,
                        field_e15: marker.extra_field_value_15,
                        field_e16: marker.extra_field_value_16,
                        field_e17: marker.extra_field_value_17,
                        field_e18: marker.extra_field_value_18,
                        field_e19: marker.extra_field_value_19,
                        field_e20: marker.extra_field_value_20,
                        name_e1: marker.extra_field_name_1,
                        name_e2: marker.extra_field_name_2,
                        name_e3: marker.extra_field_name_3,
                        name_e4: marker.extra_field_name_4,
                        name_e5: marker.extra_field_name_5,
                        name_e6: marker.extra_field_name_6,
                        name_e7: marker.extra_field_name_7,
                        name_e8: marker.extra_field_name_8,
                        name_e9: marker.extra_field_name_9,
                        name_e10: marker.extra_field_name_10,
                        name_e11: marker.extra_field_name_11,
                        name_e12: marker.extra_field_name_12,
                        name_e13: marker.extra_field_name_13,
                        name_e14: marker.extra_field_name_14,
                        name_e15: marker.extra_field_name_15,
                        name_e16: marker.extra_field_name_16,
                        name_e17: marker.extra_field_name_17,
                        name_e18: marker.extra_field_name_18,
                        name_e19: marker.extra_field_name_19,
                        name_e20: marker.extra_field_name_20,
                        icon_b1: marker.extra_button_icon_1,
                        title_b1: marker.extra_button_title_1,
                        value_b1: marker.extra_button_value_1,
                        open_b1: parseInt(marker.open_extra_content),
                        rating: parseFloat(marker.rating),
                        num_reviews: parseInt(marker.num_reviews),
                        total_images: parseInt(marker.total_images),
                        distance: -1,
                        distance_html: '',
                        min_zoom_level: marker.min_zoom_level,
                        tripadvisor_location_id: marker.tripadvisor_location_id,
                        box_warning: marker.box_warning,
                        is_owner: parseInt(marker.is_owner || 0),
                        can_edit_pending: parseInt(marker.can_edit_pending || 0),
                        geometry: new ol.geom.Point(ol.proj.fromLonLat([marker.lon,marker.lat]))
                    });
                    feature.visible_cat = true;
                    features.push(feature);
                    k++;
                }
                if(window.lazy_loading===2 && window.marker_current_id!=0) {
                    for(var selected_index=0;selected_index<features.length;selected_index++) {
                        if(parseInt(features[selected_index].get('id_db'))===parseInt(window.marker_current_id)) {
                            selected_feature = selected_index;
                            break;
                        }
                    }
                }
                progress_circle.animate(1);
                if(window.song_bg!=='' || is_marker_audio) {
                    $('.btn_song_map').show();
                }
                if(window.song_bg!=='') {
                    if (window.song_bg.startsWith("song_")) {
                        audio_player.src = "content/" + window.song_bg;
                    } else {
                        audio_player.src = window.song_bg;
                    }
                }
                setTimeout(function() {
                    if(current_request_sequence!==marker_request_sequence) return;
                    if(features.length==0) {
                        if(window.lazy_loading===2) {
                            if(clusters_layer!==undefined) {
                                map.removeLayer(clusters_layer);
                                clusters_layer = undefined;
                            }
                            features_filter = [];
                            parse_featured();
                            draw_lines();
                            draw_geofence();
                            parse_html_list();
                            $('.list_icon, .nav_marker_prev, .nav_marker_next').not('.disabled2').addClass('disabled2 viewport-empty-disabled');
                        }
                        if(window.lazy_loading==0) {
                            draw_geometries();
                            map.getView().setCenter(ol.proj.fromLonLat([0, 0]));
                            map.getView().setZoom(1);
                        }
                        complete_map_startup();
                        initialize_startup_overlays();
                        set_markers_loading_state(false,false,rsp.truncated===true);
                        refresh_markers_after_lazy_load();
                        $(window).trigger('sml:markers-loaded',[features]);
                    } else {
                        setTimeout(function () {
                            if(current_request_sequence!==marker_request_sequence) return;
                            $('.viewport-empty-disabled').removeClass('disabled2 viewport-empty-disabled');
                            if(window.lazy_loading===2 && clusters_layer!==undefined) {
                                map.removeLayer(clusters_layer);
                            }
                            add_markers(false);
                            if(window.lazy_loading==0) {
                                draw_geometries();
                            }
                            parse_featured();
                            draw_lines();
                            draw_geofence();
                            parse_html_list();
                            var preserve_user_view = window.lazy_loading===2 || (window.lazy_loading>0 && user_interacted_during_marker_load && !window.marker_sel_exists);
                            if(!preserve_user_view) {
                                if(lat_center!=null && window.initial_coordinates=='') {
                                    map_view.setCenter(ol.proj.fromLonLat([lon_center, lat_center]));
                                    if(default_zoom==0) {
                                        map_view.setZoom(10);
                                    } else {
                                        map_view.setZoom(default_zoom);
                                    }
                                } else {
                                    if(default_zoom>0) {
                                        if(window.initial_coordinates!='') {
                                            map_view.setZoom(default_zoom);
                                        } else {
                                            map_view.animate({
                                                center: ol.extent.getCenter((markers_source.getExtent())),
                                                zoom: default_zoom,
                                                duration: 500
                                            });
                                        }
                                    } else {
                                        if(features.length==1) {
                                            if($('#featured_container').css('opacity')=='1') {
                                                map_view.fit(markers_source.getExtent(), {duration: 500,padding: [100, 100, 225, 100], nearest: true, maxZoom:14});
                                            } else {
                                                map_view.fit(markers_source.getExtent(), {duration: 500,padding: [100, 100, 100, 100], nearest: true, maxZoom:14});
                                            }
                                        } else {
                                            if($('#featured_container').css('opacity')=='1') {
                                                map_view.fit(markers_source.getExtent(), {duration: 500,padding: [100, 100, 225, 100], nearest: true});
                                            } else {
                                                map_view.fit(markers_source.getExtent(), {duration: 500,padding: [100, 100, 100, 100], nearest: true});
                                            }
                                        }
                                    }
                                }
                            }
                            if(window.enable_categories>0 && viewport_reload) {
                                viewport_filter_refresh = true;
                                filter_by_category();
                            } else if(window.enable_categories>0) {
                                if(window.cat_sel==0) {
                                    var cat_d_sel = 0;
                                    jQuery.each(categories, function(index, category) {
                                        if(category.default_selected==1) {
                                            cat_d_sel++;
                                            toggle_check_item(category.id,false,true);
                                        }
                                    });
                                    if(cat_d_sel>0 || window.no_category_sel_mode==1) {
                                        filter_by_category();
                                    }
                                } else {
                                    toggle_check_item(window.cat_sel,false,true);
                                    filter_by_category();
                                }
                            }
                            complete_map_startup();
                            initialize_startup_overlays();
                            set_markers_loading_state(false,false,rsp.truncated===true);
                            refresh_markers_after_lazy_load();
                            if(viewport_reload && $('#searchbox').val()!=='') {
                                $('#searchbox').trigger('input');
                            }
                            if(!viewport_reload) switch(show_list) {
                                case 1:
                                    open_list_detail();
                                    break;
                                case 2:
                                    if(window.innerWidth > 600) {
                                        open_list_detail();
                                    }
                                    break;
                                case 3:
                                    if(window.innerWidth <= 600) {
                                        open_list_detail();
                                    }
                                    break;
                            }
                            if(!viewport_reload && window.marker_sel!=0) {
                                for(var i=0;i<features.length;i++) {
                                    var id = features[i].get('id_db');
                                    if(id==window.marker_sel) {
                                        open_sheet_detail(features[i].get('id'),false);
                                    }
                                }
                            }
                            $(window).trigger('sml:markers-loaded',[features]);
                        },window.lazy_loading===2 ? 0 : 200);
                    }
                    if(!viewport_reload && window.lazy_loading!==2) {
                        setTimeout(function() {
                            initialCenter = map_view.getCenter();
                            initialZoom = map_view.getZoom();
                        },1000);
                    }
                    $(window).trigger('resize');
                },window.lazy_loading===2 ? 0 : 500);
            },
            error: function (xhr,text_status) {
                if(current_request_sequence!==marker_request_sequence) return;
                clearInterval(interval_progress);
                if(text_status==='abort') return;
                requested_marker_bbox_key = null;
                window.markers_load_failed = true;
                $('#searchbox').attr('aria-busy','false');
                set_markers_load_error_state();
                $(window).trigger('sml:markers-load-error');
                if(window.lazy_loading==0) {
                    alert('Error getting markers, please retry later.');
                }
            }
        });
    }

    function open_initial_add_marker() {
        if(window.add_marker_open!=1) return;
        if(window.lazy_loading>0 && !window.markers_loaded && !window.markers_load_failed) {
            $(window).one('sml:markers-loaded sml:markers-load-error',function () {
                open_add_new_marker();
            });
        } else {
            open_add_new_marker();
        }
    }

    function get_add_marker_boundaries() {
        $.ajax({
            url: "ajax/get_add_marker_boundaries.php",
            type: "POST",
            data: {
                id_map: window.id_map
            },
            async: true,
            success: function (json) {
                try {
                    var geojson_data = JSON.parse(json);
                    if (geojson_data && geojson_data.features && geojson_data.features.length > 0) {
                        var format = new ol.format.GeoJSON();
                        var features = format.readFeatures(geojson_data, {
                            featureProjection: map.getView().getProjection()
                        });
                        add_marker_boundaries_source = new ol.source.Vector({
                            features: features
                        });
                        add_marker_boundaries_layer = new ol.layer.Vector({
                            source: add_marker_boundaries_source,
                            style: new ol.style.Style({
                                stroke: new ol.style.Stroke({
                                    color: 'rgba(0, 153, 255, 0.8)',
                                    width: 2
                                }),
                                fill: new ol.style.Fill({
                                    color: 'rgba(0, 153, 255, 0.1)'
                                })
                            }),
                            visible: false,
                            zIndex: 15
                        });
                        map.addLayer(add_marker_boundaries_layer);
                    }
                } catch(e) {
                    console.error(e);
                }
                $('.new_marker_btn').removeClass('disabled');
                open_initial_add_marker();
            },
            error: function() {
                $('.new_marker_btn').removeClass('disabled');
                open_initial_add_marker();
            }
        });
    }

    window.isPointInAllowedBoundaries = function(coordinate) {
        if (!add_marker_boundaries_source || add_marker_boundaries_source.getFeatures().length === 0) {
            return true;
        }
        var features = add_marker_boundaries_source.getFeatures();
        for (var i = 0; i < features.length; i++) {
            if (features[i].getGeometry().intersectsCoordinate(coordinate)) {
                return true;
            }
        }
        return false;
    };

    function init_audio_player() {
        audio_player.volume = 0.01;
        audio_player.muted = false;
        audio_player.onplay = function() {
            if(first_song_play) {
                if(!$('.btn_song_map').hasClass('open')) {
                    $('.btn_song_map').addClass('open');
                    $('.btn_song_map').addClass('active_c');
                    $('.btn_song_map i').removeClass('fa-volume-mute').addClass('fa-volume-down');
                }
                fadeVolume(audio_player,window.main_song_bg_volume,500);
                first_song_play = false;
            }
        };
        if(window.song_bg!=='') {
            if(window.song_loop==1) {
                if (typeof audio_player.loop == 'boolean') {
                    audio_player.loop = true;
                } else {
                    audio_player.addEventListener('ended', function() {
                        this.currentTime = 0;
                        this.play();
                    }, false);
                }
            } else {
                audio_player.loop = false;
            }
            switch(window.song_autoplay) {
                case 1:
                    audio_player.play().catch(function(error) {
                        $(document).on("mousedown touchstart",function(e){
                            if ($(e.target).hasClass("btn_song_map")) {
                                return;
                            }
                            if(first_song_play) {
                                try {
                                    audio_player.play().catch(function () {});
                                } catch (e) {}
                            }
                        });
                    });
                    break;
                case 2:
                    audio_prompt = $.confirm({
                        lazyOpen: true,
                        theme: 'modern,audio_prompt',
                        useBootstrap: false,
                        closeIcon: false,
                        typeAnimated: true,
                        title: window.viewer_labels.enable_audio,
                        content: '',
                        boxWidth: '250px',
                        buttons: {
                            yes: {
                                text: window.viewer_labels.yes,
                                btnClass: 'btn-green',
                                action: function(){
                                    audio_player.play().catch(function () {});
                                }
                            },
                            cancel : {
                                text: window.viewer_labels.no
                            },
                        }
                    });
                    if(audio_prompt!=null) {
                        audio_prompt.open();
                    }
                    break;
            }
        } else {
            switch(window.song_autoplay) {
                case 1:
                    $('.btn_song_map').addClass('open');
                    $('.btn_song_map').addClass('active_c');
                    $('.btn_song_map i').removeClass('fa-volume-mute').addClass('fa-volume-down');
                break;
                case 2:
                    audio_prompt = $.confirm({
                        lazyOpen: true,
                        theme: 'modern,audio_prompt',
                        useBootstrap: false,
                        closeIcon: false,
                        typeAnimated: true,
                        title: window.viewer_labels.enable_audio,
                        content: '',
                        boxWidth: '250px',
                        buttons: {
                            yes: {
                                text: window.viewer_labels.yes,
                                btnClass: 'btn-green',
                                action: function(){
                                    $('.btn_song_map').addClass('open');
                                    $('.btn_song_map').addClass('active_c');
                                    $('.btn_song_map i').removeClass('fa-volume-mute').addClass('fa-volume-down');
                                }
                            },
                            cancel : {
                                text: window.viewer_labels.no
                            },
                        }
                    });
                    if(audio_prompt!=null) {
                        audio_prompt.open();
                    }
                    break;
            }
        }
    }

    function parse_category_icon(category) {
        var color_hex = category.color_hex;
        var icon_color_hex = category.icon_color_hex;
        if(category.icon!=='' && category.icon!==null && category.icon!==undefined) {
            var tmp_icon = category.icon.split("|");
            var icon = tmp_icon[0];
        } else {
            var icon = '';
        }
        var icon_image = category.icon_image;
        if(icon_image!=='' && icon_image!==null && icon_image!==undefined) {
            var html_icon = "<div class='category_icon'>";
            html_icon += "<img src='icons/"+icon_image+"' />";
        } else if(icon!=='' && icon!==null && icon!==undefined) {
            var html_icon = "<div style='background-color: "+color_hex+"' class='category_icon'>";
            if(color_hex=='') {
                html_icon += "<i style='font-size:18px;vertical-align:sub;color: "+icon_color_hex+"' class='"+icon+"'></i>";
            } else {
                html_icon += "<i style='font-size:10px;vertical-align:middle;color: "+icon_color_hex+"' class='"+icon+"'></i>";
            }
        } else {
            var html_icon = "<div style='width:20px;height:20px;background-color: "+color_hex+"' class='category_icon'>";
        }
        html_icon += "</div>";
        return html_icon;
    }

    var categoryMap = {};
    var categoryTree = [];
    var num_subcat = 0;
    function parse_html_categories() {
        var html_categories = "";
        num_subcat = 0;
        if(categories.length>0) {
            if(window.cat_filter_switch==1) {
                var html_and_or = '<div id="and_or_switch_div" class="form-group radio-toggle">' +
                    '<div class="form-check">' +
                    '<label onclick="switch_filter_type(\'or\');" data-type="or" class="form-check-label">' +
                    '<input class="form-check-input" type="radio" name="and_or_switch_radio" id="and_or_switch" value="or" '+((window.cat_filter_type=='or') ? 'checked' : '')+'>' +
                    window.viewer_labels.or +
                    '</label>' +
                    '<label onclick="switch_filter_type(\'and\');" data-type="and" class="form-check-label">' +
                    '<input class="form-check-input" type="radio" name="and_or_switch_radio" id="and_or_switch" value="and" '+((window.cat_filter_type=='and') ? 'checked' : '')+'>' +
                    window.viewer_labels.and +
                    '</label>' +
                    '</div>' +
                    '</div>';
            } else {
                var html_and_or = '';
            }
            html_categories = "<div id='category_header'><div class='title-filters'>"+window.viewer_labels.filters+html_and_or+"</div><div class='reset-filters'><div onclick='select_all_categories();' class='select_all_categories_btn'><i class='fas fa-check-double'></i> "+window.viewer_labels.select_all+"</div><div onclick='reset_categories();' class='reset_categories_btn disabled'><i class='fas fa-times'></i> "+window.viewer_labels.reset+"</div></div></div>";
            html_categories += '<ul class="category-list">';
            jQuery.each(categories, function(index, category) {
                category.children = [];
                categoryMap[category.id] = category;
            });
            jQuery.each(categories, function(index, category) {
                var id_category_parent = parseInt(category.id_category_parent);
                if (id_category_parent !== 0) {
                    if (categoryMap[id_category_parent]) {
                        categoryMap[id_category_parent].children.push(category);
                    }
                    num_subcat++;
                } else {
                    categoryTree.push(category);
                }
            });
            function buildCategoryHtmlRecursive(categoryNodes) {
                var html = '';
                jQuery.each(categoryNodes, function(index, category) {
                    var id_category = category.id;
                    var name_category = category.name;
                    var count_m = category.count_m;
                    var id_category_parent = parseInt(category.id_category_parent);
                    var hasChildren = category.children && category.children.length > 0;
                    if (hasChildren) {
                        html += '<li data-id="'+id_category+'" class="category-list-item">\n' +
                            '            <div data-expand="0" onclick="toggle_expand_category('+id_category+')" class="category-icon-expand">\n' +
                            '                <i class="fa-solid fa-chevron-right"></i>\n' +
                            '            </div>\n' +
                            '            <div data-checked="0" onclick="toggle_check_item('+id_category+',true,false);" class="category-icon-check">\n' +
                            '                <svg width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z"></path></svg>\n' +
                            '            </div>\n' +
                            '            <div onclick="toggle_expand_category('+id_category+');" class="category-icon-image">\n' +
                            parse_category_icon(category) +
                            '            </div>\n' +
                            '            <div onclick="toggle_expand_category('+id_category+');" class="category-title">'+name_category+'</div>\n' +
                            '            <div onclick="toggle_expand_category('+id_category+');" class="category-count">'+count_m+'</div>\n' +
                            '        </li>';

                        html += '<ul data-id-parent="'+id_category+'" class="subcategory-list" style="display:none">';
                        html += buildCategoryHtmlRecursive(category.children);
                        html += '</ul>';
                    } else {
                        if (id_category_parent === 0) {
                            html += '<li data-id="'+id_category+'" class="category category-list-item">\n' +
                                '            <div class="category-icon-expand">\n' +
                                '            </div>\n' +
                                '            <div data-checked="0" onclick="toggle_check_item('+id_category+',true,false);" class="category-icon-check">\n' +
                                '                <svg width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z"></path></svg>\n' +
                                '            </div>\n' +
                                '            <div onclick="toggle_check_item('+id_category+',true,false);" class="category-icon-image">\n' +
                                parse_category_icon(category) +
                                '            </div>\n' +
                                '            <div onclick="toggle_check_item('+id_category+',true,false);" class="category-title">'+name_category+'</div>\n' +
                                '            <div onclick="toggle_check_item('+id_category+',true,false);" class="category-count">'+count_m+'</div>\n' +
                                '        </li>';
                        } else {
                            html += '<li data-id="'+id_category+'" class="category subcategory-list-item">\n' +
                                '                <div data-checked="0" onclick="toggle_check_item('+id_category+',true,false);" class="category-icon-check">\n' +
                                '                    <svg width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z"></path></svg>\n' +
                                '                </div>\n' +
                                '                <div onclick="toggle_check_item('+id_category+',true,false);" class="category-icon-image">\n' +
                                parse_category_icon(category) +
                                '                </div>\n' +
                                '                <div onclick="toggle_check_item('+id_category+',true,false);" class="category-title">'+name_category+'</div>\n' +
                                '                <div onclick="toggle_check_item('+id_category+',true,false);" class="category-count">'+count_m+'</div>\n' +
                                '            </li>';
                        }
                    }
                });
                return html;
            }
            html_categories += buildCategoryHtmlRecursive(categoryTree);
            html_categories += '</ul>';
            $('.categories_div').html(html_categories).promise().done(function () {
                if(num_subcat==0) {
                    $('.category-icon-expand').hide();
                }
                $('#and_or_switch_div').toggleInput();
                $('.filter_icon').show();
                switch(cat_filter) {
                    case 1:
                        toggle_categories();
                        break;
                    case 2:
                        if(window.innerWidth > 600) {
                            toggle_categories();
                        }
                        break;
                    case 3:
                        if(window.innerWidth <= 600) {
                            toggle_categories();
                        }
                        break;
                }
            });
        }
    }

    function getAllDescendantIds(categoryId) {
        var descendants = [];
        var category = categoryMap[categoryId];
        function findChildrenRecursive(node) {
            if (node && node.children) {
                node.children.forEach(function(child) {
                    descendants.push(child.id);
                    findChildrenRecursive(child); // Chiamata ricorsiva per i nipoti
                });
            }
        }
        findChildrenRecursive(category);
        return descendants;
    }

    function updateAncestorStatus(categoryId) {
        var category = categoryMap[categoryId];
        if (!category || parseInt(category.id_category_parent) === 0) {
            return;
        }
        var parentId = category.id_category_parent;
        var parentCheckIcon = $('li[data-id="' + parentId + '"]').find('.category-icon-check').first();
        var parentCategory = categoryMap[parentId];
        var numChildren = parentCategory.children.length;
        var checkedCount = 0;
        var partialCount = 0;
        parentCategory.children.forEach(function(child) {
            var childState = parseInt($('li[data-id="' + child.id + '"]').find('.category-icon-check').first().attr('data-checked'));
            if (childState === 1) {
                checkedCount++;
            } else if (childState === 2) {
                partialCount++;
            }
        });
        var newParentState;
        var newParentIcon;
        if (partialCount > 0 || (checkedCount > 0 && checkedCount < numChildren)) {
            newParentState = 2;
            newParentIcon = icon_check_category_2;
        } else if (checkedCount === numChildren) {
            newParentState = 1;
            newParentIcon = icon_check_category_1;
        } else {
            newParentState = 0;
            newParentIcon = icon_check_category_0;
        }
        parentCheckIcon.attr('data-checked', newParentState);
        parentCheckIcon.html(newParentIcon);
        updateAncestorStatus(parentId);
    }

    window.toggle_check_item = function(id, filter, force) {
        var checkIcon = $('li[data-id="' + id + '"]').find('.category-icon-check').first();
        var currentState = parseInt(checkIcon.attr('data-checked'));
        if(force==-1) {
            var newState = 0;
        } else {
            var newState = (currentState === 0 || currentState === 2 || force) ? 1 : 0;
        }
        checkIcon.attr('data-checked', newState);
        checkIcon.html(newState === 1 ? icon_check_category_1 : icon_check_category_0);
        var descendantIds = getAllDescendantIds(id);
        descendantIds.forEach(function(descId) {
            var descCheckIcon = $('li[data-id="' + descId + '"]').find('.category-icon-check').first();
            descCheckIcon.attr('data-checked', newState);
            descCheckIcon.html(newState === 1 ? icon_check_category_1 : icon_check_category_0);
        });
        updateAncestorStatus(id);
        if (filter) {
            setTimeout(function() { filter_by_category(); }, 0);
        }
    }

    window.toggle_expand_category = function(id) {
        var expandIconContainer = $('li[data-id="'+id+'"]').find('.category-icon-expand').first();
        var expand = parseInt(expandIconContainer.attr('data-expand'));
        var sublist = $('ul[data-id-parent="'+id+'"]');
        if (expand === 0) {
            expandIconContainer.attr('data-expand', 1);
            expandIconContainer.find('i').removeClass('fa-chevron-right').addClass('fa-chevron-down');
            sublist.show();
        } else {
            expandIconContainer.attr('data-expand', 0);
            expandIconContainer.find('i').removeClass('fa-chevron-down').addClass('fa-chevron-right');
            sublist.hide();
        }
    }


    window.reset_categories = function () {
        $('.categories_div .subcategory-list-item').each(function () {
            $(this).find('.category-icon-check').attr('data-checked',0);
            $(this).find('.category-icon-check').html(icon_check_category_0);
        });
        $('.categories_div .category-list-item').each(function () {
            $(this).find('.category-icon-check').attr('data-checked',0);
            $(this).find('.category-icon-check').html(icon_check_category_0);
        });
        setTimeout(function() { filter_by_category(); },0)
    }

    window.select_all_categories = function () {
        $('.categories_div .subcategory-list-item').each(function () {
            $(this).find('.category-icon-check').attr('data-checked',1);
            $(this).find('.category-icon-check').html(icon_check_category_1);
        });
        $('.categories_div .category-list-item').each(function () {
            $(this).find('.category-icon-check').attr('data-checked',1);
            $(this).find('.category-icon-check').html(icon_check_category_1);
        });
        setTimeout(function() { filter_by_category(); },0)
    }

    function check_marker_in_radius(my_coords,radius_m) {
        if(radius_m!=-1) create_radius(my_coords, radius_m);
        features_filter = [...features];
        var indicesToRemove = [];
        var featuresToAdd = [];
        const array_list_map = new Map(array_list.map(item => [item.id, item]));
        const features_map = new Map(features.map(item => [item.get('id_db'), item]));
        const featuresFilterIdSet = new Set(features_filter.map(item => item.get('id_db')));
        for(var i=0;i<features_filter.length;i++) {
            var visible_cat = features_filter[i].visible_cat;
            var id_feature = features_filter[i].get('id');
            var id_db_feature = features_filter[i].get('id_db');
            if(!visible_cat) {
                indicesToRemove.push(i);
                $('#list_block_'+id_feature).hide();
                $('#list_block_f_'+id_feature).hide();
                continue;
            }
            if(radius_m==-1) {
                var withinRange = true;
            } else {
                var markerCoord = features_filter[i].getGeometry().getCoordinates();
                var distance = calculateDistance(my_coords, markerCoord);
                var withinRange = distance <= radius_m;
            }
            const array_list_elem = array_list_map.get(id_feature);
            if(array_list_elem!==undefined) {
                const features_elem = features_map.get(id_db_feature);
                if (withinRange) {
                    array_list_elem.visible = true;
                    if (!featuresFilterIdSet.has(id_db_feature)) {
                        featuresToAdd.push(features_elem);
                        featuresFilterIdSet.add(id_db_feature);
                    }
                    features_elem.visible = true;
                    $('#list_block_'+id_feature).show();
                    $('#list_block_f_'+id_feature).show();
                } else {
                    array_list_elem.visible = false;
                    indicesToRemove.push(i);
                    features_elem.visible = false;
                    $('#list_block_'+id_feature).hide();
                    $('#list_block_f_'+id_feature).hide();
                }
            }
        }
        const indicesSet = new Set(indicesToRemove);
        features_filter = features_filter.filter((_, index) => !indicesSet.has(index));
        features_filter.push(...featuresToAdd);
        $('#featured_slider').trigger('refresh.owl.carousel');
        clusterize_list.update(filterRows(array_list,false));
        map.removeLayer(clusters_layer);
        add_markers(true);
        adjust_distances();
        draw_lines();
        draw_geofence();
    }

    function calculateDistance(coord1, coord2) {
        const [lon1, lat1] = ol.proj.toLonLat(coord1);
        const [lon2, lat2] = ol.proj.toLonLat(coord2);
        const R = 6371e3;
        const φ1 = (lat1 * Math.PI) / 180;
        const φ2 = (lat2 * Math.PI) / 180;
        const Δφ = ((lat2 - lat1) * Math.PI) / 180;
        const Δλ = ((lon2 - lon1) * Math.PI) / 180;
        const a =
            Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
            Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        const distance = R * c;
        return distance;
    }

    window.switch_filter_type = function(type) {
        window.cat_filter_type = type;
        filter_by_category();
    }

    window.filter_by_category = function() {
        setTimeout(function() {
            filter_by_category_exec();
        },10);
    }

    function filter_by_category_exec() {
        marker_index = -1;
        var count_categories = 0;
        var array_cat = [];
        var hideElements = [];
        var showElements = [];
        var all_selected = true;
        $('.categories_div .category').each(function () {
            var id_category_a = parseInt($(this).attr('data-id'));
            if (parseInt($(this).find('.category-icon-check').attr('data-checked')) == 1) {
                $('#category_featured_'+id_category_a).addClass('active_f');
                array_cat.push(id_category_a);
                count_categories++;
            } else {
                $('#category_featured_'+id_category_a).removeClass('active_f');
                all_selected = false;
            }
        });
        if(all_selected) {
            $('.select_all_categories_btn').addClass('disabled');
        } else {
            $('.select_all_categories_btn').removeClass('disabled');
        }
        $('#count_categories').html(count_categories);
        if (count_categories > 0) {
            $('#count_categories').css('opacity', 1);
            $('.reset_categories_btn').removeClass('disabled');
        } else {
            $('#count_categories').css('opacity', 0);
            $('.reset_categories_btn').addClass('disabled');
        }
        features_filter = [];
        geodata_filter = [];
        var marker_sel_to_show = 0;
        var markers_to_hide = [];
        for (var i = 0; i < features.length; i++) {
            var id_feature = features[i].get('id');
            var visible = features[i].get('visible');
            if (!visible) {
                markers_to_hide.push(features[i].get('id'));
                continue;
            }
            if(parseInt(window.marker_sel)==parseInt(features[i].get('id_db'))) {
                marker_sel_to_show = id_feature;
                features[i].visible_cat = true;
                features_filter.push(features[i]);
                if($('#list_block_' + id_feature).length) showElements.push($('#list_block_' + id_feature).get(0));
                if($('#list_block_f_' + id_feature).length) showElements.push($('#list_block_f_' + id_feature).get(0));
                continue;
            }
            var id_categories = features[i].get('id_categories');
            if (count_categories == 0) {
                if (window.no_category_sel_mode == 1) {
                    features[i].visible_cat = false;
                    if($('#list_block_' + id_feature).length) hideElements.push($('#list_block_' + id_feature).get(0));
                    if($('#list_block_f_' + id_feature).length) hideElements.push($('#list_block_f_' + id_feature).get(0));
                } else {
                    features[i].visible_cat = true;
                    features_filter.push(features[i]);
                    if($('#list_block_' + id_feature).length) showElements.push($('#list_block_' + id_feature).get(0));
                    if($('#list_block_f_' + id_feature).length) showElements.push($('#list_block_f_' + id_feature).get(0));
                }
            } else if (id_categories !== null && id_categories != 0) {
                var array_id_categories = id_categories.split(",");
                var cat_ok = false;
                switch (window.cat_filter_type) {
                    case 'and':
                        cat_ok = true;
                        var count_cat_ok = 0;
                        jQuery.each(array_id_categories, function (index, id_category_s) {
                            id_category_s = parseInt(id_category_s);
                            if (array_cat.includes(id_category_s) || array_cat.length == 0) {
                                count_cat_ok++;
                            }
                        });
                        if (count_cat_ok != count_categories) {
                            cat_ok = false;
                        }
                        break;
                    case 'or':
                        jQuery.each(array_id_categories, function (index, id_category_s) {
                            id_category_s = parseInt(id_category_s);
                            if (array_cat.includes(id_category_s) || array_cat.length == 0) {
                                cat_ok = true;
                            }
                        });
                        break;
                }
                if (cat_ok) {
                    features[i].visible_cat = true;
                    features_filter.push(features[i]);
                    if($('#list_block_' + id_feature).length) showElements.push($('#list_block_' + id_feature).get(0));
                    if($('#list_block_f_' + id_feature).length) showElements.push($('#list_block_f_' + id_feature).get(0));
                } else {
                    features[i].visible_cat = false;
                    if($('#list_block_' + id_feature).length) hideElements.push($('#list_block_' + id_feature).get(0));
                    if($('#list_block_f_' + id_feature).length) hideElements.push($('#list_block_f_' + id_feature).get(0));
                }
            }
        }
        for (var i = 0; i < geodatas.length; i++) {
            var id_categories = geodatas[i].id_categories;
            if (count_categories == 0) {
                if (window.no_category_sel_mode == 1) {
                    geodatas[i].visible_cat = true;
                } else {
                    geodatas[i].visible_cat = true;
                    geodata_filter.push(geodatas[i]);
                }
            } else if (id_categories !== null && id_categories != 0 && id_categories != '') {
                var array_id_categories = id_categories.split(",");
                var cat_ok = false;
                switch (window.cat_filter_type) {
                    case 'and':
                        cat_ok = true;
                        var count_cat_ok = 0;
                        jQuery.each(array_id_categories, function (index, id_category_s) {
                            id_category_s = parseInt(id_category_s);
                            if (array_cat.includes(id_category_s) || array_cat.length == 0) {
                                count_cat_ok++;
                            }
                        });
                        if (count_cat_ok != count_categories) {
                            cat_ok = false;
                        }
                        break;
                    case 'or':
                        jQuery.each(array_id_categories, function (index, id_category_s) {
                            id_category_s = parseInt(id_category_s);
                            if (array_cat.includes(id_category_s) || array_cat.length == 0) {
                                cat_ok = true;
                            }
                        });
                        break;
                }
                if (cat_ok) {
                    geodatas[i].visible_cat = true;
                    geodata_filter.push(geodatas[i]);
                } else {
                    geodatas[i].visible_cat = false;
                }
            } else {
                geodatas[i].visible_cat = true;
                geodata_filter.push(geodatas[i]);
            }
        }
        setTimeout(function() {
            $(showElements).show();
            $(hideElements).hide();
            $('#featured_slider').trigger('refresh.owl.carousel');
        },0);
        for (var i = 0, ii = array_list.length; i < ii; i++) {
            if (markers_to_hide.includes(array_list[i].id)) {
                array_list[i].visible = false;
            } else {
                var id_categories = array_list[i].id_categories;
                if (count_categories == 0) {
                    if (window.no_category_sel_mode == 1) {
                        if(parseInt(marker_sel_to_show)==parseInt(array_list[i].id)) {
                            array_list[i].cat_active = true;
                        } else {
                            array_list[i].cat_active = false;
                        }
                    } else {
                        array_list[i].cat_active = true;
                    }
                } else if (id_categories !== null && id_categories != 0) {
                    var array_id_categories = id_categories.split(",");
                    var cat_ok = false;
                    switch (window.cat_filter_type) {
                        case 'and':
                            cat_ok = true;
                            var count_cat_ok2 = 0;
                            jQuery.each(array_id_categories, function (index, id_category_s) {
                                id_category_s = parseInt(id_category_s);
                                if (array_cat.includes(id_category_s) || array_cat.length == 0) {
                                    count_cat_ok2++;
                                }
                            });
                            if (count_cat_ok2 != count_categories) {
                                cat_ok = false;
                            }
                            break;
                        case 'or':
                            jQuery.each(array_id_categories, function (index, id_category_s) {
                                id_category_s = parseInt(id_category_s);
                                if (array_cat.includes(id_category_s) || array_cat.length == 0) {
                                    cat_ok = true;
                                }
                            });
                            break;
                    }
                    array_list[i].cat_active = cat_ok;
                } else {
                    array_list[i].cat_active = false;
                }
            }
        }
        clusterize_list.update(filterRows(array_list,true));
        map.removeLayer(clusters_layer);
        add_markers(true);
        adjust_distances();
        draw_lines();
        draw_geofence();
        $('.loading_geodata').hide();
        if (geodatas.length > 0) {
            draw_geodata(true);
        }
        if (features_filter.length == 0) {
            $('.list_icon').addClass('disabled2');
            $('.nav_marker_next').addClass('disabled2');
            $('.nav_marker_prev').addClass('disabled2');
        } else {
            $('.list_icon').removeClass('disabled2');
            $('.nav_marker_next').removeClass('disabled2');
            $('.nav_marker_prev').removeClass('disabled2');
        }
        var preserve_user_view = viewport_filter_refresh || (first_time_filter && (window.lazy_loading===2 || (window.lazy_loading>0 && user_interacted_during_marker_load)));
        if (window.fit_categories == 1 && count_categories > 0 && !window.marker_sel_exists && !preserve_user_view) {
            try {
                if ($('#featured_container').css('opacity') == '1') {
                    map.getView().fit(markers_source.getExtent(), {
                        duration: 500,
                        padding: [100, 100, 225, 100],
                        nearest: true,
                        maxZoom: 16
                    });
                } else {
                    map.getView().fit(markers_source.getExtent(), {
                        duration: 500,
                        padding: [100, 100, 100, 100],
                        nearest: true,
                        maxZoom: 16
                    });
                }
            } catch (e) {}
        }
        if(search_radius_enabled) {
            var coordinates = geolocation.getPosition();
            if (coordinates) {
                check_marker_in_radius(coordinates,window.search_radius_m);
            }
        }
        first_time_filter = false;
        viewport_filter_refresh = false;
    }

    var step_markers = 0;
    function add_markers(filter) {
        marker_index==-1;
        if (filter) {
            markers_source = new ol.source.Vector({
                features: features_filter,
            });
            var total_markers = features_filter.length;
        } else {
            markers_source = new ol.source.Vector({
                features: features,
            });
            var total_markers = features.length;
            features_filter = features;
        }
        step_markers = total_markers / 4 / window.custer_color_tolerance;
        if(window.map_mode=='large') {
            window.cluster_distance = 0;
        }
        markers_source_cluster = new ol.source.Cluster({
            distance: window.cluster_distance,
            source: markers_source
        });
        if(globe_mode) {
            var source_layer = markers_source;
        } else {
            var source_layer = markers_source_cluster;
        }
        if(window.map_mode=='large') {
            var style = {
                'circle-radius': [
                    'interpolate',
                    ['exponential', window.markers_size],
                    ['zoom'],
                    5,
                    1.5,
                    18,
                    1.5 * Math.pow(window.markers_size, 10),
                ],
                'circle-fill-color': window.markers_color_hex,
                'circle-displacement': [0.5, 0.5],
                'circle-opacity': 1,
            };
            if(!window.is_webgl) {
                clusters_layer = new ol.layer.Vector({
                    updateWhileAnimating: updateWhileAnimating,
                    updateWhileInteracting: updateWhileInteracting,
                    source: source_layer,
                    zIndex: 10,
                    style: style
                });
            } else {
                clusters_layer = new ol.layer.WebGLVector({
                    updateWhileAnimating: updateWhileAnimating,
                    updateWhileInteracting: updateWhileInteracting,
                    source: source_layer,
                    zIndex: 10,
                    style: style
                });
            }
        } else {
            if(window.cluster_animation==0) {
                clusters_layer = new ol.layer.Vector({
                    updateWhileAnimating: updateWhileAnimating,
                    updateWhileInteracting: updateWhileInteracting,
                    renderBuffer: renderBuffer,
                    source: source_layer,
                    zIndex: 10,
                    style: getStyleCluster
                });
            } else {
                clusters_layer = new ol.layer.AnimatedCluster({
                    updateWhileAnimating: false,
                    updateWhileInteracting: true,
                    renderBuffer: renderBuffer,
                    source: source_layer,
                    animationDuration: window.cluster_animation,
                    style: getStyleCluster
                });
            }
        }
        clusters_layer.setZIndex(20);
        if(!filter && !map_initialized) clusters_layer.setOpacity(0);
        map.addLayer(clusters_layer);
    }

    window.clusterStyleCache = window.clusterStyleCache || {};
    window.markerIconStyleCache = window.markerIconStyleCache || {};
    window.ownPendingMarkerStyleCache = window.ownPendingMarkerStyleCache || {};
    function get_own_pending_marker_style(scale) {
        var key = window.main_color_hex + '_' + window.darker_color_hex + '_' + scale;
        if(!window.ownPendingMarkerStyleCache[key]) {
            var radius = 14 * scale;
            var font_size = 12 * scale;
            window.ownPendingMarkerStyleCache[key] = [
                new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: radius + 4,
                        fill: new ol.style.Fill({ color: hexToRgbA('#ffffff',0.95) }),
                        stroke: new ol.style.Stroke({ color: hexToRgbA(window.darker_color_hex,0.95), width: 3 })
                    })
                }),
                new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: radius,
                        fill: new ol.style.Fill({ color: hexToRgbA(window.main_color_hex,1) }),
                        stroke: new ol.style.Stroke({ color: '#ffffff', width: 2 })
                    }),
                    text: new ol.style.Text({
                        text: String.fromCharCode("0xf044"),
                        textAlign: "center",
                        textBaseline: "middle",
                        font: '900 '+font_size+'px "Font Awesome 7 Free"',
                        fill: new ol.style.Fill({ color: '#ffffff' })
                    })
                })
            ];
        }
        return window.ownPendingMarkerStyleCache[key];
    }
    var getStyleCluster = function(feature) {
        var size = 1;
        var current_zoom = parseInt(map.getView().getZoom());
        if(globe_mode) {
            var visible_map = feature.get('visible_map');
            var icon_image = feature.get('icon_image');
            var icon_base64 = feature.get('icon_base64');
            var active = feature.get('active');
            var style_m = feature.get('style');
            var style_label = feature.get('style_label');
            var marker_size = feature.get('size');
            var min_zoom_level = feature.get('min_zoom_level');
            var can_edit_pending = feature.get('can_edit_pending');
        } else {
            var features = feature.get('features');
            if(features===undefined) {
                var visible_map = feature.get('visible_map');
                var icon_image = feature.get('icon_image');
                var icon_base64 = feature.get('icon_base64');
                var active = feature.get('active');
                var style_m = feature.get('style');
                var style_label = feature.get('style_label');
                var marker_size = feature.get('size');
                var min_zoom_level = feature.get('min_zoom_level');
                var can_edit_pending = feature.get('can_edit_pending');
            } else {
                var visible_map = features[0].get('visible_map');
                var icon_image = features[0].get('icon_image');
                var icon_base64 = features[0].get('icon_base64');
                var active = features[0].get('active');
                var style_m = features[0].get('style');
                var style_label = features[0].get('style_label');
                var marker_size = features[0].get('size');
                var min_zoom_level = features[0].get('min_zoom_level');
                var can_edit_pending = features[0].get('can_edit_pending');
                var count_f = 0;
                for (var t = 0; t < features.length; t++) {
                    if (current_zoom >= parseInt(features[t].values_.min_zoom_level || 0)) {
                        count_f++;
                    }
                }
                size = count_f;
            }
        }
        if(parseInt(visible_map)==0) {
            return null;
        }
        if(size>1) {
            var color = main_color_hex;
            var dark_color = darker_color_hex;
            if(density_color==1) {
                var density_size = size / step_markers;
                if(density_size<=1.5) {
                    color = '#00D61D'; dark_color = '#00b51b';
                } else if(density_size>1.5 && density_size<=2.5) {
                    color = '#ffcd00'; dark_color = '#e5b300';
                } else if(density_size>2.5 && density_size<=3.5) {
                    color = '#ff7800'; dark_color = '#d26200';
                } else {
                    color = '#ff2c00'; dark_color = '#cd2400';
                }
            }
            var size_cluser = size >= 1000 ? (size / 1000).toFixed(0) + 'k' : size.toString();
            var clusterCacheKey = size_cluser + '_' + dark_color;
            if (!window.clusterStyleCache[clusterCacheKey]) {
                window.clusterStyleCache[clusterCacheKey] = [
                    new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 15,
                            fill: new ol.style.Fill({ color: dark_color, weight: 1 })
                        }),
                        text: new ol.style.Text({
                            text: size_cluser,
                            textAlign: "center",
                            textBaseline: "middle",
                            font: "13.2px sans-serif",
                            fill: new ol.style.Fill({ color: '#ffffff' })
                        })
                    }),
                    new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 15,
                            stroke: new ol.style.Stroke({ color: hexToRgbA(dark_color,0.9), width: 4 })
                        })
                    }),
                    new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 19,
                            stroke: new ol.style.Stroke({ color: hexToRgbA(dark_color,0.5), width: 4 })
                        })
                    }),
                    new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 23,
                            stroke: new ol.style.Stroke({ color: hexToRgbA(dark_color,0.2), width: 4 })
                        })
                    }),
                ];
            }
            return window.clusterStyleCache[clusterCacheKey];
        } else {
            if (current_zoom < parseInt(min_zoom_level || 0)) {
                return null;
            }
            if(parseInt(can_edit_pending || 0)===1) {
                var pending_scale = marker_size == 0 ? window.markers_size : marker_size;
                return get_own_pending_marker_style(pending_scale);
            }
            var opacity = active == 1 ? 1 : 0.4;
            var scale = icon_base64 != '' ? (marker_size == 0 ? window.markers_size : marker_size) : (marker_size == 0 ? window.markers_size/10 : marker_size/10);
            if(icon_image == '') {
                return style_label != null ? [style_m, style_label] : style_m;
            } else {
                var inner_features = feature.get('features');
                var id_marker = (globe_mode || inner_features === undefined) ? feature.get('id') : inner_features[0].get('id');
                if(icon_image.includes('.gif')) {
                    if(array_gif[id_marker]==undefined) {
                        const gifUrl = 'icons/'+icon_image;
                        array_gif[id_marker] = gifler(gifUrl);
                    }
                    if(array_gif_canvas[id_marker]==undefined) {
                        array_gif_canvas[id_marker]=document.createElement('canvas');
                    } else {
                        const context = array_gif_canvas[id_marker].getContext('2d');
                        context.clearRect(0, 0, array_gif_canvas[id_marker].width, array_gif_canvas[id_marker].height);
                    }
                    var style = '';
                    array_gif[id_marker].frames(
                        array_gif_canvas[id_marker],
                        function (ctx, frame) {
                            var f = (globe_mode || inner_features === undefined) ? feature : inner_features[0];
                            if (!f.getStyle()) {
                                f.setStyle(
                                    new ol.style.Style({
                                        image: new ol.style.Icon({
                                            anchor: [0.5, 150],
                                            anchorXUnits: 'fraction',
                                            anchorYUnits: 'pixels',
                                            scale: scale,
                                            opacity: opacity,
                                            img: ctx.canvas,
                                            imgSize: [frame.width, frame.height]
                                        }),
                                    })
                                );
                            }
                            ctx.clearRect(0, 0, frame.width, frame.height);
                            ctx.drawImage(frame.buffer, frame.x, frame.y);
                            map.render();
                        }, true);
                    return null;
                } else {
                    var iconKey = icon_image + '_' + icon_base64 + '_' + scale + '_' + opacity;
                    if (!window.markerIconStyleCache[iconKey]) {
                        window.markerIconStyleCache[iconKey] = new ol.style.Style({
                            image: new ol.style.Icon({
                                anchor: [0.5, 0.5],
                                anchorXUnits: 'fraction',
                                anchorYUnits: 'fraction',
                                scale: icon_base64 != '' ? 1 : scale,
                                opacity: opacity,
                                src: icon_base64 != '' ? icon_base64 : 'icons/'+icon_image,
                            })
                        });
                    }
                    var style_i = window.markerIconStyleCache[iconKey];
                    return style_label != null ? [style_i, style_label] : style_i;
                }
            }
        }
    }

    var midPoint = function(latitude1, longitude1, latitude2, longitude2) {
        var DEG_TO_RAD = Math.PI / 180;
        var lat1 = latitude1 * DEG_TO_RAD;
        var lat2 = latitude2 * DEG_TO_RAD;
        var lng1 = longitude1 * DEG_TO_RAD;
        var dLng = (longitude2 - longitude1) * DEG_TO_RAD;
        var bx = Math.cos(lat2) * Math.cos(dLng);
        var by = Math.cos(lat2) * Math.sin(dLng);
        var lat = Math.atan2(
            Math.sin(lat1) + Math.sin(lat2),
            Math.sqrt((Math.cos(lat1) + bx) * (Math.cos(lat1) + bx) + by * by));
        var lng = lng1 + Math.atan2(by, Math.cos(lat1) + bx);
        return [lng / DEG_TO_RAD, lat / DEG_TO_RAD];
    };

    function addCircle(index,lon,lat,radius,color) {
        var rgb = color.replace('rgba(','').replace(')','').split(',');
        rgb = "rgb("+rgb[0]+","+rgb[1]+","+rgb[2]+")";
        var centerLongitudeLatitude = ol.proj.fromLonLat([lon, lat]);
        layerCircles[index] = new ol.layer.Vector({
            renderBuffer: 10,
            updateWhileAnimating: updateWhileAnimating,
            updateWhileInteracting: updateWhileInteracting,
            source: new ol.source.Vector({
                features: [new ol.Feature(new ol.geom.Circle(centerLongitudeLatitude, radius))]
            }),
            style: [
                new ol.style.Style({
                    stroke: new ol.style.Stroke({
                        color: rgb,
                        width: 1
                    }),
                    fill: new ol.style.Fill({
                        color: color
                    })
                })
            ]
        });
        layerCircles[index].setZIndex(12);
        map.addLayer(layerCircles[index]);
    }

    function draw_geofence() {
        jQuery.each(layerCircles, function(index, layer) {
            map.removeLayer(layer);
        });
        if(!globe_mode) {
            for(var i=0;i<features_filter.length;i++) {
                var geofence_radius = features_filter[i].get('geofence_radius');
                var geofence_color = features_filter[i].get('geofence_color');
                if(geofence_radius>0) {
                    var lat = parseFloat(features_filter[i].get('latitude'));
                    var lon = parseFloat(features_filter[i].get('longitude'));
                    addCircle(i,lon, lat, geofence_radius, geofence_color);
                }
            }
        }
    }

    function draw_geometries() {
        if(saved_geometries!='') {
            var features = new ol.format.GeoJSON().readFeatures(saved_geometries, { featureProjection: 'EPSG:3857' });
            features.forEach(function(feature){ feature.setId(undefined) });
            var source = new ol.source.Vector({
                features: features,
            });
            vector_geometries = new ol.layer.Vector({
                updateWhileAnimating: updateWhileAnimating,
                updateWhileInteracting: updateWhileInteracting,
                renderBuffer: renderBuffer,
                source: source,
                zIndex: 1,
                style: function (f) {
                    return new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: 5,
                            stroke: new ol.style.Stroke({ width: 1.5, color: f.get('color') || [255,0,0] }),
                            fill: new ol.style.Fill({ color: (f.get('color') || [255,0,0]).concat([.5]) })
                        }),
                        stroke: new ol.style.Stroke({ width: 2.5, color: f.get('color') || [255,0,0] }),
                        fill: new ol.style.Fill({ color: (f.get('color') || [255,0,0]).concat([.5]) })
                    })
                }
            });
            vector_geometries.setZIndex(8);
            map.addLayer(vector_geometries);
        }
    }

    function draw_lines() {
        jQuery.each(layerLines, function(index, layer) {
            map.removeLayer(layer);
        });
        jQuery.each(layerMidpoint, function(index, layer) {
            map.removeLayer(layer);
        });
        jQuery.each(markers_connections, function(index, markers_connection) {
            var id_source = markers_connection.id_source;
            var id_dest = markers_connection.id_dest;
            var id_source_exist = false;
            var id_dest_exist = false;
            jQuery.each(features_filter, function(index, feature_filter) {
                var id_db = feature_filter.values_.id_db;
                if(id_db==id_source) id_source_exist=true;
                if(id_db==id_dest) id_dest_exist=true;
            });
            if(id_source_exist && id_dest_exist) {
                var lat_s = parseFloat(markers_connection.lat_source);
                var lon_s = parseFloat(markers_connection.lon_source);
                var lat_d = parseFloat(markers_connection.lat_dest);
                var lon_d = parseFloat(markers_connection.lon_dest);
                var coordinates = [
                    ol.proj.fromLonLat([lon_s, lat_s]),
                    ol.proj.fromLonLat([lon_d, lat_d])
                ];
                var midpoint = midPoint(lat_s,lon_s,lat_d,lon_d);
                var midpoint_coordinates = ol.proj.fromLonLat([midpoint[0], midpoint[1]]);
                layerLines[index] = new ol.layer.Vector({
                    updateWhileAnimating: updateWhileAnimating,
                    updateWhileInteracting: updateWhileInteracting,
                    renderBuffer: renderBuffer,
                    zIndex: 3,
                    source: new ol.source.Vector({
                        features: [
                            new ol.Feature({
                                geometry: new ol.geom.LineString(coordinates),
                            })
                        ],
                    }),
                    style: new ol.style.Style({
                        geometry: function(feature) {
                            var projection = map.getView().getProjection();
                            var coordinates = feature.getGeometry().clone().transform(projection, 'EPSG:4326').getCoordinates();
                            var from = coordinates[0];
                            var to = coordinates[1];
                            var arcGenerator = new arc.GreatCircle({
                                x: from[0],
                                y: from[1]
                            }, {
                                x: to[0],
                                y: to[1]
                            });
                            var arcLine = arcGenerator.Arc(100, {
                                offset: 10
                            });
                            var coords = [];
                            arcLine.geometries.forEach(function(geom) {
                                coords.push(geom.coords);
                            });
                            var line = new ol.geom.MultiLineString(coords);
                            line.transform('EPSG:4326', projection);
                            return line;
                        },
                        stroke: new ol.style.Stroke({
                            color: markers_connection.color,
                            width: markers_connection.width
                        })
                    })
                });
                layerMidpoint[index] = new ol.layer.Vector({
                    updateWhileAnimating: updateWhileAnimating,
                    updateWhileInteracting: updateWhileInteracting,
                    renderBuffer: renderBuffer,
                    zIndex: 4,
                    source: new ol.source.Vector({
                        features: [
                            new ol.Feature({
                                geometry: new ol.geom.Point(midpoint_coordinates),
                                name: 'connection_midpoint',
                                id_source: markers_connection.id_source,
                                id_dest: markers_connection.id_dest,
                                title: markers_connection.title,
                                description: markers_connection.description
                            })
                        ],
                    }),
                    style: new ol.style.Style({
                        image: new ol.style.Circle({
                            anchor: [0.5, 0.5],
                            anchorXUnits: 'fraction',
                            anchorYUnits: 'fraction',
                            radius: 9,
                            stroke: new ol.style.Stroke({
                                color: '#ffffff',
                                opacity: 0.6,
                                width: 1,
                            }),
                            fill: new ol.style.Fill({
                                color: markers_connection.color,
                                opacity: 1,
                                weight: 1
                            })
                        })
                    })
                });
                layerLines[index].setZIndex(13);
                layerMidpoint[index].setZIndex(14);
                map.addLayer(layerLines[index]);
                if(markers_connection.title!='' || markers_connection.description!='') {
                    map.addLayer(layerMidpoint[index]);
                }
            }
        });
    }

    window.check_password_map = function () {
        var password = $('#map_password').val();
        if(password!='') {
            $.ajax({
                url: "ajax/check_password_map.php",
                type: "POST",
                data: {
                    id_map: window.id_map,
                    password: password
                },
                async: false,
                success: function (json) {
                    var rsp = JSON.parse(json);
                    if(rsp.status=='ok') {
                        $('#btn_check_password').removeClass("disabled");
                        $('#btn_check_password').css('pointer-events','none');
                        $('#btn_check_password').addClass('ok_lead');
                        setTimeout(function() {
                            $('.protect').fadeOut();
                            render_map();
                            if(window.lazy_loading>0) {
                                $('.progress-circle').hide();
                                $('.loading').hide();
                                $('#background_loading').hide();
                            } else if(window.loading_visible==1) {
                                $('.progress-circle').fadeIn();
                            } else {
                                $('.loading').hide();
                                $('.map_render').css('opacity',1);
                                map.getView().setCenter(ol.proj.fromLonLat([0, 0]));
                                map.getView().setZoom(1);
                                $('html').css('pointer-events','initial');
                                $('body').css('pointer-events','initial');
                            }
                        },500);
                    } else {
                        $('#btn_check_password').removeClass("disabled");
                        $('#btn_check_password').css('pointer-events','none');
                        $('#btn_check_password').addClass('error_lead');
                        setTimeout(function () {
                            $('#btn_check_password').removeClass('error_lead');
                            $('#btn_check_password').css('pointer-events','initial');
                        },250);
                        $('#map_password').val('');
                    }
                }
            });
        }
    }

    window.change_opacity_overlay = function() {
        var opacity = parseFloat($('.overlay_slider input').val());
        switch (current_map_style) {
            case 'default_style':
                if(globe_mode) {
                    if(street_overlay_layer_d!==null) {
                        street_overlay_layer_d.setOpacity(opacity);
                    }
                } else {
                    if(street_overlay_layer!==null) {
                        street_overlay_layer.setOpacity(opacity);
                    }
                }
                break;
            case 'satellite_style':
                if(globe_mode) {
                    if(satellite_overlay_layer_d!==null) {
                        satellite_overlay_layer_d.setOpacity(opacity);
                    }
                } else {
                    if(satellite_overlay_layer!==null) {
                        satellite_overlay_layer.setOpacity(opacity);
                    }
                }
                break;
        }
    }

    window.change_map_style = function (id) {
        current_map_style = id;
        var empty_layer = new ol.layer.Vector({
            source: new ol.source.Vector({})
        });
        switch(id) {
            case 'default_style':
                $('#satellite_style').show();
                $('#default_style').hide();
                if(globe_mode) {
                    map.getLayers().setAt(0, default_style_d);
                    if(street_overlay_layer_d!==null) {
                        map.getLayers().setAt(1, street_overlay_layer_d);
                        $('.overlay_slider input').val(parseFloat(street_overlay_layer_d.getOpacity()));
                        $('.overlay_slider').show();
                    } else {
                        map.getLayers().setAt(1, empty_layer);
                        $('.overlay_slider').hide();
                    }
                } else {
                    map.getLayers().setAt(0, default_style);
                    if(street_overlay_layer!==null) {
                        map.getLayers().setAt(1, street_overlay_layer);
                        $('.overlay_slider input').val(parseFloat(street_overlay_layer.getOpacity()));
                        $('.overlay_slider').show();
                    } else {
                        map.getLayers().setAt(1, empty_layer);
                        $('.overlay_slider').hide();
                    }
                }
                if(window.use_street_attributions==1) {
                    $('#map-attributions').removeClass('hidden');
                    $('.map-legal-footer').addClass('extra-padding');
                } else {
                    $('#map-attributions').addClass('hidden');
                    $('.map-legal-footer').removeClass('extra-padding');
                }
                map_view.setMaxZoom(window.street_maxzoom);
                map_view.setMinZoom(window.street_minzoom);
                break;
            case 'satellite_style':
                $('#satellite_style').hide();
                $('#default_style').show();
                if(globe_mode) {
                    map.getLayers().setAt(0, satellite_style_d);
                    if(satellite_overlay_layer_d!==null) {
                        map.getLayers().setAt(1, satellite_overlay_layer_d);
                        $('.overlay_slider input').val(parseFloat(satellite_overlay_layer_d.getOpacity()));
                        $('.overlay_slider').show();
                    } else {
                        map.getLayers().setAt(1, empty_layer);
                        $('.overlay_slider').hide();
                    }
                } else {
                    map.getLayers().setAt(0, satellite_style);
                    if(satellite_overlay_layer!==null) {
                        map.getLayers().setAt(1, satellite_overlay_layer);
                        $('.overlay_slider input').val(parseFloat(satellite_overlay_layer.getOpacity()));
                        $('.overlay_slider').show();
                    } else {
                        map.getLayers().setAt(1, empty_layer);
                        $('.overlay_slider').hide();
                    }
                }
                if(window.use_satellite_attributions==1) {
                    $('#map-attributions').removeClass('hidden');
                    $('.map-legal-footer').addClass('extra-padding');
                } else {
                    $('#map-attributions').addClass('hidden');
                    $('.map-legal-footer').removeClass('extra-padding');
                }
                map_view.setMaxZoom(window.satellite_maxzoom);
                map_view.setMinZoom(window.satellite_minzoom);
                break;
        }
        update_footer_visibility();
    }

    function parse_category_icons(id_categories) {
        var html_categories = '';
        if(id_categories!='' && window.enable_categories>0 && window.show_categories_marker>0) {
            var array_id_categories = id_categories.split(",");
            $.each(array_id_categories,function(index_category,id_category) {
                id_category = parseInt(id_category);
                var icon = mapping_categories_icon[id_category];
                var name = mapping_categories_name[id_category];
                switch (window.show_categories_marker) {
                    case 1:
                        if(icon!='') {
                            html_categories += '<div class="category_detail" style="display:inline-block">' + icon + '</div>';
                        }
                        break;
                    case 2:
                        if(icon!='') {
                            html_categories+='<div class="category_detail" style="display:inline-block">'+icon+' <span>'+name+'</span></div>';
                        } else {
                            html_categories+='<div class="category_detail" style="display:inline-block"><span>'+name+'</span></div>';
                        }
                        break;
                }
            });
        }
        return html_categories;
    }

    function parse_category_featured(array_id_categories) {
        var html_categories = '';
        if(array_id_categories.length>0 && (window.enable_categories==1 || window.enable_categories==3)) {
            $.each(array_id_categories,function(index_category,id_category) {
                id_category = parseInt(id_category);
                var icon = mapping_categories_icon[id_category];
                var name = mapping_categories_name[id_category];
                if(icon!='') {
                    html_categories+='<div onclick="click_cat_featured('+id_category+');" id="category_featured_'+id_category+'" class="category_detail category-chip" style="display:inline-block">'+icon+' <span>'+name+'</span></div>';
                } else {
                    html_categories+='<div onclick="click_cat_featured('+id_category+');" id="category_featured_'+id_category+'" class="category_detail category-chip" style="display:inline-block"><span>'+name+'</span></div>';
                }
            });
        }
        $('#featured_categories').html(html_categories);
    }

    window.click_cat_featured = function(id) {
        switch(window.category_featured_mode) {
            case 'filter':
                toggle_check_item(id,true,false);
                break;
            case 'toggle':
                jQuery.each(categories, function(index, category) {
                    toggle_check_item(category.id,false,-1);
                });
                toggle_check_item(id,true,false);
                break;
        }
    }

    window.initCategorySlider = function(wrapperId, contentId) {
        const wrapper = document.getElementById(wrapperId);
        const element = document.getElementById(contentId);
        if (!wrapper || !element) return;
        const arrowLeft = wrapper.querySelector('.arrow.left');
        const arrowRight = wrapper.querySelector('.arrow.right');
        const maskLeft = wrapper.querySelector('.slider-mask-left');
        const maskRight = wrapper.querySelector('.slider-mask-right');
        let isDragging = false;
        let startX;
        let scrollStart;
        let dragDistance = 0;
        const DRAG_THRESHOLD = 5;
        const scrollAmount = 150;
        function startDrag(e) {
            if (element.scrollWidth <= element.clientWidth) return;
            if (e.type === 'mousedown') e.preventDefault();
            isDragging = true;
            dragDistance = 0;
            element.classList.add('active');
            const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0);
            startX = pageX;
            scrollStart = element.scrollLeft;
            element.style.cursor = 'grabbing';
        }
        function onDrag(e) {
            if (!isDragging) return;
            const pageX = e.pageX || (e.touches ? e.touches[0].pageX : 0);
            const delta = pageX - startX;
            element.scrollLeft = scrollStart - delta;
            dragDistance = Math.abs(delta);
            if (dragDistance > DRAG_THRESHOLD && e.cancelable) {
                e.preventDefault();
            }
        }
        function stopDrag() {
            isDragging = false;
            element.classList.remove('active');
            element.style.cursor = ''; // Reset cursor
        }
        function updateUI() {
            const scrollLeftVal = Math.ceil(element.scrollLeft);
            const maxScrollLeft = Math.ceil(element.scrollWidth - element.clientWidth);
            const isAtStart = scrollLeftVal <= 0;
            const isAtEnd = scrollLeftVal >= maxScrollLeft - 1;
            if (isAtStart) {
                if (arrowLeft) arrowLeft.classList.remove('visible');
                if (maskLeft) maskLeft.style.opacity = '0';
            } else {
                if (arrowLeft) arrowLeft.classList.add('visible');
                if (maskLeft) maskLeft.style.opacity = '1';
            }
            if (isAtEnd) {
                if (arrowRight) arrowRight.classList.remove('visible');
                if (maskRight) maskRight.style.opacity = '0';
            } else {
                if (arrowRight) arrowRight.classList.add('visible');
                if (maskRight) maskRight.style.opacity = '1';
            }
            if (maxScrollLeft <= 0) {
                element.classList.add('no-scroll');
            } else {
                element.classList.remove('no-scroll');
            }
        }
        element.addEventListener('mousedown', startDrag);
        element.addEventListener('mouseleave', stopDrag);
        element.addEventListener('mouseup', stopDrag);
        element.addEventListener('mousemove', onDrag);
        element.addEventListener('touchstart', startDrag, {passive: false});
        element.addEventListener('touchend', stopDrag);
        element.addEventListener('touchmove', onDrag, {passive: false});
        element.addEventListener('click',
            function (e) {
                if (dragDistance > DRAG_THRESHOLD) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            }, true
        );
        if (arrowLeft) {
            arrowLeft.addEventListener('click', () => {
                element.scrollBy({ left: -scrollAmount, behavior: 'smooth' });
            });
        }
        if (arrowRight) {
            arrowRight.addEventListener('click', () => {
                element.scrollBy({ left: scrollAmount, behavior: 'smooth' });
            });
        }
        element.addEventListener('scroll', updateUI);
        window.addEventListener('resize', updateUI);
        setTimeout(updateUI, 50);
        return {
            reset: function() {
                element.scrollTo({ left: 0, behavior: 'instant' });
                updateUI();
            }
        };
    }

    function manageCategoryOverflow(element) {
        $('.'+element).each(function() {
            var $container = $(this);
            $container.find('.category_detail').css('opacity',1);
            $container.find('.category_icon').css('opacity',1);
            var $categories = $container.find('.category_detail').not('.category-overflow-badge');
            $categories.show();
            $container.find('.category-overflow-badge').remove();
            if ($categories.length === 0) return;
            var containerLeft = $container.offset().left;
            var containerWidth = $container.width();
            var containerRight = containerLeft + containerWidth;
            var $tempBadge = $('<div class="category_detail category-overflow-badge" style="display:inline-block">...+0</div>').appendTo($container);
            var badgeWidth = $tempBadge.outerWidth(true);
            $tempBadge.remove();
            var $lastCat = $categories.last();
            var lastCatRight = $lastCat.offset().left + $lastCat.outerWidth(true);
            if (lastCatRight <= containerRight) {
                return;
            }
            var lastVisibleIndex = 0;
            for (var i = $categories.length - 2; i >= 0; i--) {
                var $cat = $categories.eq(i);
                var catRight = $cat.offset().left + $cat.outerWidth(true);
                if (catRight + badgeWidth <= containerRight) {
                    lastVisibleIndex = i;
                    break;
                }
            }
            $categories.slice(lastVisibleIndex + 1).hide();
            var hiddenCount = $categories.length - (lastVisibleIndex + 1);
            if (hiddenCount > 0) {
                $container.append('<div class="category_detail category-overflow-badge" style="display:inline-block">...+' + hiddenCount + '</div>');
            }
        });
    }

    function parse_stars(stars) {
        var html = '';
        if(stars==0) {
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if((stars>0) && (stars<1)) {
            html += '<i aria-hidden="true" class="fas fa-star-half-alt"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if (stars==1) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if ((stars>1) && (stars<2)) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star-half-alt"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if (stars==2) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if ((stars>2) && (stars<3)) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star-half-alt"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if (stars==3) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if ((stars>3) && (stars<4)) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star-half-alt"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if (stars==4) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="far fa-star"></i>';
        } else if ((stars>4) && (stars<5)) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star-half-alt"></i>';
        } else if (stars==5) {
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
            html += '<i aria-hidden="true" class="fas fa-star"></i>';
        }
        return html;
    }

    function parse_review(review) {
        var html = '<div class="comment-part">\n' +
            '                    <div class="user-img-part">\n' +
            '                        <div class="user-text">\n' +
            '                            <p>'+review.name+'</p>\n' +
            '                            <h4>'+review.create_date+'</h4>\n' +
            '                        </div>\n' +
            '                        <div style="clear: both;"></div>\n' +
            '                    </div>\n' +
            '                    <div class="comment">\n' +
            parse_stars(review.rating) +
            '                        <p style="'+((review.reply!='') ? 'margin-bottom:4px;' : '')+'">'+review.comment+'</p>\n' +
            ((review.reply!='') ? '<p class="reply"><b>'+window.viewer_labels.owner+': </b>'+review.reply+'</p>\n' : '') +
            '                    </div>\n' +
            '                    <div style="clear: both;"></div>\n' +
            '                </div>';
        return html;
    }

    function get_reviews() {
        $('.btn_review').addClass('disabled');
        $('#div_comments').html('');
        $('.average-rating h2').html("-");
        $('.average-rating .total_reviews b').html('-');
        $('.average-rating .rating').html(parse_stars(0));
        $('#rating_bars_style').html(".progress:after{ width: 0%;} .progress-2:after{ width: 0%;} .progress-3:after{ width: 0%;} .progress-4:after{ width: 0%;} .progress-5:after{ width: 0%;}");
        $.ajax({
            url: "ajax/get_reviews.php",
            type: "POST",
            data: {
                id_marker: window.id_marker_sel,
                language: window.language
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                var reviews = rsp.reviews;
                var average_rating = rsp.average_rating;
                var array_perc = rsp.array_perc;
                var viewer_reviewed = rsp.viewer_reviewed===true;
                $('.average-rating h2').html(average_rating.toFixed(1));
                $('.average-rating .rating').html(parse_stars(average_rating));
                $('.average-rating .total_reviews b').html(reviews.length);
                $('#rating_bars_style').html(".progress-5:after{ width: "+array_perc[0]+"%;} .progress-4:after{ width: "+array_perc[1]+"%;} .progress-3:after{ width: "+array_perc[2]+"%;} .progress-2:after{ width: "+array_perc[3]+"%;} .progress:after{ width: "+array_perc[4]+"%;}");
                var html_reviews = '';
                var array_identifiers = [];
                jQuery.each(reviews, function(index, review) {
                    if(review.identifier!=null) {
                        array_identifiers.push(review.identifier);
                    }
                    html_reviews += parse_review(review);
                });
                $('#div_comments').html(html_reviews).promise().done(function () {
                    var identifier_review = localStorage.getItem('smlreview_'+window.id_map+'_'+window.id_marker_sel);
                    if(viewer_reviewed || array_identifiers.includes(identifier_review)) {
                        $('.btn_review').addClass('disabled');
                    } else {
                        $('.btn_review').removeClass('disabled');
                    }
                });
            }
        });
    }

    window.toggle_viewer_account = function () {
        close_language_menu();
        $('.viewer_account_panel').toggleClass('open');
    }

    $(document).on('click', function(event) {
        if(!$(event.target).closest('.viewer_account_btn, .viewer_account_panel').length) {
            $('.viewer_account_panel').removeClass('open');
        }
        if(!$(event.target).closest('.language_menu').length) {
            close_language_menu();
        }
    });

    window.open_viewer_login = function () {
        $('.viewer_account_panel').removeClass('open');
        viewer_hide_auth_feedback();
        $("#modal_viewer_register").hide();
        $("#modal_viewer_login").modal({escapeClose:false, clickClose:false});
    }

    window.open_viewer_register = function () {
        $('.viewer_account_panel').removeClass('open');
        viewer_hide_auth_feedback();
        $("#modal_viewer_login").hide();
        $("#modal_viewer_forgot").hide();
        $("#modal_viewer_register").modal({escapeClose:false, clickClose:false});
    }

    window.open_viewer_forgot = function () {
        $('.viewer_account_panel').removeClass('open');
        viewer_hide_auth_feedback();
        $("#modal_viewer_login").hide();
        $("#modal_viewer_register").hide();
        $("#modal_viewer_forgot").modal({escapeClose:false, clickClose:false});
    }

    function viewer_escape_html(value) {
        return $('<div>').text(value || '').html();
    }

    function viewer_show_auth_feedback(selector,message,type) {
        type = type || 'error';
        var icon = (type==='success') ? 'fas fa-check-circle' : 'fas fa-exclamation-circle';
        $(selector).removeClass('success error').addClass(type).html('<i class="'+icon+'"></i> '+viewer_escape_html(message)).addClass('show');
    }

    function viewer_hide_auth_feedback() {
        $('.viewer_auth_feedback').removeClass('show success error').html('');
    }

    function viewer_get_initials(username) {
        username = (username || '').trim();
        if(username==='') return '?';
        var parts = username.split(/\s+/);
        for(var i=0;i<parts.length;i++) {
            if(parts[i] !== '') return parts[i].charAt(0).toUpperCase();
        }
        return username.substring(0,1).toUpperCase();
    }

    function viewer_get_user_name() {
        return (window.viewer_user && window.viewer_user.username) ? window.viewer_user.username : '';
    }

    function viewer_get_user_email() {
        return (window.viewer_user && window.viewer_user.email) ? window.viewer_user.email : '';
    }

    function viewer_fill_author_fields(name_selector,email_selector) {
        if(!window.viewer_user) return;
        var name = viewer_get_user_name();
        var email = viewer_get_user_email();
        if(name!=='' && $(name_selector).length) $(name_selector).val(name);
        if(email!=='' && $(email_selector).length) $(email_selector).val(email);
    }

    function viewer_count_loaded_pending_markers() {
        var count = 0;
        if(typeof features === 'undefined') return count;
        for(var i=0;i<features.length;i++) {
            if(parseInt(features[i].get('can_edit_pending') || 0)===1) count++;
        }
        return count;
    }

    function viewer_account_markers_html() {
        if(!window.viewer_user) return '';
        if(parseInt(window.enable_add_marker || 0)===0) return '';
        var total = parseInt(window.viewer_user.markers_total || 0);
        var pending = parseInt(window.viewer_user.markers_pending || 0);
        var loaded_pending = viewer_count_loaded_pending_markers();
        var html = '<div class="viewer_account_markers">';
        html += '<div><i class="fas fa-map-marker-alt"></i><span>'+viewer_escape_html(window.viewer_labels.my_markers)+': '+total+'</span></div>';
        if(pending>0) {
            html += '<div><i class="fas fa-clock"></i><span>'+viewer_escape_html(window.viewer_labels.pending_validation)+': '+pending+'</span></div>';
        }
        if(pending>loaded_pending) {
            html += '<div class="viewer_account_notice">'+viewer_escape_html(window.viewer_labels.markers_not_loaded)+'</div>';
            html += '<button class="viewer_account_action viewer_account_reload" onclick="viewer_reload_map();"><i class="fas fa-rotate-right"></i><span>'+viewer_escape_html(window.viewer_labels.reload_map)+'</span></button>';
        }
        html += '</div>';
        return html;
    }

    window.viewer_reload_map = function () {
        location.reload();
    }

    function viewer_set_user(user) {
        window.viewer_user = user || false;
        $('.viewer_account_panel').removeClass('open');
        if(window.viewer_user) {
            $('.viewer_account_btn').removeClass('guest').addClass('logged');
            $('.viewer_account_btn').html('<span class="viewer_account_initials">'+viewer_escape_html(viewer_get_initials(window.viewer_user.username))+'</span><span class="viewer_account_badge"><i class="fas fa-user"></i></span>');
            $('.viewer_account_panel').html('<div class="viewer_account_name">'+viewer_escape_html(window.viewer_user.username)+'</div>'+viewer_account_markers_html()+'<button class="viewer_account_action" onclick="viewer_logout();"><i class="fas fa-sign-out-alt"></i><span>'+viewer_escape_html(window.viewer_labels.logout)+'</span></button>');
        } else {
            $('.viewer_account_btn').removeClass('logged').addClass('guest');
            $('.viewer_account_btn').html('<i class="fas fa-user"></i>');
            var html = '<button class="viewer_account_action" onclick="open_viewer_login();"><i class="fas fa-sign-in-alt"></i><span>'+viewer_escape_html(window.viewer_labels.login)+'</span></button>';
            if(window.viewer_auth_mode===2) {
                html += '<button class="viewer_account_action" onclick="open_viewer_register();"><i class="fas fa-user-plus"></i><span>'+viewer_escape_html(window.viewer_labels.register)+'</span></button>';
            }
            $('.viewer_account_panel').html(html);
            $('.btn_edit_own_marker').hide();
            $('.btn_delete_own_marker').hide();
        }
        fix_logo();
        viewer_refresh_visible_captchas();
    }

    function close_viewer_auth_modal() {
        try {
            $.modal.close();
        } catch(e) {
            $("#modal_viewer_login").hide();
            $("#modal_viewer_register").hide();
            $("#modal_viewer_forgot").hide();
        }
    }

    window.viewer_require_auth = function (feature) {
        if(window.viewer_auth_mode===0 || window.viewer_user) return true;
        var protected_feature = false;
        if(feature==='add_marker') protected_feature = window.add_marker_require_login===1;
        if(feature==='review') protected_feature = window.review_require_login===1;
        if(feature==='add_photo') protected_feature = window.add_photo_require_login===1;
        if(feature==='issue_report') protected_feature = window.issue_report_require_login===1;
        if(feature==='live_tracking') protected_feature = window.live_tracking_require_login===1;
        if(!protected_feature) return true;
        alertify.message(window.viewer_labels.auth_required_msg);
        open_viewer_login();
        return false;
    }

    function viewer_should_skip_captcha(feature) {
        return (window.viewer_auth_mode>0 && window.viewer_user);
    }

    function viewer_toggle_captcha(feature, captcha_object, input_selector) {
        if(viewer_should_skip_captcha(feature)) {
            $('.viewer_captcha_field[data-feature="'+feature+'"]').hide();
            $(input_selector).prop('required',false).val('');
        } else {
            $('.viewer_captcha_field[data-feature="'+feature+'"]').show();
            $(input_selector).prop('required',true).val('');
            if(captcha_object) captcha_object.refresh();
        }
    }

    function viewer_refresh_visible_captchas() {
        if($('.viewer_captcha_field[data-feature="review"]').length) {
            viewer_toggle_captcha('review',window.captcha,'#captcha_code');
        }
        if($('.viewer_captcha_field[data-feature="add_photo"]').length) {
            viewer_toggle_captcha('add_photo',window.photo_captcha,'#photo_captcha_code');
        }
        if($('.viewer_captcha_field[data-feature="issue_report"]').length) {
            viewer_toggle_captcha('issue_report',window.issue_captcha,'#issue_captcha_code');
        }
    }

    window.viewer_login = function () {
        var username = $('#viewer_login_username').val();
        var password = $('#viewer_login_password').val();
        var remember = ($('#viewer_login_remember').is(':checked')) ? 1 : 0;
        viewer_hide_auth_feedback();
        $('#viewer_login_submit').addClass('disabled');
        $.ajax({
            url: "ajax/login.php",
            type: "POST",
            data: {
                id_map: window.id_map,
                username: username,
                password: password,
                remember: remember
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                if(rsp.status==='ok') {
                    close_viewer_auth_modal();
                    viewer_set_user(rsp.user);
                    $('#viewer_login_submit').removeClass('disabled');
                } else if(rsp.status==='inactive') {
                    viewer_show_auth_feedback('#viewer_login_feedback',window.viewer_labels.account_inactive);
                    $('#viewer_login_submit').removeClass('disabled');
                } else {
                    viewer_show_auth_feedback('#viewer_login_feedback',window.viewer_labels.login_error);
                    $('#viewer_login_submit').removeClass('disabled');
                }
            },
            error: function() {
                viewer_show_auth_feedback('#viewer_login_feedback',window.viewer_labels.login_error);
                $('#viewer_login_submit').removeClass('disabled');
            }
        });
    }

    window.viewer_register = function () {
        var username = $('#viewer_register_username').val();
        var email = $('#viewer_register_email').val();
        var password = $('#viewer_register_password').val();
        var repeat_password = $('#viewer_register_repeat_password').val();
        viewer_hide_auth_feedback();
        if(password!==repeat_password) {
            viewer_show_auth_feedback('#viewer_register_feedback',window.viewer_labels.password_mismatch);
            return;
        }
        $('#viewer_register_submit').addClass('disabled');
        $.ajax({
            url: "ajax/register.php",
            type: "POST",
            data: {
                id_map: window.id_map,
                username: username,
                email: email,
                password: password,
                repeat_password: repeat_password
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                if(rsp.status==='ok') {
                    viewer_show_auth_feedback('#viewer_register_feedback',window.viewer_labels.register_success,'success');
                    setTimeout(function() {
                        close_viewer_auth_modal();
                        viewer_set_user(rsp.user);
                        $('#viewer_register_submit').removeClass('disabled');
                    },800);
                } else if(rsp.status==='activation_required') {
                    viewer_show_auth_feedback('#viewer_register_feedback',window.viewer_labels.register_activation,'success');
                    $('#viewer_register_submit').removeClass('disabled');
                } else {
                    viewer_show_auth_feedback('#viewer_register_feedback',rsp.msg || window.viewer_labels.register_error);
                    $('#viewer_register_submit').removeClass('disabled');
                }
            },
            error: function() {
                viewer_show_auth_feedback('#viewer_register_feedback',window.viewer_labels.register_error);
                $('#viewer_register_submit').removeClass('disabled');
            }
        });
    }

    window.viewer_send_verification_code = function() {
        var email = $('#viewer_forgot_email').val();
        viewer_hide_auth_feedback();
        if(email==='') {
            viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.invalid_email);
            return;
        }
        $('#viewer_forgot_code_submit').addClass('disabled');
        $.ajax({
            url: "ajax/send_email.php",
            type: "POST",
            data: {
                id_map: window.id_map,
                type: 'forgot',
                email: email,
                language: window.language
            },
            timeout: 15000,
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                if(rsp.status==='ok') {
                    viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.check_msg,'success');
                } else {
                    viewer_show_auth_feedback('#viewer_forgot_feedback',rsp.msg || window.viewer_labels.invalid_email);
                    $('#viewer_forgot_code_submit').removeClass('disabled');
                }
            },
            error: function() {
                viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.login_error);
                $('#viewer_forgot_code_submit').removeClass('disabled');
            }
        });
    }

    window.viewer_change_password_forgot = function() {
        var forgot_code = $('#viewer_forgot_code').val();
        var password = $('#viewer_forgot_password').val();
        var repeat_password = $('#viewer_forgot_repeat_password').val();
        viewer_hide_auth_feedback();
        if(forgot_code==='') {
            viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.invalid_code);
            return;
        }
        if(password==='' || repeat_password==='') {
            viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.password_mismatch);
            return;
        }
        if(password!==repeat_password) {
            viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.password_mismatch);
            return;
        }
        $('#viewer_forgot_submit').addClass('disabled');
        $.ajax({
            url: "ajax/change_password_forgot.php",
            type: "POST",
            data: {
                id_map: window.id_map,
                forgot_code: forgot_code,
                password: password
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                if(rsp.status==='ok') {
                    viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.password_success,'success');
                    setTimeout(function() {
                        close_viewer_auth_modal();
                        viewer_set_user(rsp.user);
                        $('#viewer_forgot_submit').removeClass('disabled');
                        if(window.history && window.history.replaceState) {
                            window.history.replaceState({}, document.title, window.url_map);
                        }
                    },800);
                } else {
                    viewer_show_auth_feedback('#viewer_forgot_feedback',rsp.msg || window.viewer_labels.invalid_code);
                    $('#viewer_forgot_submit').removeClass('disabled');
                }
            },
            error: function() {
                viewer_show_auth_feedback('#viewer_forgot_feedback',window.viewer_labels.login_error);
                $('#viewer_forgot_submit').removeClass('disabled');
            }
        });
    }

    $(document).ready(function() {
        if(parseInt(window.viewer_forgot || 0)===1) {
            open_viewer_forgot();
        }
    });

    window.viewer_logout = function () {
        $.ajax({
            url: "ajax/logout.php",
            type: "POST",
            data: {
                id_map: window.id_map
            },
            async: true,
            complete: function () {
                viewer_set_user(false);
            }
        });
    }

    window.open_modal_new_review = function () {
        if(!viewer_require_auth('review')) return;
        $('#form_new_review').show();
        $('#review_feedback').hide();
        set_rating(0);
        $('#review_name').val('');
        $('#review_email').val('');
        $('#review_comment').val('');
        viewer_fill_author_fields('#review_name','#review_email');
        viewer_toggle_captcha('review',window.captcha,'#captcha_code');
        $("#modal_new_review").modal({escapeClose:false, clickClose:false});
    }

    window.open_modal_add_photo = function () {
        if(!viewer_require_auth('add_photo')) return;
        $('#form_add_photo').show();
        $('#photo_feedback').hide();
        $('#photo_name').val('');
        $('#photo_email').val('');
        viewer_fill_author_fields('#photo_name','#photo_email');
        $('#photo_file').val('');
        $('#photo_dropzone').removeClass('has-file error-highlight');
        $('#photo_preview_image').attr('src', '');
        $('#photo_preview_container').hide();
        $('.dz-message').show();
        viewer_toggle_captcha('add_photo',window.photo_captcha,'#photo_captcha_code');
        $("#modal_add_photo").modal({escapeClose:false, clickClose:false});
    }

    window.add_photo = function (e) {
        e.preventDefault();
        var name = $('#photo_name').val();
        var email = $('#photo_email').val();
        var fileInput = document.getElementById('photo_file');
        var valid_captcha = viewer_should_skip_captcha('add_photo') || window.photo_captcha.valid($('input[id="photo_captcha_code"]').val());
        var copyright_checked = $('#photo_copyright').is(':checked');
        if(fileInput.files.length === 0) {
            $('#photo_dropzone').addClass('error-highlight');
        } else {
            $('#photo_dropzone').removeClass('error-highlight');
        }
        if(valid_captcha && fileInput.files.length > 0 && copyright_checked) {
            var $submitBtn = $('#photo_submit');
            var originalBtnText = $submitBtn.html();
            $submitBtn.addClass('disabled').html('<i class="fas fa-spin fa-circle-notch"></i>');
            $('.close-modal').hide();
            var formData = new FormData();
            formData.append('id_marker', window.id_marker_sel);
            formData.append('name', name);
            formData.append('email', email);
            formData.append('language', window.language);
            formData.append('photo', fileInput.files[0]);
            $.ajax({
                url: "ajax/add_photo.php",
                type: "POST",
                data: formData,
                processData: false,
                contentType: false,
                async: true,
                success: function (json) {
                    var rsp = JSON.parse(json);
                    if(rsp.status == 'ok') {
                        $('#form_add_photo').hide();
                        $('#photo_feedback').show();
                        var current_total = features[selected_feature].get('total_images') || 0;
                        var new_total = current_total + 1;
                        features[selected_feature].set('total_images', new_total);
                        if (window.marker_images_num !== -1 && window.marker_images_num > 0 && new_total >= window.marker_images_num) {
                            $('.btn_add_photo').hide();
                            $('.btn_add_photo_small').hide();
                        }
                    } else if(rsp.status == 'auth_required') {
                        alertify.message(window.viewer_labels.auth_required_msg);
                        open_viewer_login();
                    } else {
                        alert(rsp.message);
                    }
                },
                error: function() {
                    alert("An error occurred during the upload.");
                },
                complete: function() {
                    $submitBtn.removeClass('disabled').html(originalBtnText);
                    $('.close-modal').show();
                }
            });
        }
    }

    window.open_modal_report_issue = function () {
        if(!viewer_require_auth('issue_report')) return;
        $('#form_report_issue').show();
        $('#issue_feedback').hide();
        $('#issue_name').val('');
        $('#issue_email').val('');
        $('#issue_comment').val('');
        viewer_fill_author_fields('#issue_name','#issue_email');
        viewer_toggle_captcha('issue_report',window.issue_captcha,'#issue_captcha_code');
        $("#modal_report_issue").modal({escapeClose:false, clickClose:false});
    }

    window.add_review = function () {
        var name = $('#review_name').val();
        var email = $('#review_email').val();
        var comment = $('#review_comment').val();
        var valid_captcha = viewer_should_skip_captcha('review') || window.captcha.valid($('input[id="captcha_code"]').val());
        if(valid_captcha) {
            $('#review_submit').addClass('disabled');
            $.ajax({
                url: "ajax/add_review.php",
                type: "POST",
                data: {
                    id_marker: window.id_marker_sel,
                    rating: window.rating,
                    name: name,
                    email: email,
                    comment: comment
                },
                async: true,
                success: function (json) {
                    var rsp = JSON.parse(json);
                    if(rsp.status=='ok') {
                        var identifier = rsp.identifier;
                        localStorage.setItem('smlreview_'+window.id_map+'_'+window.id_marker_sel,identifier);
                        $('#form_new_review').hide();
                        $('#review_feedback').show();
                        get_reviews();
                    } else if(rsp.status=='auth_required') {
                        $('#review_submit').removeClass('disabled');
                        alertify.message(window.viewer_labels.auth_required_msg);
                        open_viewer_login();
                    } else if(rsp.status=='duplicate') {
                        $('#review_submit').addClass('disabled');
                        get_reviews();
                    } else {
                        $('#review_submit').removeClass('disabled');
                    }
                },
                error: function() {
                    $('#review_submit').removeClass('disabled');
                }
            });
        }
    }

    window.add_report_issue = function () {
        var name = $('#issue_name').val();
        var email = $('#issue_email').val();
        var comment = $('#issue_comment').val();
        var valid_captcha = viewer_should_skip_captcha('issue_report') || window.issue_captcha.valid($('input[id="issue_captcha_code"]').val());
        if(valid_captcha) {
            $('#issue_submit').addClass('disabled');
            $.ajax({
                url: "ajax/add_report_issue.php",
                type: "POST",
                data: {
                    id_marker: window.id_marker_sel,
                    name: name,
                    email: email,
                    comment: comment
                },
                async: true,
                success: function (json) {
                    var rsp = JSON.parse(json);
                    if(rsp.status=='ok') {
                        $('#form_report_issue').hide();
                        $('#issue_feedback').show();
                    } else if(rsp.status=='auth_required') {
                        $('#issue_submit').removeClass('disabled');
                        alertify.message(window.viewer_labels.auth_required_msg);
                        open_viewer_login();
                    } else {
                        $('#issue_submit').removeClass('disabled');
                    }
                }
            });
        }
    }

    window.rating = 0;
    window.set_rating = function (stars) {
        $('#review_submit').removeClass('disabled');
        $('#new_rating i').removeClass('fas').addClass('far');
        window.rating = stars;
        switch (stars) {
            case 0:
                $('#review_submit').addClass('disabled');
                break;
            case 1:
                $('#new_rating i:nth-child(2)').removeClass('far').addClass('fas');
                break;
            case 2:
                $('#new_rating i:nth-child(2)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(3)').removeClass('far').addClass('fas');
                break;
            case 3:
                $('#new_rating i:nth-child(2)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(3)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(4)').removeClass('far').addClass('fas');
                break;
            case 4:
                $('#new_rating i:nth-child(2)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(3)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(4)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(5)').removeClass('far').addClass('fas');
                break;
            case 5:
                $('#new_rating i:nth-child(2)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(3)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(4)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(5)').removeClass('far').addClass('fas');
                $('#new_rating i:nth-child(6)').removeClass('far').addClass('fas');
                break;
        }
    }

    window.next_marker = function () {
        if(new_marker_mode) return;
        if(!marker_animation) {
            close_list_detail();
            close_sheet_detail();
            close_categories();
            if(marker_index==-1) {
                marker_index=0;
                var coordinates = features[marker_index].getGeometry().getCoordinates();
                var size = map.getSize();
                var w = size[0]/2;
                var h = size[1]/2;
                map_view.setZoom(14);
                map_view.centerOn(coordinates, size, [w,h]);
                setTimeout(function () {
                    show_popup(features[marker_index],true);
                },100);
            } else {
                marker_animation = true;
                marker_index++;
                if(marker_index>=features_filter.length) {
                    marker_index=0;
                }
                var destination = features_filter[marker_index];
                flyTo(destination);
            }
        }
    }

    window.prev_marker = function () {
        if(new_marker_mode) return;
        if(!marker_animation) {
            close_list_detail();
            close_sheet_detail();
            close_categories();
            if (marker_index == -1) {
                marker_index = features_filter.length - 1;
                var coordinates = features[marker_index].getGeometry().getCoordinates();
                var size = map.getSize();
                var w = size[0]/2;
                var h = size[1]/2;
                map_view.setZoom(14);
                map_view.centerOn(coordinates, size, [w,h]);
                setTimeout(function () {
                    show_popup(features[marker_index],true);
                },100);
            } else {
                marker_animation = true;
                marker_index--;
                if (marker_index < 0) {
                    marker_index = features_filter.length - 1;
                }
                var destination = features_filter[marker_index];
                flyTo(destination);
            }
        }
    }

    function flyTo(location) {
        $('.popup').hide();
        const duration = 350;
        var zoom = 16;
        let view = map.getView();
        var extentOfPolygon = location.getGeometry().getExtent();
        let resolution = view.getResolutionForExtent(extentOfPolygon);
        var center = ol.extent.getCenter(extentOfPolygon);
        var currentCenter = map.getView().getCenter();
        var currentResolution = map.getView().getResolution();
        var distance = Math.sqrt(Math.pow(center[0] - currentCenter[0], 2) + Math.pow(center[1] - currentCenter[1], 2));
        var maxResolution = Math.max(distance/ map.getSize()[0], currentResolution);
        var up = Math.abs(maxResolution - currentResolution);
        var down = Math.abs(maxResolution - resolution);
        var scale_f = Math.sqrt(up + down);
        var adjustedDuration = duration + scale_f * 100;
        var zoom_t = 0;
        if(scale_f>0 && scale_f<=5) {
            zoom_t = 0;
        } else if(scale_f>5 && scale_f<=10) {
            zoom_t = 2;
        } else if(scale_f>10 && scale_f<=15) {
            zoom_t = 4;
        } else if(scale_f>15 && scale_f<=20) {
            zoom_t = 6;
        } else if(scale_f>20 && scale_f<=25) {
            zoom_t = 7;
        } else if(scale_f>25 && scale_f<=35) {
            zoom_t = 8;
        } else if(scale_f>35 && scale_f<=45) {
            zoom_t = 9;
        } else if(scale_f>45) {
            zoom_t = 10;
        }
        view.animate({
            center: center,
            duration: adjustedDuration
        });
        view.animate({
            zoom: zoom - zoom_t,
            resolution: maxResolution,
            duration: adjustedDuration * up / (up + down)
        }, {
            zoom: zoom,
            resolution: resolution,
            duration: adjustedDuration * down / (up + down)
        });
        setTimeout(function () {
            show_popup(location,true);
            marker_animation = false;
        },adjustedDuration + 100);
    }

    window.open_add_new_marker = function () {
        if(!viewer_require_auth('add_marker')) return;
        window.edit_own_marker_id = 0;
        set_new_marker_form_mode(false);
        new_marker_mode = true;
        $('.new_marker_btn').hide();
        $('#slider_categories_featured').css('opacity',0);
        $('#slider_categories_featured').css('pointer-events','none');
        $('.live_tracking_btn').hide();
        $('.live_tracking_stop_btn').hide();
        $('#live_tracking_count').hide();
        $('.sheet_detail').hide();
        $('.popup').hide();
        $('.popup_c').hide();
        if(window.search_radius_enabled) {
            close_radius_m();
        }
        if($('.list_detail').is(':visible')) {
            close_list_detail();
        }
        $('#slider_categories_featured').css({'opacity':0,'pointer-events':'none'});
        $('.featured_icon').addClass('disabled');
        $('.globe_icon').addClass('disabled');
        $('.search_div').addClass('disabled');
        $('.nav_marker_prev').addClass('disabled');
        $('.nav_marker_next').addClass('disabled');
        $('.btn_story').addClass('disabled');
        $('.connections_icon').addClass('disabled');
        hide_connections();
        try {
            clusters_layer.setOpacity(0.5);
        } catch (e) {}
        if (add_marker_boundaries_layer) add_marker_boundaries_layer.setVisible(true);
        dialog.confirm({
            title: window.viewer_labels.add_marker_title,
            message: window.viewer_labels.add_marker_location,
            cancel: window.viewer_labels.no,
            button: window.viewer_labels.yes,
            required: true,
            callback: function(value){
                if(value) {
                    getLocation_add_marker();
                } else {
                    $('.new_marker_msg').show();
                }
            }
        });
    }

    window.stop_live_tracking = function() {
        live_tracking_enabled = false;
        my_location_follow_enabled = false;
        syncWakeLock();
        enablePan();
        if (set_live_tracking_interval) {
            clearInterval(set_live_tracking_interval);
        }
        delete_live_tracking_position();
        initialize_get_live_tracking();
        $('.my_position_icon').removeClass('disabled');
        $('.live_tracking_btn').removeClass('hidden');
        $('.live_tracking_stop_btn').addClass('hidden');
        removeLabelFromPositionFeature();
    }

    window.open_live_tracking = function() {
        if(!viewer_require_auth('live_tracking')) return;
        dialog.prompt({
            title: window.viewer_labels.live_tracking_title,
            message: '<b>'+((window.live_tracking_only_admin==1) ? window.viewer_labels.live_tracking_admin_msg : window.viewer_labels.live_tracking_msg) + '</b><br><br><i>' + window.viewer_labels.live_tracking_policy+'</i>',
            input: {
                id: 'live_tracking_name',
                type: "text",
                placeholder: window.viewer_labels.name_placeholder,
                value: viewer_get_user_name() || (localStorage.getItem('live_tracking_name') ?? '')
            },
            validate: function(value){
                if($.trim(value) === "") {
                    return false;
                }
            },
            button: window.viewer_labels.start,
            required: false,
            callback: function(value){
                if(value) {
                    live_tracking_name = value;
                    localStorage.setItem('live_tracking_name',live_tracking_name);
                    live_tracking_enabled = true;
                    $('.live_tracking_btn').addClass('disabled');
                    $('.my_position_icon').addClass('disabled');
                    if (set_live_tracking_interval) {
                        clearInterval(set_live_tracking_interval);
                    }
                    if (get_live_tracking_interval) {
                        clearInterval(get_live_tracking_interval);
                    }
                    if(geolocation.getTracking()) {
                        const coordinates = geolocation.getPosition();
                        const accuracy = geolocation.getAccuracy();
                        if(coordinates && accuracy<=40) {
                            set_live_tracking_position(coordinates);
                        }
                    }
                    set_live_tracking_interval = setInterval(() => {
                        if(geolocation.getTracking()) {
                            const coordinates = geolocation.getPosition();
                            const accuracy = geolocation.getAccuracy();
                            if(coordinates && accuracy<=40) {
                                set_live_tracking_position(coordinates);
                            }
                        }
                    }, window.live_tracking_interval);
                    geolocate();
                }
            }
        });
    }

    window.initialize_get_live_tracking = function() {
        if (get_live_tracking_interval) {
            clearInterval(get_live_tracking_interval);
        }
        get_live_tracking_positions();
        get_live_tracking_interval = setInterval(() => {
            get_live_tracking_positions();
        }, window.live_tracking_interval);
    }

    function updateLiveTrackingMarkers(positions) {
        const currentIds = new Set();
        positions.forEach((pos) => {
            const { id, lat, lon, name, color } = pos;
            currentIds.add(id);
            addOrUpdateLiveTrackingMarker(id, lat, lon, name, color);
        });
        clearExpiredLiveTrackingMarkers(currentIds);
    }

    function addOrUpdateLiveTrackingMarker(id, lat, lon, name, color) {
        if (!liveTrackingMarkers[id]) {
            const feature = new ol.Feature({
                geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(lon), parseFloat(lat)])),
                name: 'live_tracking',
            });
            feature.setId(id);
            liveTrackingSource.addFeature(feature);
            liveTrackingMarkers[id] = feature;
        } else {
            const feature = liveTrackingMarkers[id];
            feature.getGeometry().setCoordinates(ol.proj.fromLonLat([parseFloat(lon), parseFloat(lat)]));
        }
        liveTrackingMarkers[id].setStyle(new ol.style.Style({
            image: new ol.style.Circle({
                radius: 9,
                fill: new ol.style.Fill({ color: color }),
                stroke: new ol.style.Stroke({
                    color: '#ffffff',
                    width: 3,
                }),
            }),
            text: new ol.style.Text({
                text: name,
                font: '12px Arial, sans-serif',
                fill: new ol.style.Fill({ color: color }),
                backgroundFill: new ol.style.Fill({ color: '#ffffff' }),
                padding: [2, 4, 2, 4],
                offsetY: -20,
                scale: 1,
            }),
        }));
    }

    function clearExpiredLiveTrackingMarkers(currentIds) {
        Object.keys(liveTrackingMarkers).forEach((id) => {
            if (!currentIds.has(id)) {
                removeLiveTrackingMarker(id);
            }
        });
    }

    function removeLiveTrackingMarker(id) {
        const feature = liveTrackingMarkers[id];
        if (feature) {
            liveTrackingSource.removeFeature(feature);
            delete liveTrackingMarkers[id];
        }
    }

    function getLocation_add_marker() {
        if(geolocation.getTracking()) {
            var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
            var my_lat = my_lat_lon[1];
            var my_lon = my_lat_lon[0];
            var position = {};
            position['coords'] = {};
            position.coords.latitude = my_lat;
            position.coords.longitude = my_lon;
            setPosition_add_marker(position);
        } else if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(setPosition_add_marker,errorCallback_add_marker);
        } else {
            $('.new_marker_msg').show();
        }
    }

    function errorCallback_add_marker(error) {
        $('.new_marker_msg').show();
    }

    function setPosition_add_marker(position) {
        var lat = position.coords.latitude;
        var lon =  position.coords.longitude;
        var coordinate = ol.proj.fromLonLat([lon, lat]);
        if (!isPointInAllowedBoundaries(coordinate)) {
            alertify.error(window.viewer_labels.out_of_bounds_current_loc);
            $('.new_marker_msg').show();
            return;
        }
        var target_zoom = Math.max(parseInt(map_view.getZoom() || 0),14);
        map_view.animate({
            center: coordinate,
            zoom: target_zoom,
            duration: 500
        });
        new_marker_clicked = true;
        new_marker_layer = new ol.layer.Vector({
            zIndex: 11,
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat]))
                    })
                ],
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    anchor: [0.5, 0.5],
                    anchorXUnits: 'fraction',
                    anchorYUnits: 'fraction',
                    radius: 14,
                    stroke: new ol.style.Stroke({
                        color: '#ffffff',
                        opacity: 0.6,
                        width: 1,
                    }),
                    fill: new ol.style.Fill({
                        color: window.main_color_hex,
                        opacity: 1,
                        weight: 1
                    })
                })
            })
        });
        new_marker_layer.setZIndex(21);
        map.addLayer(new_marker_layer);
        drag_interaction = new ol.interaction.Translate({layers: [new_marker_layer]});
        map.addInteraction(drag_interaction);
        $('.new_marker_msg').hide();
        $('.drag_marker_msg').show();
    }

    window.close_new_marker = function (force) {
        if(force) {
            new_marker_mode = false;
            new_marker_clicked = false;
            $('.search_div').removeClass('disabled');
            $('.nav_marker_prev').removeClass('disabled');
            $('.nav_marker_next').removeClass('disabled');
            $('.connections_icon').removeClass('disabled');
            $('.btn_story').removeClass('disabled');
            if(connections_visible) {
                toggle_connections();
            }
            try {
                clusters_layer.setOpacity(1);
            } catch (e) {}
            if (add_marker_boundaries_layer) add_marker_boundaries_layer.setVisible(false);
            $('.new_marker_msg').hide();
            $('.drag_marker_msg').hide();
            $('.new_sheet_detail').hide();
            $('.new_sheet_detail').removeClass('open');
            $('.search_div').removeClass('open');
            $('.new_marker_btn').show();
            $('.live_tracking_btn').show();
            $('.live_tracking_stop_btn').show();
            $('#live_tracking_count').show();
            try {
                map.removeInteraction(drag_interaction);
            } catch (e) {}
            map.removeLayer(new_marker_layer);
            reset_new_marker();
            if($('.featured_icon').hasClass('active_c')) {
                $('#featured_container').css('opacity',1);
                $('#featured_container .list_block_featured').css('pointer-events','initial');
            }
            $('#slider_categories_featured').css({'opacity':1,'pointer-events':'initial'});
            $('.featured_icon').removeClass('disabled');
            $('.globe_icon').removeClass('disabled');
        } else {
            var cancel_message = parseInt(window.edit_own_marker_id || 0)>0 ? window.viewer_labels.cancel_edit_marker : window.viewer_labels.cancel_new_marker;
            if (confirm(cancel_message) == true) {
                new_marker_mode = false;
                new_marker_clicked = false;
                $('.search_div').removeClass('disabled');
                $('.nav_marker_prev').removeClass('disabled');
                $('.nav_marker_next').removeClass('disabled');
                $('.btn_story').removeClass('disabled');
                $('.connections_icon').removeClass('disabled');
                if(connections_visible) {
                    toggle_connections();
                }
                try {
                    clusters_layer.setOpacity(1);
                } catch (e) {}
                if (add_marker_boundaries_layer) add_marker_boundaries_layer.setVisible(false);
                $('.new_marker_msg').hide();
                $('.drag_marker_msg').hide();
                $('.new_sheet_detail').hide();
                $('.new_sheet_detail').removeClass('open');
                $('.search_div').removeClass('open');
                $('.new_marker_btn').show();
                $('.live_tracking_btn').show();
                $('.live_tracking_stop_btn').show();
                $('#live_tracking_count').show();
                try {
                    map.removeInteraction(drag_interaction);
                } catch (e) {}
                map.removeLayer(new_marker_layer);
                reset_new_marker();
                if($('.featured_icon').hasClass('active_c')) {
                    $('#featured_container').css('opacity',1);
                    $('#featured_container .list_block_featured').css('pointer-events','initial');
                }
                $('#slider_categories_featured').css({'opacity':1,'pointer-events':'initial'});
                $('.featured_icon').removeClass('disabled');
                $('.globe_icon').removeClass('disabled');
            }
        }
        if(window.lazy_loading===2 && !new_marker_mode) {
            schedule_viewport_markers_load();
        }
    }

    function refresh_own_markers_after_change(id_marker) {
        id_marker = parseInt(id_marker || 0);
        if(id_marker>0) {
            window.marker_sel = id_marker;
            window.marker_current_id = id_marker;
            direct_marker_pending = true;
        } else {
            window.marker_sel = 0;
            window.marker_current_id = 0;
            selected_feature = null;
        }
        if(window.lazy_loading===2) {
            load_viewport_markers(false);
            return;
        }
        if(clusters_layer!==undefined) {
            map.removeLayer(clusters_layer);
            clusters_layer = undefined;
        }
        features = [];
        features_filter = [];
        marker_index = -1;
        selected_feature = null;
        get_markers(false);
    }

    function set_new_marker_form_mode(is_edit) {
        if(is_edit) {
            $('.btn_cancel_marker').html('<i class="fas fa-times"></i> '+viewer_escape_html(window.viewer_labels.cancel_edit));
            $('.btn_add_marker').html('<i class="fas fa-save"></i> '+viewer_escape_html(window.viewer_labels.save_marker));
        } else {
            $('.btn_cancel_marker').html('<i class="fas fa-times"></i> '+viewer_escape_html(window.viewer_labels.cancel_marker));
            $('.btn_add_marker').html('<i class="fas fa-plus"></i> '+viewer_escape_html(window.viewer_labels.submit_marker));
        }
    }

    window.open_edit_own_marker = function () {
        if(!window.viewer_user) {
            open_viewer_login();
            return;
        }
        $.ajax({
            url: "ajax/get_own_marker.php",
            type: "POST",
            data: {
                id_map: window.id_map,
                id_marker: window.id_marker_sel
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                if(rsp.status==="ok") {
                    open_edit_own_marker_form(rsp.marker);
                } else if(rsp.status==="auth_required") {
                    alertify.message(window.viewer_labels.auth_required_msg);
                    open_viewer_login();
                } else {
                    alert(window.viewer_labels.error_new_marker);
                }
            }
        });
    }

    function open_edit_own_marker_form(marker) {
        reset_new_marker();
        window.edit_own_marker_id = parseInt(marker.id);
        window.edit_own_marker_existing_images = parseInt(marker.total_images || 0);
        new_marker_mode = true;
        new_marker_clicked = true;
        set_new_marker_form_mode(true);
        $('.new_marker_btn').hide();
        $('#slider_categories_featured').css({'opacity':0,'pointer-events':'none'});
        $('.live_tracking_btn').hide();
        $('.live_tracking_stop_btn').hide();
        $('#live_tracking_count').hide();
        $('.sheet_detail').hide();
        $('.popup').hide();
        $('.popup_c').hide();
        if(window.search_radius_enabled) close_radius_m();
        if($('.list_detail').is(':visible')) close_list_detail();
        $('.featured_icon').addClass('disabled');
        $('.globe_icon').addClass('disabled');
        $('.search_div').addClass('disabled');
        $('.nav_marker_prev').addClass('disabled');
        $('.nav_marker_next').addClass('disabled');
        $('.btn_story').addClass('disabled');
        $('.connections_icon').addClass('disabled');
        hide_connections();
        try {
            clusters_layer.setOpacity(0.5);
        } catch (e) {}
        if (add_marker_boundaries_layer) add_marker_boundaries_layer.setVisible(true);
        $('#new_name').val(marker.name || '');
        $('#new_latitude').val(marker.lat || '');
        $('#new_longitude').val(marker.lon || '');
        $('#new_street').val(marker.street || '');
        $('#new_city').val(marker.city || '');
        $('#new_postal_code').val(marker.postal_code || '');
        $('#new_country').val(marker.country || '');
        $('#new_county').val(marker.county || '');
        $('#new_state').val(marker.state || '');
        $('#new_website').val(marker.website || '');
        $('#new_email').val(marker.email || '');
        var phone = marker.phone || '';
        var phone_prefix = $('#new_phone_prefix').val() || '';
        if(phone_prefix!=='' && phone.indexOf(phone_prefix)===0) phone = phone.substring(phone_prefix.length);
        $('#new_phone').val(phone);
        var whatsapp = marker.whatsapp || '';
        var whatsapp_prefix = $('#new_whatsapp_prefix').val() || '';
        if(whatsapp_prefix!=='' && whatsapp.indexOf(whatsapp_prefix)===0) whatsapp = whatsapp.substring(whatsapp_prefix.length);
        $('#new_whatsapp').val(whatsapp);
        $('#new_hours').val(marker.hours || '');
        $('#new_description').val(marker.description || '');
        for(var i=1;i<=20;i++) {
            $('#new_field_'+i).val(marker['extra_field_value_'+i] || '');
        }
        $('#new_category option:selected').prop('selected', false);
        if(marker.categories && marker.categories.length>0) {
            for(var c=0;c<marker.categories.length;c++) {
                $('#new_category option[id="'+marker.categories[c]+'"]').prop('selected', true);
            }
        }
        $('#new_category').trigger('change');
        try {
            map.removeLayer(new_marker_layer);
        } catch (e) {}
        new_marker_layer = new ol.layer.Vector({
            zIndex: 11,
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(marker.lon), parseFloat(marker.lat)]))
                    })
                ],
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    anchor: [0.5, 0.5],
                    anchorXUnits: 'fraction',
                    anchorYUnits: 'fraction',
                    radius: 14,
                    stroke: new ol.style.Stroke({
                        color: '#ffffff',
                        opacity: 0.6,
                        width: 1,
                    }),
                    fill: new ol.style.Fill({
                        color: window.main_color_hex,
                        opacity: 1,
                        weight: 1
                    })
                })
            })
        });
        new_marker_layer.setZIndex(21);
        map.addLayer(new_marker_layer);
        drag_interaction = new ol.interaction.Translate({layers: [new_marker_layer]});
        map.addInteraction(drag_interaction);
        drag_interaction.on('translateend', function () {
            new_marker_layer.getSource().forEachFeature(function(feature){
                var lat_lon = ol.proj.transform(feature.getGeometry().getCoordinates(), 'EPSG:3857', 'EPSG:4326');
                $('#new_latitude').val(lat_lon[1]);
                $('#new_longitude').val(lat_lon[0]);
            });
        });
        $('#new_latitude').off('input.edit_marker').on('input.edit_marker', function () {
            new_marker_layer.getSource().forEachFeature(function(feature){
                feature.getGeometry().setCoordinates(ol.proj.fromLonLat([$('#new_longitude').val(),$('#new_latitude').val()]));
            });
        });
        $('#new_longitude').off('input.edit_marker').on('input.edit_marker', function () {
            new_marker_layer.getSource().forEachFeature(function(feature){
                feature.getGeometry().setCoordinates(ol.proj.fromLonLat([$('#new_longitude').val(),$('#new_latitude').val()]));
            });
        });
        $('.new_marker_msg').hide();
        $('.drag_marker_msg').hide();
        $('.new_sheet_detail').show();
        $('.new_sheet_detail').addClass('open');
        $('.search_div').addClass('open');
        $('#new_name').focus();
    }

    window.delete_own_marker = function () {
        if(!window.viewer_user) {
            open_viewer_login();
            return;
        }
        if(confirm(window.viewer_labels.confirm_delete_marker) != true) return;
        $.ajax({
            url: "ajax/delete_own_marker.php",
            type: "POST",
            data: {
                id_map: window.id_map,
                id_marker: window.id_marker_sel
            },
            async: true,
            success: function (json) {
                var rsp = JSON.parse(json);
                if(rsp.status==="ok") {
                    alert(window.viewer_labels.ok_delete_marker);
                    if(window.viewer_user) {
                        window.viewer_user.markers_total = Math.max(0,parseInt(window.viewer_user.markers_total || 0)-1);
                        window.viewer_user.markers_pending = Math.max(0,parseInt(window.viewer_user.markers_pending || 0)-1);
                        viewer_set_user(window.viewer_user);
                    }
                    close_sheet_detail();
                    refresh_own_markers_after_change(0);
                } else if(rsp.status==="auth_required") {
                    alertify.message(window.viewer_labels.auth_required_msg);
                    open_viewer_login();
                } else {
                    alert(window.viewer_labels.error_new_marker);
                }
            }
        });
    }

    window.add_new_marker = function () {
        var name = $('#new_name').val();
        var latitude = $("#new_latitude").val();
        var longitude = $('#new_longitude').val();
        var complete = true;
        if(name=='') {
            complete = false;
            $('#new_name').addClass('error-highlight');
        } else {
            $('#new_name').removeClass('error-highlight');
        }
        if(latitude=='') {
            complete = false;
            $('#new_latitude').addClass('error-highlight');
        } else {
            $('#new_latitude').removeClass('error-highlight');
        }
        if(longitude=='') {
            complete = false;
            $('#new_longitude').addClass('error-highlight');
        } else {
            $('#new_longitude').removeClass('error-highlight');
        }
        $('.new_sheet_detail_container input[data-mandatory], .new_sheet_detail_container textarea[data-mandatory]').each(function() {
            if($(this).is(':visible')) {
                if($(this).attr('data-mandatory')=='1') {
                    const value = $(this).val().trim();
                    if (value === '') {
                        complete = false;
                        $(this).addClass('error-highlight');
                    } else {
                        $(this).removeClass('error-highlight');
                    }
                }
            }
        });
        var category = $('#new_category option:selected').map(function() {
            return this.id;
        }).get();
        if($('#new_category').is(':visible')) {
            if($('#new_category').attr('data-mandatory')=='1') {
                if(category.length==0) {
                    complete = false;
                    $('#new_category').addClass('error-highlight');
                } else {
                    $('#new_category').removeClass('error-highlight');
                }
            }
        }
        var array_images = [];
        if($('#uploaded_images').is(':visible')) {
            $('#uploaded_images img').each(function () {
                var image = $(this).attr('data-image');
                array_images.push(image);
            });
        }
        if($('.sheet_detail_feature_images').length) {
            if($('#uploaded_images').is(':visible')) {
                if($('#uploaded_images').attr('data-mandatory')=='1') {
                    if(array_images.length==0 && !(parseInt(window.edit_own_marker_id || 0)>0 && parseInt(window.edit_own_marker_existing_images || 0)>0)) {
                        complete = false;
                        $('#new_image_btn').addClass('error-highlight');
                    } else {
                        $('#new_image_btn').removeClass('error-highlight');
                    }
                }
            }
        }
        var street = $('#new_street').val();
        var city = $('#new_city').val();
        var postal_code = $('#new_postal_code').val();
        var country = $('#new_country').val();
        var county = $('#new_county').val();
        var state = $('#new_state').val();
        var website = $('#new_website').val();
        var email = $('#new_email').val();
        var phone = $('#new_phone').val();
        if(phone!='') {
            var phone_prefix = $('#new_phone_prefix').val();
            phone = phone_prefix+phone;
        }
        var whatsapp = $('#new_whatsapp').val();
        if(whatsapp!='') {
            var whatsapp_prefix = $('#new_whatsapp_prefix').val();
            whatsapp = whatsapp_prefix+whatsapp;
        }
        var hours = $('#new_hours').val();
        var description = $('#new_description').val();
        var field_1 = $('#new_field_1').val();
        var field_2 = $('#new_field_2').val();
        var field_3 = $('#new_field_3').val();
        var field_4 = $('#new_field_4').val();
        var field_5 = $('#new_field_5').val();
        var field_6 = $('#new_field_6').val();
        var field_7 = $('#new_field_7').val();
        var field_8 = $('#new_field_8').val();
        var field_9 = $('#new_field_9').val();
        var field_10 = $('#new_field_10').val();
        var field_11 = $('#new_field_11').val();
        var field_12 = $('#new_field_12').val();
        var field_13 = $('#new_field_13').val();
        var field_14 = $('#new_field_14').val();
        var field_15 = $('#new_field_15').val();
        var field_16 = $('#new_field_16').val();
        var field_17 = $('#new_field_17').val();
        var field_18 = $('#new_field_18').val();
        var field_19 = $('#new_field_19').val();
        var field_20 = $('#new_field_20').val();
        if(complete) {
            var edit_own_marker_id = parseInt(window.edit_own_marker_id || 0);
            var confirm_message = edit_own_marker_id>0 ? window.viewer_labels.confirm_edit_marker : window.viewer_labels.confirm_new_marker;
            if (confirm(confirm_message) == true) {
                $.ajax({
                    url: edit_own_marker_id>0 ? "ajax/save_own_marker.php" : "ajax/add_new_marker.php",
                    type: "POST",
                    data: {
                        id_marker: edit_own_marker_id,
                        id_map: window.id_map,
                        name: name,
                        street: street,
                        city: city,
                        postal_code: postal_code,
                        country: country,
                        county: county,
                        state: state,
                        website: website,
                        email: email,
                        phone: phone,
                        whatsapp: whatsapp,
                        h_desc: hours,
                        description: description,
                        lat: latitude,
                        lon: longitude,
                        array_images: array_images,
                        category: category,
                        field_1: field_1,
                        field_2: field_2,
                        field_3: field_3,
                        field_4: field_4,
                        field_5: field_5,
                        field_6: field_6,
                        field_7: field_7,
                        field_8: field_8,
                        field_9: field_9,
                        field_10: field_10,
                        field_11: field_11,
                        field_12: field_12,
                        field_13: field_13,
                        field_14: field_14,
                        field_15: field_15,
                        field_16: field_16,
                        field_17: field_17,
                        field_18: field_18,
                        field_19: field_19,
                        field_20: field_20
                    },
                    async: true,
                    success: function (json) {
                        var rsp = JSON.parse(json);
                        if (rsp.status == "ok") {
                            if(edit_own_marker_id===0 && window.viewer_user) {
                                window.viewer_user.markers_total = parseInt(window.viewer_user.markers_total || 0)+1;
                                window.viewer_user.markers_pending = parseInt(window.viewer_user.markers_pending || 0)+1;
                                viewer_set_user(window.viewer_user);
                            }
                            close_new_marker(true);
                            alert(edit_own_marker_id>0 ? window.viewer_labels.ok_update_marker : window.viewer_labels.ok_new_marker);
                            refresh_own_markers_after_change(rsp.id_marker || edit_own_marker_id);
                        } else if(rsp.status == "auth_required") {
                            alertify.message(window.viewer_labels.auth_required_msg);
                            open_viewer_login();
                        } else {
                            alert(window.viewer_labels.error_new_marker);
                        }
                    }
                });
            }
        }
    }

    window.reset_new_marker = function() {
        window.edit_own_marker_id = 0;
        window.edit_own_marker_existing_images = 0;
        set_new_marker_form_mode(false);
        $('#new_name').val('');
        $("#new_latitude").val('');
        $('#new_longitude').val('');
        $('#new_street').val('');
        $('#new_city').val('');
        $('#new_postal_code').val('');
        $('#new_country').val('');
        $('#new_county').val('');
        $('#new_state').val('');
        $('#new_website').val('');
        $('#new_email').val('');
        $('#new_phone').val('');
        $('#new_whatsapp').val('');
        $('#new_hours').val('');
        $('#new_description').val('');
        $('#uploaded_images').empty();
        $('#new_category option:selected').prop('selected', false);
        $('#new_category').trigger('change');
        $('.new_sheet_detail_image').css('background-image','url("images/placeholder.jpg")');
    }

    window.confirm_drag_new_marker = function () {
        var source = new_marker_layer.getSource();
        var is_valid = true;
        source.forEachFeature(function(feature){
            var coordinates = feature.getGeometry().getCoordinates();
            if (!isPointInAllowedBoundaries(coordinates)) {
                alertify.error(window.viewer_labels.out_of_bounds);
                is_valid = false;
                return;
            }
            var lat_lon = ol.proj.transform(coordinates, 'EPSG:3857', 'EPSG:4326');
            var lat = lat_lon[1];
            var lon = lat_lon[0];
            $('#new_latitude').val(lat);
            $('#new_longitude').val(lon);
            position_to_address(lat,lon);
        });
        if (!is_valid) return;
        map.removeInteraction(drag_interaction);
        $('#new_latitude').on('input', function () {
            source.forEachFeature(function(feature){
                var lat = $('#new_latitude').val();
                var lon = $('#new_longitude').val();
                feature.getGeometry().setCoordinates(ol.proj.fromLonLat([lon,lat]));
            });
        });
        $('#new_longitude').on('input', function () {
            source.forEachFeature(function(feature){
                var lat = $('#new_latitude').val();
                var lon = $('#new_longitude').val();
                feature.getGeometry().setCoordinates(ol.proj.fromLonLat([lon,lat]));
            });
        });
        $('.drag_marker_msg').hide();
        $('.new_sheet_detail').show();
        $('.new_sheet_detail').addClass('open');
        $('.search_div').addClass('open');
        $('#new_name').focus();
    }

    window.position_to_address = function (lat, lon) {
        const geocode_mode = window.geocoding_provider;
        function positionToAddress_queryNominatim(lat, lon) {
            return $.get(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json&addressdetails=1`);
        }
        function positionToAddress_queryGoogle(lat, lon) {
            return $.get(`ajax/google_position_to_address.php?lat=${lat}&lon=${lon}`);
        }
        function populateAddressFields(address) {
            try {
                $('#new_street').val(address.road || address.route);
            } catch (e) {}
            try {
                $('#new_city').val(address.city || address.locality);
            } catch (e) {}
            if ($('#new_city').val() === '') {
                try {
                    $('#new_city').val(address.town || address.village);
                } catch (e) {}
            }
            try {
                $('#new_postal_code').val(address.postcode || address.postal_code);
            } catch (e) {}
            try {
                $('#new_country').val(address.country || address.country_name);
            } catch (e) {}
            try {
                $('#new_county').val(address.county || address.administrative_area_level_2);
            } catch (e) {}
            try {
                $('#new_state').val(address.state || address.administrative_area_level_1);
            } catch (e) {}
        }
        if (geocode_mode === 'google') {
            positionToAddress_queryGoogle(lat, lon)
                .done((response) => {
                    if (response.status === 'OK' && response.results.length > 0) {
                        const addressComponents = response.results[0].address_components;
                        const address = {};
                        addressComponents.forEach((component) => {
                            component.types.forEach((type) => {
                                address[type] = component.long_name;
                            });
                        });
                        populateAddressFields(address);
                    } else {
                        console.error('No address found using Google API');
                    }
                })
                .fail(() => console.error('Failed to retrieve address from Google API'));
        } else if (geocode_mode === 'nominatim') {
            positionToAddress_queryNominatim(lat, lon)
                .done((data) => {
                    if (data && data.address) {
                        populateAddressFields(data.address);
                    } else {
                        console.error('No address found using Nominatim');
                    }
                })
                .fail(() => console.error('Failed to retrieve address from Nominatim'));
        }
    };

    window.inizialize_resize_sheet_icon = function () {
        if((window.innerHeight > window.innerWidth) && (window.innerWidth <= 600)){
            $('.resize_sheet_icon i').removeClass().addClass('fas fa-caret-down');
            $('.resize_sheet_icon').attr('onclick',"resize_sheet_detail('down')");
            $('.sheet_detail').removeClass('sheet_detail_maximized').addClass('sheet_detail_minimized');
            $('.resize_direction_icon i').removeClass().addClass('fas fa-caret-down');
            $('.resize_direction_icon').attr('onclick',"resize_direction_detail('down')");
            $('.direction_detail').removeClass('direction_detail_maximized').addClass('direction_detail_minimized');
        }
    }

    window.adjust_minimized_image_height = function() {
        var $sheet = $('.sheet_detail');
        if ($sheet.hasClass('sheet_detail_minimized')) {
            var $image = $('.sheet_detail_image').is(':visible') ? $('.sheet_detail_image') : ($('.sheet_detail_video').is(':visible') ? $('.sheet_detail_video') : null);
            if (!$image) return;
            $image.css('transition', 'none');
            $image.css('height', '150px');
            $image[0].offsetHeight;
            var $container = $('.sheet_detail_container');
            if ($container.length) {
                var containerTop = $container[0].getBoundingClientRect().top;
                var currentScroll = $container[0].scrollTop;
                var maxBottom = 0;
                var checkElement = function($el) {
                    if ($el.length && $el.is(':visible')) {
                        var bottom = ($el[0].getBoundingClientRect().bottom - containerTop) + currentScroll + ($el.outerHeight(true) - $el.outerHeight(false));
                        if (bottom > maxBottom) {
                            maxBottom = bottom;
                        }
                    }
                };
                checkElement($('#button_actions'));
                checkElement($('#box_warning_container'));
                checkElement($('#last_update_container'));
                if (maxBottom > 0) {
                    var targetLine = 270;
                    if (maxBottom > targetLine) {
                        var excess = maxBottom - targetLine;
                        var newImageHeight = 150 - excess;
                        if (newImageHeight < 40) newImageHeight = 40;
                        $image.css('height', newImageHeight + 'px');
                    }
                }
            }
            $image[0].offsetHeight;
            $image.css('transition', '');
        }
    };

    window.resize_sheet_detail = function (direction) {
        switch(direction) {
            case 'up':
                $('.resize_sheet_icon i').removeClass().addClass('fas fa-caret-down');
                $('.resize_sheet_icon').attr('onclick',"resize_sheet_detail('down')");
                $('.sheet_detail').removeClass('sheet_detail_maximized').addClass('sheet_detail_minimized');
                adjust_minimized_image_height();
                break;
            case 'down':
                $('.resize_sheet_icon i').removeClass().addClass('fas fa-caret-up');
                $('.resize_sheet_icon').attr('onclick',"resize_sheet_detail('up')");
                $('.sheet_detail').removeClass('sheet_detail_minimized').addClass('sheet_detail_maximized');
                $('.sheet_detail_image, .sheet_detail_video').css('height', '');
                break;
        }
    }

    window.resize_direction_detail = function (direction) {
        switch(direction) {
            case 'up':
                $('.resize_direction_icon i').removeClass().addClass('fas fa-caret-down');
                $('.resize_direction_icon').attr('onclick',"resize_direction_detail('down')");
                $('.direction_detail').removeClass('direction_detail_maximized').addClass('direction_detail_minimized');
                break;
            case 'down':
                $('.resize_direction_icon i').removeClass().addClass('fas fa-caret-up');
                $('.resize_direction_icon').attr('onclick',"resize_direction_detail('up')");
                $('.direction_detail').removeClass('direction_detail_minimized').addClass('direction_detail_maximized');
                break;
        }
    }

    window.delete_images = function() {
        $('#uploaded_images').empty();
        $('.new_sheet_detail_image').css('background-image','url("images/placeholder.jpg")');
        $('#btn_delete_images').css('pointer-events','none');
        $('#btn_delete_images').css('opacity',0.5);
        if(marker_images_num!=-1) {
            $('#new_image_btn').removeClass('disabled');
        }
        window.first_image_upload=false;
    }

    function hexToRgbA(hex,opacity){
        var c;
        if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){
            c= hex.substring(1).split('');
            if(c.length== 3){
                c= [c[0], c[0], c[1], c[1], c[2], c[2]];
            }
            c= '0x'+c.join('');
            return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+','+opacity+')';
        }
        return 'rgba(0,0,0,'+opacity+')';
    }

    function fix_logo() {
        if(window.innerWidth<=600 && window.enable_search) {
            if(window.logo_mobile!='') {
                var logo_height = $('.logo_mobile').height();
                $('.logo').hide();
                $('.logo_mobile').show();
            } else {
                var logo_height = $('.logo').height();
                $('.logo').show();
                $('.logo_mobile').hide();
            }
            $('.logo').css('top','48px');
            $('.logo_mobile').css('top','48px');
            $('.info_icon').css('top','48px');
            $('.language_menu').css('top','48px');
            $('.weather').css('top',(logo_height+48)+'px');
        } else {
            if(window.innerWidth<=600 && window.logo_mobile!='') {
                var logo_height = $('.logo_mobile').height();
                $('.logo').hide();
                $('.logo_mobile').show();
            } else {
                var logo_height = $('.logo').height();
                $('.logo').show();
                $('.logo_mobile').hide();
            }
            $('.logo').css('top','6px');
            $('.logo_mobile').css('top','6px');
            $('.info_icon').css('top','6px');
            $('.language_menu').css('top','6px');
            $('.weather').css('top',(logo_height+6)+'px');
        }
        if(window.innerWidth<=600 && window.logo_mobile!='') {
            var logo_width = $('.logo_mobile').width();
        } else {
            var logo_width = $('.logo').width();
        }
        var button_size = window.innerWidth <= 600 ? window.getComputedStyle(document.documentElement).getPropertyValue('--button_size_mobile') : window.getComputedStyle(document.documentElement).getPropertyValue('--button_size');
        button_size = parseInt(button_size.replace('px',''));
        var controls_top = (window.innerWidth<=600 && window.enable_search) ? 48 : 6;
        var reserved_right = 6;
        if(logo_width>0) {
            reserved_right = logo_width + 12;
        } else if($('.weather').is(':visible')) {
            reserved_right = 68;
        }
        var account_width = $('.viewer_account_btn').is(':visible') ? $('.viewer_account_btn').outerWidth() : 0;
        var info_width = $('.info_icon').is(':visible') ? $('.info_icon').outerWidth() : 0;
        var language_width = $('.language_menu').is(':visible') ? $('.language_menu').outerWidth() : 0;
        if(language_width==0 && $('.language_menu').is(':visible')) language_width = button_size;
        var group_width = reserved_right - 6;
        if(info_width>0) group_width += info_width + 6;
        if(language_width>0) group_width += language_width + 6;
        if(account_width>0) group_width += account_width + 6;
        var group_left = window.innerWidth - 6 - group_width;
        if($('.search_div').is(':visible')) {
            var search_right = $('.search_div').offset().left + $('.search_div').outerWidth();
            if(group_left < search_right + 6) {
                controls_top = (parseInt($('.search_div').css('top')) || 6) + $('.search_div').outerHeight() + 6;
            }
        }
        var current_right = reserved_right;
        if($('.info_icon').is(':visible')) {
            $('.info_icon').css({'top':controls_top+'px','right':current_right+'px'});
            current_right += $('.info_icon').outerWidth() + 6;
        }
        if($('.language_menu').is(':visible')) {
            $('.language_menu').css({'top':controls_top+'px','right':current_right+'px'});
            current_right += ($('.language_menu').outerWidth() || button_size) + 6;
        }
        if($('.viewer_account_btn').is(':visible')) {
            $('.viewer_account_btn').css({'top':controls_top+'px','right':current_right+'px','left':'auto'});
            $('.viewer_account_panel').css({'top':(controls_top+button_size+6)+'px','right':current_right+'px','left':'auto'});
            current_right += $('.viewer_account_btn').outerWidth() + 6;
        }
        if($('#slider_categories_featured').length) {
            var category_top = parseInt($('.btn_bar').css('top')) || 44;
            var category_height = $('#slider_categories_featured').outerHeight() || 30;
            var category_left = $('#slider_categories_featured').offset() ? $('#slider_categories_featured').offset().left : 6;
            var controls_bottom = controls_top + button_size;
            var category_overlaps_controls = category_top < controls_bottom + 6 && (category_top + category_height) > controls_top - 6;
            if(category_overlaps_controls) {
                var max_category_width = Math.max(120,window.innerWidth - category_left - current_right - 12);
                $('#slider_categories_featured').css('max-width',max_category_width+'px');
            } else if(window.innerWidth<=600) {
                $('#slider_categories_featured').css('max-width','calc(100vw - 12px)');
            } else {
                $('#slider_categories_featured').css('max-width','400px');
            }
        }
    }

    function resize_elements_ui() {
        if(window.innerWidth <= 600) {
            var button_size = window.getComputedStyle(document.documentElement).getPropertyValue('--button_size_mobile');
        } else {
            var button_size = window.getComputedStyle(document.documentElement).getPropertyValue('--button_size');
        }
        button_size = parseInt(button_size.replace('px',''));
        var pos1 = button_size+12;
        var pos2 = (button_size*2)+18;
        var pos3 = (button_size*3)+24;
        var pos4 = (button_size*4)+30;
        if(!$('.ol-full-screen').is(':visible')) {
            $('.ol-zoom .ol-zoom-out').css('right','6px');
            $('.ol-zoom .ol-zoom-in').css('right',pos1+'px');
            if($('.my_position_icon').is(':visible')) {
                $('.my_position_icon').css('right',pos2+'px');
                $('.home_icon').css('right',pos3+'px');
            } else {
                $('.home_icon').css('right',pos2+'px');
            }
        } else {
            $('.ol-zoom .ol-zoom-out').css('right',pos1+'px');
            $('.ol-zoom .ol-zoom-in').css('right',pos2+'px');
            if($('.my_position_icon').is(':visible')) {
                $('.my_position_icon').css('right',pos3+'px');
                $('.home_icon').css('right',pos4+'px');
            } else {
                $('.home_icon').css('right',pos3+'px');
            }
        }
        var current_left = $('.switch_style').is(':visible') ? pos1 : 6;
        if (window.enable_measure) {
            $('.measure-controls').removeClass('hidden').css('left', current_left + 'px');
            current_left += button_size + 6;
        } else {
            $('.measure-controls').addClass('hidden');
        }
        if(window.globe==0) {
            $('.globe_icon').addClass('hidden');
        } else {
            $('.globe_icon').removeClass('hidden').css('left', current_left+'px');
            current_left += button_size + 6;
        }
        if(markers_connections.length>0) {
            $('.connections_icon').removeClass('hidden').css('left', current_left+'px');
            current_left += button_size + 6;
        } else {
            $('.connections_icon').addClass('hidden');
        }
        $('.featured_icon').css('left', current_left+'px');
        var current_footer_h = $('.map-legal-footer').outerHeight() || 18;
        $('#featured_container').css('bottom', (button_size + current_footer_h + 16) + 'px');
    }

    $(window).resize(function () {
        fix_logo();
        manageCategoryOverflow('list_rating');
        try {
            clusterize_list.refresh(true);
        } catch (e) {}
        var scale = window.innerHeight / 1100;
        scale = Math.min(0.6, Math.max(0.3, scale))
        document.documentElement.style.setProperty("--scale_overlay_input", scale);
    });

    function pin_active_marker(lat,lon) {
        if(parseInt(pin_marker['pin_marker_enable'])==1) {
            map.removeLayer(pin_marker_layer);
            var feature = new ol.Feature({
                geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat]))
            });
            var main_color_rgb = hexToRgbA(pin_marker['pin_marker_color_hex'],1);
            var icon_color_rgb = hexToRgbA(pin_marker['pin_marker_icon_color_hex'],1);
            var icon_image = pin_marker['pin_marker_icon_image'];
            var icon_base64 = pin_marker['pin_marker_icon_base64'];
            var marker_size = parseFloat(pin_marker['pin_marker_size']);
            if(icon_base64!='') {
                var scale = marker_size;
            } else {
                var scale = marker_size/10;
            }
            var radius = 140*scale;
            var font_size = 120*scale;
            switch(pin_marker['pin_marker_align']) {
                case 'bottom':
                    var anchor_v = 1;
                    var anchor_gif = 300;
                    break;
                case 'middle':
                    var anchor_v = 0.5;
                    var anchor_gif = 150;
                    break;
                case 'top':
                    var anchor_v = 0;
                    var anchor_gif = 0;
                    break;
            }
            if(icon_image=='') {
                if(pin_marker['pin_marker_color_hex']=='') {
                    font_size = 160*scale;
                    style = new ol.style.Style({
                        text: new ol.style.Text({
                            text: String.fromCharCode("0x" + pin_marker['pin_marker_icon']),
                            textAlign: "center",
                            textBaseline: pin_marker['pin_marker_align'],
                            font: '900 '+font_size+'px "Font Awesome 7 Free"',
                            fill: new ol.style.Fill({
                                color: icon_color_rgb
                            })
                        })
                    });
                } else {
                    style = new ol.style.Style({
                        image: new ol.style.Circle({
                            radius: radius,
                            fill: new ol.style.Fill({
                                color: main_color_rgb,
                                weight: 1
                            })
                        }),
                        text: new ol.style.Text({
                            text: String.fromCharCode("0x" + pin_marker['pin_marker_icon']),
                            textAlign: "center",
                            textBaseline: pin_marker['pin_marker_align'],
                            font: '900 '+font_size+'px "Font Awesome 7 Free"',
                            fill: new ol.style.Fill({
                                color: icon_color_rgb
                            })
                        })
                    });
                }
            } else {
                if(icon_image.includes('.gif')) {
                    const gifUrl = 'icons/'+icon_image;
                    const gif = gifler(gifUrl);
                    var style = '';
                    gif.frames(
                        document.createElement('canvas'),
                        function (ctx, frame) {
                            if (!feature.getStyle()) {
                                feature.setStyle(
                                    new ol.style.Style({
                                        image: new ol.style.Icon({
                                            anchor: [0.5, anchor_gif],
                                            anchorXUnits: 'fraction',
                                            anchorYUnits: 'pixels',
                                            scale: scale,
                                            img: ctx.canvas,
                                            imgSize: [frame.width, frame.height]
                                        }),
                                    })
                                );
                            }
                            ctx.clearRect(0, 0, frame.width, frame.height);
                            ctx.drawImage(frame.buffer, frame.x, frame.y);
                            map.render();
                        }, true);
                } else {
                    if(icon_base64!='') {
                        var style = new ol.style.Style({
                            image: new ol.style.Icon({
                                anchor: [0.5, anchor_v],
                                anchorXUnits: 'fraction',
                                anchorYUnits: 'fraction',
                                scale: 1,
                                src: icon_base64,
                            })
                        });
                    } else {
                        var style = new ol.style.Style({
                            image: new ol.style.Icon({
                                anchor: [0.5, anchor_v],
                                anchorXUnits: 'fraction',
                                anchorYUnits: 'fraction',
                                scale: scale,
                                src: 'icons/'+icon_image,
                            })
                        });
                    }
                }
            }
            pin_marker_layer = new ol.layer.Vector({
                zIndex: 20,
                source: new ol.source.Vector({
                    features: [feature],
                }),
                style: style
            });
            pin_marker_layer.setZIndex(30);
            map.addLayer(pin_marker_layer);
        }
    }

    window.close_intro = function() {
        init_audio_player();
        $('.intro').fadeOut(250,function() {
            $('.intro').remove();
            switch(info_auto_open) {
                case 1:
                    $('.info_icon').trigger('click');
                    break;
                case 2:
                    if(window.innerWidth > 600) {
                        $('.info_icon').trigger('click');
                    }
                    break;
                case 3:
                    if(window.innerWidth <= 600) {
                        $('.info_icon').trigger('click');
                    }
                    break;
            }
        });
    }

    function fadeVolume(audioElement, targetVolume, duration) {
        targetVolume = Math.max(0, Math.min(1, targetVolume));
        let currentVolume = audioElement.volume;
        let steps = Math.abs(targetVolume - currentVolume) / (duration / 50);
        let isFadingIn = targetVolume > currentVolume;
        let fadeInterval = setInterval(function() {
            if (isFadingIn) {
                currentVolume = Math.min(targetVolume, currentVolume + steps);
            } else {
                currentVolume = Math.max(targetVolume, currentVolume - steps);
            }
            audioElement.volume = currentVolume;
            if ((isFadingIn && currentVolume >= targetVolume) || (!isFadingIn && currentVolume <= targetVolume)) {
                audioElement.volume = targetVolume;
                clearInterval(fadeInterval);
            }
        }, 50);
    }

    document.addEventListener("visibilitychange", () => {
        if (document.hidden) {
            if($('#story_container').hasClass('story_open')) {
                show_story();
            }
            if(selected_feature!==null) {
                var song_play_bg = features[selected_feature].get('song_play_bg');
            } else {
                var song_play_bg = 0;
            }
            audio_player.muted = true;
            if(!song_play_bg) {
                audio_player_marker.muted = true;
            }
        } else {
            if($('.btn_song_map').hasClass('open')) {
                if(selected_feature!==null) {
                    var song = features[selected_feature].get('song');
                } else {
                    var song = null;
                }
                if(song!='' && song!=null) {
                    audio_player_marker.muted = false;
                    audio_player.muted = false;
                } else {
                    audio_player.muted = false;
                }
            }
        }
    });

    function onAppBackground() {
        var storyContainer = document.getElementById('story_container');
        if (storyContainer) {
            storyContainer.style.display = 'none';
            void storyContainer.offsetWidth;
        }
    }

    function get_tripadvisor_info(id) {
        $('#tripadvisor_container').empty();
        var id_marker = features[id].get('id_db');
        var tripadvisor_location_id = features[id].get('tripadvisor_location_id');
        if(tripadvisor_location_id=='') {
            $('.tripadvisor-section').hide();
        } else {
            $('.tripadvisor-section').show();
            $('#tripadvisor_container').html('<i class="fas fa-spin fa-circle-notch"></i>');
            $.ajax({
                url: "ajax/tripadvisor_info.php",
                type: "POST",
                data: {
                    id_marker: id_marker,
                    location_id: tripadvisor_location_id,
                    language: window.map_language
                },
                async: true,
                success: function (data) {
                    if (data.error) {
                        $('.tripadvisor-section').hide();
                        return;
                    }
                    renderTripAdvisorBadge(parseFloat(data.rating),parseInt(data.num_reviews),data.web_url);
                },
                error: function() {
                    $('.tripadvisor-section').hide();
                },
            });
        }
    }

    function renderTripAdvisorBadge(rating, reviewCount, link) {
        const container = document.getElementById('tripadvisor_container');
        container.className = 'tripadvisor-badge';
        container.innerHTML = '';
        const logo = document.createElement('img');
        logo.src = 'images/tripadvisor-logo.svg';
        logo.className = 'tripadvisor-logo';
        container.appendChild(logo);
        const rounded = Math.round(rating * 2) / 2;
        const full = Math.floor(rounded);
        const hasHalf = (rounded - full) === 0.5;
        for (let i = 0; i < 5; i++) {
            const bubble = document.createElement('div');
            bubble.classList.add('tripadvisor-bubble');
            if (i < full) {
                bubble.classList.add('full');
            } else if (i === full && hasHalf) {
                bubble.classList.add('half');
            }
            container.appendChild(bubble);
        }
        const a = document.createElement('a');
        a.className = 'tripadvisor-link';
        a.target = '_blank';
        a.href = link;
        a.textContent = `${reviewCount.toLocaleString()} `+window.viewer_labels.reviews;
        container.appendChild(a);
    }

    function initializeMeasureTool(map) {
        const source_measure = new ol.source.Vector();
        const vectorLayer_measure = new ol.layer.Vector({
            source: source_measure,
            style: function(feature) {
                const geometry = feature.getGeometry();
                const styles = [
                    new ol.style.Style({
                        stroke: new ol.style.Stroke({ color: 'rgba(0, 153, 255, 0.8)', width: 4 }),
                    }),
                ];
                if (geometry.getType() === 'LineString') {
                    const coordinates = geometry.getCoordinates();
                    styles.push(new ol.style.Style({
                        geometry: new ol.geom.Point(coordinates[0]),
                        image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({color: 'rgba(0, 153, 255, 0.8)'}) }),
                    }));
                    styles.push(new ol.style.Style({
                        geometry: new ol.geom.Point(coordinates[coordinates.length - 1]),
                        image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({color: 'rgba(0, 153, 255, 0.8)'}) }),
                    }));
                }
                return styles;
            },
        });
        const highlightSource_measure = new ol.source.Vector();
        const highlightLayer_measure = new ol.layer.Vector({
            source: highlightSource_measure,
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 10,
                    stroke: new ol.style.Stroke({ color: 'rgba(0, 153, 255, 0.8)', width: 4 }),
                    fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.3)' }),
                }),
            }),
            zIndex: 10,
        });
        vectorLayer_measure.setZIndex(40);
        highlightLayer_measure.setZIndex(40);
        map.addLayer(vectorLayer_measure);
        map.addLayer(highlightLayer_measure);
        const tooltipElement_measure = document.getElementById('tooltip-distance');
        const tooltipOverlay_measure = new ol.Overlay({
            element: tooltipElement_measure,
            offset: [0, -15],
            positioning: 'bottom-center',
        });
        map.addOverlay(tooltipOverlay_measure);
        const helpTooltipElement_measure = document.getElementById('help-tooltip-measure');
        const helpTooltipOverlay_measure = new ol.Overlay({
            element: helpTooltipElement_measure,
            offset: [15, 0],
            positioning: 'center-left',
        });
        map.addOverlay(helpTooltipOverlay_measure);
        const pointerMoveHandler = function (evt) {
            if (evt.dragging) return;
            helpTooltipElement_measure.innerHTML = window.viewer_labels.click_drawing;
            helpTooltipOverlay_measure.setPosition(evt.coordinate);
            helpTooltipElement_measure.style.display = 'block';
        };
        let isMeasuring = false;
        let measurementOverlay;
        let sketchChangeListener, modifyChangeListener;
        const formatLength = function (line) {
            const lengthInMeters = ol.sphere.getLength(line);
            let output;
            if (window.unit_map === 'km') {
                if (lengthInMeters > 1000) {
                    output = Math.round((lengthInMeters / 1000) * 100) / 100 + ' km';
                } else {
                    output = Math.round(lengthInMeters * 100) / 100 + ' m';
                }
            } else {
                const lengthInFeet = lengthInMeters * 3.28084;
                if (lengthInFeet > 5280) {
                    output = (Math.round((lengthInFeet / 5280) * 100) / 100) + ' mi';
                } else {
                    output = (Math.round(lengthInFeet * 100) / 100) + ' ft';
                }
            }
            return output;
        };
        const modify = new ol.interaction.Modify({
            source: source_measure,
            style: new ol.style.Style({}),
            insertVertexCondition: ol.events.condition.never,
        });
        map.addInteraction(modify);
        const draw = new ol.interaction.Draw({
            source: source_measure,
            type: 'LineString',
            maxPoints: 2,
            style: new ol.style.Style({
                stroke: new ol.style.Stroke({ color: 'rgba(0, 153, 255, 0.8)', width: 4 }),
            }),
        });
        draw.setActive(false);
        map.addInteraction(draw);
        draw.on('drawstart', function (evt) {
            clearMeasurement();
            map.un('pointermove', pointerMoveHandler);
            if (helpTooltipElement_measure) helpTooltipElement_measure.style.display = 'none';
            const sketch = evt.feature;
            sketchChangeListener = sketch.getGeometry().on('change', function (geomEvt) {
                const geom = geomEvt.target;
                const output = formatLength(geom);
                tooltipElement_measure.innerHTML = output;
                tooltipOverlay_measure.setPosition(geom.getLastCoordinate());
                tooltipElement_measure.style.display = 'block';
            });
        });
        draw.on('drawend', function (evt) {
            tooltipElement_measure.style.display = 'none';
            if (sketchChangeListener) ol.Observable.unByKey(sketchChangeListener);
            const geometry = evt.feature.getGeometry();
            const newTooltipElement = document.createElement('div');
            newTooltipElement.className = 'tooltip-m tooltip-measure';
            newTooltipElement.innerHTML = formatLength(geometry);
            measurementOverlay = new ol.Overlay({
                element: newTooltipElement,
                positioning: 'bottom-center',
                offset: [0, -15],
            });
            map.addOverlay(measurementOverlay);
            measurementOverlay.setPosition(geometry.getCoordinateAt(0.5));
            document.getElementById('measure-btn').classList.add('hidden');
            document.getElementById('clear-btn').classList.remove('hidden');
            document.getElementById('measure-btn').click();
        });
        modify.on('modifystart', function(evt) {
            highlightSource_measure.clear();
            map.getTargetElement().style.cursor = '';
            const modifiedFeature = evt.features.getArray()[0];
            if (modifiedFeature) {
                modifyChangeListener = modifiedFeature.getGeometry().on('change', function(geomEvt) {
                    const geom = geomEvt.target;
                    if (measurementOverlay) {
                        const midpoint = geom.getCoordinateAt(0.5);
                        measurementOverlay.getElement().innerHTML = formatLength(geom);
                        measurementOverlay.setPosition(midpoint);
                    }
                });
            }
        });
        modify.on('modifyend', function(evt) {
            if (modifyChangeListener) ol.Observable.unByKey(modifyChangeListener);
        });
        map.on('pointermove', function (evt) {
            if (evt.dragging || isMeasuring) return;
            const pixel = map.getEventPixel(evt.originalEvent);
            let featureFound = false;
            highlightSource_measure.clear();
            const lineFeature = source_measure.getFeatures()[0];
            if (lineFeature) {
                const coords = lineFeature.getGeometry().getCoordinates();
                const startPixel = map.getPixelFromCoordinate(coords[0]);
                const endPixel = map.getPixelFromCoordinate(coords[coords.length - 1]);
                const hoverThreshold = 10;
                const distToStart = Math.sqrt(Math.pow(pixel[0] - startPixel[0], 2) + Math.pow(pixel[1] - startPixel[1], 2));
                const distToEnd = Math.sqrt(Math.pow(pixel[0] - endPixel[0], 2) + Math.pow(pixel[1] - endPixel[1], 2));
                if (distToStart < hoverThreshold) {
                    featureFound = true;
                    highlightSource_measure.addFeature(new ol.Feature(new ol.geom.Point(coords[0])));
                } else if (distToEnd < hoverThreshold) {
                    featureFound = true;
                    highlightSource_measure.addFeature(new ol.Feature(new ol.geom.Point(coords[coords.length - 1])));
                }
            }
            map.getTargetElement().style.cursor = featureFound ? 'grab' : '';
        });
        function clearMeasurement() {
            source_measure.clear();
            highlightSource_measure.clear();
            if (measurementOverlay) {
                map.removeOverlay(measurementOverlay);
                measurementOverlay = null;
            }
        }
        document.getElementById('measure-btn').addEventListener('click', function() {
            isMeasuring = !isMeasuring;
            this.classList.toggle('measuring', isMeasuring);
            modify.setActive(!isMeasuring);
            draw.setActive(isMeasuring);
            if (isMeasuring) {
                map.on('pointermove', pointerMoveHandler);
            } else {
                map.un('pointermove', pointerMoveHandler);
                if (helpTooltipElement_measure) helpTooltipElement_measure.style.display = 'none';
            }
        });
        document.getElementById('clear-btn').addEventListener('click', function() {
            if (isMeasuring) document.getElementById('measure-btn').click();
            clearMeasurement();
            document.getElementById('measure-btn').classList.remove('hidden');
            this.classList.add('hidden');
        });
    }

    function close_language_menu() {
        $('.language_menu .dropdown').removeClass('down');
        $('.language_menu .arrow').removeClass('gone');
    }

    window.click_language_menu = function() {
        $('.viewer_account_panel').removeClass('open');
        $('.language_menu .dropdown').toggleClass('down');
        $('.language_menu .arrow').toggleClass('gone');
    }

    window.change_language_map = function(lang,force=false) {
        $('.div_change_lang').show();
        $('#switching_lang').html($('#lang_item_'+lang).html()).promise().done(function() {
            setTimeout(function() {
                var current_url = location.href;
                if (current_url.indexOf('code=') !== -1 || current_url.indexOf('?') !== -1) {
                    if (current_url.indexOf('lang=') !== -1) {
                        if(window.default_language==lang && window.browser_language==lang) {
                            var new_url = current_url.replace(/&lang=[^&]+/,``);
                        } else {
                            var new_url = current_url.replace(/lang=[^&]+/, `lang=${lang}`);
                        }
                    } else {
                        if(window.default_language==lang && window.browser_language==lang) {
                            var new_url = current_url;
                        } else {
                            var new_url = current_url+`&lang=${lang}`;
                        }
                    }
                } else {
                    if (current_url.indexOf('@') !== -1) {
                        if(window.default_language==lang && window.browser_language==lang) {
                            var new_url = current_url.replace(/@[^/]+/, ``);
                        } else {
                            var new_url = current_url.replace(/@[^/]+/, `@${lang}`);
                        }
                    } else {
                        if(window.default_language==lang && window.browser_language==lang) {
                            var new_url = current_url;
                        } else {
                            var new_url = current_url+`@${lang}`;
                        }
                    }
                }
                location.href=new_url;
            },100);
        });
    }

    function init_category_fields_logic() {
        const categorySelect = document.getElementById('new_category');
        if (!categorySelect) return;
        let fieldsMap = {
            'street':      'new_store_street_container',
            'city':        'new_store_city_container',
            'state':       'new_store_state_container',
            'postal_code': 'new_store_postal_code_container',
            'county':      'new_store_county_container',
            'country':     'new_store_country_container',
            'website':     'new_store_website_container',
            'email':       'new_store_email_container',
            'hours':       'new_store_hours_container',
            'description': 'new_store_description_container',
            'phone':       'new_store_phone_container',
            'whatsapp':    'new_store_whatsapp_container'
        };
        for (let i = 1; i <= 20; i++) {
            fieldsMap['field_' + i] = 'new_store_field_' + i + '_container';
        }
        const update_am_fields_visibility = () => {
            const selectedOptions = Array.from(categorySelect.selectedOptions);
            if (selectedOptions.length === 0) {
                for (let key in fieldsMap) {
                    const el = document.getElementById(fieldsMap[key]);
                    if (el) {
                        el.classList.remove('hidden_c');
                    }
                }
                return;
            }
            for (let key in fieldsMap) {
                let containerId = fieldsMap[key];
                let containerElement = document.getElementById(containerId);
                if (!containerElement) continue;
                let showField = false;
                selectedOptions.forEach(option => {
                    let rules = {};
                    try {
                        let dataAttr = option.getAttribute('data-am-fields');
                        if (dataAttr && dataAttr !== "") {
                            rules = JSON.parse(dataAttr);
                        }
                    } catch (e) {
                        console.error("Errore parsing JSON per categoria:", option.text);
                    }
                    let visibleForThisCategory = true;
                    if (rules.hasOwnProperty(key)) {
                        visibleForThisCategory = (rules[key] == 1 || rules[key] == "1");
                    }
                    if (visibleForThisCategory) {
                        showField = true;
                    }
                });
                if (showField) {
                    containerElement.classList.remove('hidden_c');
                } else {
                    containerElement.classList.add('hidden_c');
                }
            }
        };
        categorySelect.addEventListener('change', update_am_fields_visibility);
        update_am_fields_visibility();
    }

    window.enable_select_start_point = function() {
        window.selecting_start_point = true;
        $('.direction_detail').hide();
        alertify.success(window.viewer_labels.click_start_point);
        map.getTargetElement().style.cursor = 'crosshair';
    };

    window.reset_start_point = function() {
        window.custom_start_lat = null;
        window.custom_start_lon = null;
        $('#direction_start_point').val(window.viewer_labels.my_location);
        $('#btn_reset_start_map').hide();
        window.trigger_route_recalc();
    };

    window.positionToAddress_start_point = function(lat, lon) {
        $('#direction_start_point').val(lat.toFixed(5) + ', ' + lon.toFixed(5));
        if (window.geocoding_provider === 'google') {
            $.get('ajax/google_position_to_address.php?lat=' + lat + '&lon=' + lon).done(function(resp) {
                if (resp.status === 'OK' && resp.results.length > 0) {
                    $('#direction_start_point').val(resp.results[0].formatted_address);
                }
            });
        } else {
            $.get('https://nominatim.openstreetmap.org/reverse?lat=' + lat + '&lon=' + lon + '&format=json&addressdetails=1').done(function(data) {
                if (data && data.display_name) {
                    $('#direction_start_point').val(data.display_name);
                }
            });
        }
    };

    window.enable_select_end_point = function() {
        window.selecting_end_point = true;
        $('.direction_detail').hide();
        alertify.success(window.viewer_labels.click_end_point);
        map.getTargetElement().style.cursor = 'crosshair';
    };

    window.reset_end_point = function() {
        window.custom_end_lat = null;
        window.custom_end_lon = null;
        $('#btn_reset_end_map').hide();
        $('#direction_end_point').val('');
        window.trigger_route_recalc();
    };

    window.positionToAddress_end_point = function(lat, lon) {
        $('#direction_end_point').val(lat.toFixed(5) + ', ' + lon.toFixed(5));
        if (window.geocoding_provider === 'google') {
            $.get('ajax/google_position_to_address.php?lat=' + lat + '&lon=' + lon).done(function(resp) {
                if (resp.status === 'OK' && resp.results.length > 0) {
                    $('#direction_end_point').val(resp.results[0].formatted_address);
                }
            });
        } else {
            $.get('https://nominatim.openstreetmap.org/reverse?lat=' + lat + '&lon=' + lon + '&format=json&addressdetails=1').done(function(data) {
                if (data && data.display_name) {
                    $('#direction_end_point').val(data.display_name);
                }
            });
        }
    };

    window.trigger_route_recalc = function() {
        var profile = $('.direction_profile_active').attr('data-profile') || 'driving-car';
        if (window.custom_start_lat != null && window.custom_start_lon != null) {
            open_ors_directions(profile, window.custom_start_lat, window.custom_start_lon);
        } else if(geolocation.getTracking()) {
            var my_lat_lon = ol.proj.transform(geolocation.getPosition(), 'EPSG:3857', 'EPSG:4326');
            open_ors_directions(profile, my_lat_lon[1], my_lat_lon[0]);
        } else {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function(position) {
                    open_ors_directions(profile, position.coords.latitude, position.coords.longitude);
                });
            }
        }
    };

    window.add_empty_waypoint = function() {
        window.route_waypoints.push({ lat: null, lon: null, address: '...' });
        window.render_waypoints();
        window.enable_select_waypoint(window.route_waypoints.length - 1);
    };

    window.remove_waypoint = function(index) {
        window.route_waypoints.splice(index, 1);
        window.render_waypoints();
        window.trigger_route_recalc();
    };

    window.enable_select_waypoint = function(index) {
        window.selecting_waypoint_index = index;
        $('.direction_detail').hide();
        alertify.success(window.viewer_labels.click_start_point);
        map.getTargetElement().style.cursor = 'crosshair';
    };

    window.render_waypoints = function() {
        var html = '';
        window.route_waypoints.forEach((wp, index) => {
            var letter = String.fromCharCode(66 + index);
            var addr_text = wp.lat == null ? '...' : (wp.address || wp.lat.toFixed(5)+','+wp.lon.toFixed(5));
            html += '<div class="direction_features noselect">';
            html += '    <div class="features_icon"><div style="background-color:orange; color:white;">'+letter+'</div></div>';
            html += '    <div class="features_value" style="display:flex; gap:5px;">';
            html += '        <input style="flex:1; margin-bottom:0;" type="text" readonly value="'+addr_text+'" />';
            html += '        <div onclick="enable_select_waypoint('+index+');" class="select_waypoint" style="cursor:pointer; background:#2f2f2f; color:white; padding:0 8px; border-radius:4px; line-height:26px;" title="'+window.viewer_labels.select_on_map+'"><i class="fas fa-crosshairs"></i></div>';
            html += '        <div onclick="remove_waypoint('+index+');" class="remove_waypoint" style="cursor:pointer; background:#dc2626; color:white; padding:0 8px; border-radius:4px; line-height:26px;" title="'+window.viewer_labels.remove+'"><i class="fas fa-trash"></i></div>';
            html += '    </div>';
            html += '</div>';
        });
        $('#direction_waypoints_container').html(html);
        var endLetter = String.fromCharCode(66 + window.route_waypoints.length);
        $('#direction_end_point').parent().prev().find('div').html(endLetter);
        $('.select_waypoint,.remove_waypoint').tooltipster({
            delay: 10,
            hideOnClick: true,
            position: 'top',
            theme: 'tooltipster-borderless'
        });
    };

    window.positionToAddress_waypoint = function(lat, lon, index) {
        var wp = window.route_waypoints[index];
        wp.address = lat.toFixed(5) + ', ' + lon.toFixed(5);
        window.render_waypoints();

        var query = window.geocoding_provider === 'google'
            ? 'ajax/google_position_to_address.php?lat=' + lat + '&lon=' + lon
            : 'https://nominatim.openstreetmap.org/reverse?lat=' + lat + '&lon=' + lon + '&format=json&addressdetails=1';

        $.get(query).done(function(data) {
            if (window.geocoding_provider === 'google' && data.status === 'OK') {
                wp.address = data.results[0].formatted_address;
            } else if (data && data.display_name) {
                wp.address = data.display_name;
            }
            window.render_waypoints();
        }).always(function() {
            window.trigger_route_recalc();
        });
    };

    window.hasWebGL = function() {
        try {
            const canvas = document.createElement("canvas");
            if (window.WebGL2RenderingContext && canvas.getContext("webgl2")) {
                return true;
            }
            if (window.WebGLRenderingContext && (canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))) {
                return true;
            }
            return false;
        } catch (e) {
            return false;
        }
    }

    $(document).ready(function() {
        var $dropzone = $('#photo_dropzone');
        var $fileInput = $('#photo_file');
        var $dzText = $('#dz-text');
        $dropzone.on('click', function(e) {
            if (e.target.id !== 'photo_file') {
                $fileInput.click();
            }
        });
        $dropzone.on('dragover', function(e) {
            e.preventDefault();
            e.stopPropagation();
            $dropzone.addClass('dragover');
        });
        $dropzone.on('dragleave', function(e) {
            e.preventDefault();
            e.stopPropagation();
            $dropzone.removeClass('dragover');
        });
        $dropzone.on('drop', function(e) {
            e.preventDefault();
            e.stopPropagation();
            $dropzone.removeClass('dragover');
            var files = e.originalEvent.dataTransfer.files;
            if(files.length > 0) {
                $fileInput[0].files = files;
                updateDropzonePreview(files[0]);
            }
        });
        $fileInput.on('change', function() {
            if(this.files.length > 0) {
                updateDropzonePreview(this.files[0]);
            } else {
                updateDropzonePreview(null);
            }
        });

        function updateDropzonePreview(file) {
            if(file && file.type.startsWith('image/')) {
                var reader = new FileReader();
                reader.onload = function(e) {
                    $('#photo_preview_image').attr('src', e.target.result);
                    $('.dz-message').hide();
                    $('#photo_preview_container').show();
                    $dropzone.addClass('has-file').removeClass('error-highlight');
                }
                reader.readAsDataURL(file);
            } else {
                $('#photo_preview_image').attr('src', '');
                $('#photo_preview_container').hide();
                $('.dz-message').show();
                $dropzone.removeClass('has-file');
            }
        }
    });
})(jQuery);
