<!DOCTYPE HTML>
<html>
<head>
    <title>Project Horus Chase Mapper</title>

    <link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/leaflet.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/leaflet-sidebar.min.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/leaflet-control-topcenter.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/Leaflet.PolylineMeasure.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/leaflet-routing-machine.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/easy-button.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/tabulator_simple.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/jquery-ui.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='css/chasemapper.css') }}" rel="stylesheet">


    <!-- I should probably feel bad for using so many libraries, but apparently this is the way thing are done :-/ -->
    <script src="{{ url_for('static', filename='js/jquery-3.3.1.min.js')}}"></script>
    <script src="{{ url_for('static', filename='js/jquery-ui.min.js')}}"></script>
    <script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
    <script src="{{ url_for('static', filename='js/leaflet.js') }}"></script>
    <!-- Leaflet plugins... -->
    <script src="{{ url_for('static', filename='js/leaflet.rotatedMarker.js') }}"></script>
    <script src="{{ url_for('static', filename='js/leaflet-control-topcenter.js') }}"></script>
    <script src="{{ url_for('static', filename='js/leaflet-sidebar.min.js') }}"></script>
    <script src="{{ url_for('static', filename='js/Leaflet.Control.Custom.js') }}"></script>
    <script src="{{ url_for('static', filename='js/Leaflet.PolylineMeasure.js') }}"></script>
    <script src="{{ url_for('static', filename='js/easy-button.js') }}"></script>

    <script src="{{ url_for('static', filename='js/tabulator.min.js') }}"></script>

    <script src="{{ url_for('static', filename='js/d3.v3.min.js') }}"></script>
    <script src="{{ url_for('static', filename='js/micropolar-v0.2.2.js') }}"></script>

    <!-- Custom scripts -->
    <script src="{{ url_for('static', filename='js/habitat.js') }}"></script>
    <script src="{{ url_for('static', filename='js/sondehub.js') }}"></script>
    <script src="{{ url_for('static', filename='js/utils.js') }}"></script>
    <script src="{{ url_for('static', filename='js/tables.js') }}"></script>
    <script src="{{ url_for('static', filename='js/settings.js') }}"></script>
    <script src="{{ url_for('static', filename='js/balloon.js') }}"></script>
    <script src="{{ url_for('static', filename='js/predictions.js') }}"></script>
    <script src="{{ url_for('static', filename='js/car.js') }}"></script>
    <script src="{{ url_for('static', filename='js/bearings.js') }}"></script>


    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

    <script type="text/javascript" charset="utf-8">

        // Object which will contain balloon markers and traces.
        // properties for each key in this object (key = callsign)
        //  latest_data - latest sonde telemetry object from SondeDecoded
        //  marker: Leaflet marker object.
        //  path: Leaflet polyline object.
        //  pred_marker: Leaflet marker for predicted landing position.
        //  pred_path: Leaflet polyline object for predicted path.
        //  burst_marker: Leaflet marker for burst prediction.
        //  abort_marker: Leaflet marker for abort landing prediction.
        //  abort_path: Leaflet marker for abort prediction track.
        var balloon_positions = {};
        var initial_load_complete = false;

        // The sonde we are currently following on the map
        var balloon_currently_following = "none";

        // Other chase vehicles
        var chase_vehicles = {};
        // Only add chase cars which are (initially) within this range limit (km).
        var vehicle_max_range = 200.0;

        // Chase car position.
        // properties will contain:
        //   latest_data: [lat,lon, alt] (latest car position)
        //   heading: Car heading (to point icon appropriately.)
        //   marker: Leaflet marker
        var chase_car_position = {latest_data: [], heading:0, marker: 'NONE', path: 'NONE'};

        // Home position marker
        var home_marker = 'NONE';

        // Data Age variables - these are updated regularly to indicate
        // if we haven't received data in a while.
        var payload_data_age = 0.0;
        var car_data_age = 0.0;
        var pred_data_age = 0.0;

        // Other markers which may be added. (TBD, probably other chase car positions via the LoRa payload?)
        var misc_markers = {};

        // Habitat chase cars
        var habitat_chase_cars = {};

        // Functions defined later.
        var setChaseCarTrack;

        // Global dark mode setting
        var dark_mode = false;
        var dark_mode_layers = ["Alidade Smooth Dark", "Dark Matter"];

        // Leaflet map instance.
        var map;
        // Routing Engine
        var router;


        // Socket.IO Settings
        var namespace = '/chasemapper';
        // Socket.IO instance.
        var socket;

        $(document).ready(function() {

            // Connect to the Socket.IO server.
            // The connection URL has the following format:
            //     http[s]://<domain>:<port>[/<namespace>]
            socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);


            // Grab the System config on startup.
            // Refer to config.py for the contents of the configuration blob.
            $.ajax({
                  url: "/get_config",
                  dataType: 'json',
                  async: false, // Yes, this is deprecated...
                  success: function(data) {
                    serverSettingsUpdate(data);
                  }
            });

            // Handler for further settings updates supplied by the server
            // (i.e. when another client makes a change)
            socket.on('server_settings_update', function(data){
                serverSettingsUpdate(data);
            });

            // Add handlers for various text fields.
            // Use the jquery on-changed call for text entry fields,
            // so they only fire after they lose focus.
            $("#burstAlt").change(function(){
                clientSettingsUpdate();
            });
            $("#descentRate").change(function(){
                clientSettingsUpdate();
            });
            $("#predUpdateRate").change(function(){
                clientSettingsUpdate();
            });
            $("#habitatUpdateRate").change(function(){
                clientSettingsUpdate();
            });
            $("#habitatCall").change(function(){
                clientSettingsUpdate();
            });

            // Handlers for range ring settings.
            $("#ringQuantity").change(function(){
                updateRangeRings();
            });
            $("#ringSpacing").change(function(){
                updateRangeRings();
            });
            $("#ringWeight").change(function(){
                updateRangeRings();
            });
            $("#ringColorSelect").change(function(){
                updateRangeRings();
            });
            $("#ringCustomColor").change(function(){
                updateRangeRings();
            });

            // Handlers for bearing settings
            $("#bearingWeight").change(function(){
                updateBearingSettings();
            });
            $("#bearingLength").change(function(){
                updateBearingSettings();
            });
            $("#bearingConfidenceThreshold").change(function(){
                updateBearingSettings();
            });
            $("#bearingMaximumAge").change(function(){
                updateBearingSettings();
            });
            $("#bearingMinOpacity").change(function(){
                updateBearingSettings();
            });
            $("#bearingMaxOpacity").change(function(){
                updateBearingSettings();
            });
            $("#bearingColorSelect").change(function(){
                updateBearingSettings();
            });
            $("#bearingCustomColor").change(function(){
                updateBearingSettings();
            });

            // Changes to the telemetry source profile selection works a bit differently, as we 
            // need to do a fair bit of work on the server when these occur. These have a dedicated
            // socketio message.
            $("#profileSelect").change(function(){
                // On a profile selection change, emit a message to the client.
                socket.emit('profile_change', this.value);

                // Remove chase car if switching to a profile which does not have live position updates.
                _profile = this.value;
                reconfigureCarMarker(this.value);
            });

            // Handle arrival of new log data.
            socket.on('log_event', function(msg) {
                $('#log_data').prepend('<br>' + $('<div/>').text(msg.timestamp + " [" + msg.level + "]: " + msg.msg).html());
                // Scroll to the bottom of the log table
                $("#log_data").scrollTop($("#log_data")[0].scrollHeight);
            });

            //
            // LEAFLET MAP SETUP
            //
            // Setup a basic Leaflet map
            map = L.map('map').setView([chase_config.default_lat, chase_config.default_lon], 8);

            // Add OSM Map Layer
            var osm_map = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            }).addTo(map);

            // Add OSM Topo Map Layer
            var osm_topo_map = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
                attribution: '&copy; <a href="https://wiki.openstreetmap.org/wiki/OpenTopoMap">OpenTopoMap</a> contributors'
            });

            // Add ESRI Satellite Map layers.
            var esrimapLink = 
            '<a href="http://www.esri.com/">Esri</a>';
            var esriwholink = 
            'i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community';
            var esri_sat_map = L.tileLayer(
            'http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', 
            {
                attribution: '&copy; '+esrimapLink+', '+esriwholink,
                maxZoom: 18,
            });
            // Dark Matter map layer, one of the maps suitable for 'dark mode'
            var dark_matter_map = L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/dark_all/{z}/{x}/{y}.png', {
                attribution: '&copy; <a href="https://carto.com/help/building-maps/basemap-list/">Carto</a>'
            });

            

            var map_layers = {'OSM':osm_map, 'OpenTopo':osm_topo_map, 'ESRI Satellite':esri_sat_map, 'Dark Matter':dark_matter_map};

            // Add ThunderForest layers, if we have a key provided.
            if (chase_config.thunderforest_api_key !== 'none'){
                // Thunderforest Outdoors layer.
                var thunderforest_outdoors = L.tileLayer('https://tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey='+chase_config.thunderforest_api_key, 
                {
                    attribution: '&copy; <a href="http://www.thunderforest.com">Thunderforest</a>, Data &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>'
                });
                map_layers['Outdoors (Terrain)'] = thunderforest_outdoors;

            }

            if (chase_config.stadia_api_key !== 'none'){
                // Stadia Alidade Smooth Dark Layer.
                var alidade_smooth_dark = L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png?apikey='+chase_config.stadia_api_key, 
                {
                    attribution: '&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
                });
                map_layers['Alidade Smooth Dark'] = alidade_smooth_dark;

            }

            // Add Offline map layers, if we have any.
            for (var i = 0, len = chase_config.offline_tile_layers.length; i < len; i++) {
                var _layer_name = chase_config.offline_tile_layers[i];
                map_layers['Offline - ' + _layer_name] = L.tileLayer(location.protocol + '//' + document.domain + ':' + location.port + '/tiles/'+_layer_name+'/{z}/{x}/{y}.png');
            }

            // Add measurement control.

            if (chase_config['unitselection'] == "imperial") {
                L.control.polylineMeasure({
                    position: 'topleft',
                    unit: 'landmiles',
                    showClearControl: true,
                }).addTo(map);
            }


            if (chase_config['unitselection'] == "metric") { 
                L.control.polylineMeasure({
                    position: 'topleft',
                    unit: 'metres',
                    showClearControl: true,
                }).addTo(map);
            }


            
            // Add layer selection control (top right).
            map.addControl(new L.Control.Layers(map_layers));

            // Add map scale.
            if (chase_config['unitselection'] == "imperial") { L.control.scale({imperial: true, metric: false}).addTo(map) ;}
            if (chase_config['unitselection'] == "metric") { L.control.scale({imperial: false, metric: true}).addTo(map) ;}



            // Units for rings
            if (chase_config['unitselection'] == "imperial") { document.getElementById("ring_spacing").innerHTML = "Ring Spacing (ft)";}
            if (chase_config['unitselection'] == "metric")   { document.getElementById("ring_spacing").innerHTML = "Ring Spacing (m)";}

            // Add sidebar to map (where all of our controls are!)
            var sidebar = L.control.sidebar('sidebar').addTo(map);

            // Add custom controls, which show various sets of data.

            // Telemetry table - shows all payload telemetry.
            L.control.custom({
                position: 'bottomright',
                content : "<div class='centerWrapper'><div id='telem_table_btn' class='center_btn'><i class='fa fa-angle-right fa-4x text-center'></i></div><div id='telem_table' style='float:right;'></div></div>",
                classes : 'btn-group-horizonal btn-group-sm',
                id: 'telem_display',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);

            // Allow hiding of the telemetry table. This function is in tables.js
            $("#telem_table_btn").click(toggleTelemTableHide);


            // Summary display - a 'quick-look' of where the currently tracked payload is and what it's doing.
            L.control.custom({
                position: 'topcenter',
                content : "<div id='summary_table'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'summary_display',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);

            // Data age display - shows how old the various datasets are.
            L.control.custom({
                position: 'topleft',
                content : "<div class='dataAgeHeader'>Data Age</div><div id='payload_age' class='dataAgeOK'></div><div id='car_age' class='dataAgeOK'></div><div id='pred_age' class='dataAgeOK'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'age_display',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);

            // Chase Car Speed Display
            L.control.custom({
                position: 'bottomleft',
                content : "<div class='dataAgeHeader' id='chase_car_speed_header'></div><div id='chase_car_speed' class='chaseCarSpeed'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'speed_display',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);
            // Chase Car Heading Display
            L.control.custom({
                position: 'bottomleft',
                content : "<div class='dataAgeHeader' id='chase_car_heading_header'></div><div id='chase_car_heading' class='chaseCarSpeed'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'heading_display',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);

            // Time-to-landing display - shows the time until landing for the currently tracked payload.
            L.control.custom({
                position: 'bottomleft',
                content : "<div id='time_to_landing' class='timeToLanding'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'ttl_display',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);


            L.control.custom({
                position: 'bottomright',
                content : "<div id='bearing_table'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'bearing_data',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);

            L.control.custom({
                position: 'bottomright',
                content : "<div id='bearing_plot'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'bearing_plot_control',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);

            // Used to show log replay time information, if received.
            L.control.custom({
                position: 'bottomcenter',
                content : "<div id='log_time' class='chaseCarSpeed'></div>",
                classes : 'btn-group-vertical btn-group-sm',
                id: 'log_time_control',
                style   :
                {
                    margin: '5px',
                    padding: '0px 0 0 0',
                    cursor: 'pointer',
                }
            })
            .addTo(map);



            // Follow buttons - these just set the radio buttons on the settings pane.
            // TODO: Figure out how to centre the icons under iOS's Safari browser.
            // Also TODO: Find a decent balloon icon!
            L.easyButton('fa-paper-plane', function(btn, map){
                $('input:radio[name=autoFollow]').val(['payload']);
            }, 'Follow Payload', 'followPayloadButton', {
                position: 'topright'
            }
            ).addTo(map);

            L.easyButton('fa-car', function(btn, map){
                $('input:radio[name=autoFollow]').val(['car']);
            }, 'Follow Chase Car', 'followCarButton', {
                position: 'topright'
            }
            ).addTo(map);

            map.zoomControl.setPosition('topright');

            // Experimental routing control
            // Currently disabled, as there is currently not enough control around how the map is re-panned
            // after a route is calculated.
            // router = L.Routing.control({
            //     waypoints: [null],
            //     show: false,
            //     showAlternatives: false
            // }).addTo(map);

            // Handler for when the user manually moves the map. This turns off
            // the auto-follow options.
            // Note we have to use 'dragend' else map movements from auto-follow would trigger this.
            function mapMovedEvent(e){
                // The user has panned the map, stop following things.
                $('input:radio[name=autoFollow]').val(['none']);
            }
            map.on('dragend',mapMovedEvent);


            map.on('baselayerchange', function (e) {
                if(dark_mode_layers.includes(e.name)){
                    dark_mode = true;
                }else {
                    dark_mode = false;
                }
            });

            initTables();

            
            // Grab the recent archive of telemetry data
            // This should only ever be run once - on page load.
            $.ajax({
                  url: "/get_telemetry_archive",
                  dataType: 'json',
                  async: true,
                  success: function(data) {

                    for (callsign in data){
                        add_new_balloon(data[callsign]);
                    }
                    // Update telemetry table
                    updateTelemetryTable();
                    initial_load_complete = true;
                  }
            });

            // Initialise bearings
            initialiseBearings();

            // Initial setup of station marker, if using a profile which uses it.
            reconfigureCarMarker(chase_config.selected_profile);


            // Telemetry event handler.
            // We will get one of these mesages with every new balloon position
            socket.on('telemetry_event', function(data) {
                handleTelemetry(data);
            });

            socket.on('modem_stats_event', function(data) {
                handleModemStats(data);
            });

            // Predictor Functions
            socket.on('predictor_model_update', function(data){
                var _model_data = data.model;
                $("#predictorModelValue").text(_model_data);
            });
        
            socket.on('predictor_update', function(data){
                handlePrediction(data);
            });

            socket.on('bearing_change', function(data){
                bearingUpdate(data);
            });

            socket.on('server_bearings_cleared', function(data){
                destroyAllBearings();
            });


            $("#downloadModel").click(function(){
                socket.emit('download_model', {data: 'plzkthx'});
            });

            $("#clearPayloadData").click(function(){
                var _confirm = confirm("Really clear all Payload data?");
                if (_confirm == true){
                    socket.emit('payload_data_clear', {data: 'plzkthx'});

                    // Clear all payload markers and tracks from the map/
                    for (_callsign in balloon_positions){
                        balloon_positions[_callsign].marker.remove();
                        balloon_positions[_callsign].path.remove();
                        balloon_positions[_callsign].pred_path.remove();
                        balloon_positions[_callsign].abort_path.remove();
                        // Clear out the markers if they exist.
                        if (balloon_positions[_callsign].abort_marker != null){
                            balloon_positions[_callsign].abort_marker.remove();
                        }
                        if (balloon_positions[_callsign].burst_marker != null){
                            balloon_positions[_callsign].burst_marker.remove();
                        }
                        if (balloon_positions[_callsign].pred_marker != null){
                            balloon_positions[_callsign].pred_marker.remove();
                        }
                    }
                    // Reset the balloon positions object to nothing.
                    balloon_positions = {};
                    balloon_currently_following = "none";
                    // Update tables.
                    updateTelemetryTable();
                    updateSummaryDisplay();
                    // Clear the time-to-landing display.
                    $('#time_to_landing').text("");
                }
            });

            $("#clearCarData").click(function(){
                var _confirm = confirm("Really clear all Chase Car data?");
                if (_confirm == true){
                    socket.emit('car_data_clear', {data: 'plzkthx'});
                    if (chase_car_position.marker !== "NONE"){
                        chase_car_position.marker.remove();
                    }
                    if (chase_car_position.path !== "NONE"){
                        chase_car_position.path.remove();
                    }

                    chase_car_position = {latest_data: [], heading:0, marker: 'NONE', path: 'NONE'};

                }
            });

            // Function to show/hide chase car track tail.
            setChaseCarTrack = function(){
                // Read state of checkbox
                var _car_track_enabled = document.getElementById("chaseCarTrack").checked;
                // Only continue if we have chase car data to show/hide.
                if (chase_car_position !== "NONE"){
                    if (_car_track_enabled == false){
                        chase_car_position.path.remove();
                    }else{
                        chase_car_position.path.addTo(map);
                    }
                }
            };

            // Tell the server we are connected and ready for data.
            socket.on('connect', function() {
                socket.emit('client_connected', {data: 'I\'m connected!'});
                // This will cause the server to emit a few messages telling us to fetch data.
            });


            // Data age update.
            var age_update_rate = 500;
            window.setInterval(function () {
                // Update the data age displays.
                payload_data_age += age_update_rate/1000.0;
                car_data_age += age_update_rate/1000.0;
                pred_data_age += age_update_rate/1000.0;

                if (balloon_currently_following === 'none'){
                    $("#payload_age").text("Payload: No Data.");
                }else{
                    $("#payload_age").text("Payload: " + payload_data_age.toFixed(1)+"s");
                    if (payload_data_age > payload_bad_age){
                        $("#payload_age").removeClass();
                        $("#payload_age").addClass('dataAgeBad');
                    }else{
                        $("#payload_age").removeClass();
                        $("#payload_age").addClass('dataAgeOK');
                    }
                }

                if(chase_car_position.latest_data.length == 0){
                    $("#car_age").text("Car GPS: No Data.");
                }else{
                    $("#car_age").text("Car GPS: " + car_data_age.toFixed(1)+"s");
                    if (car_data_age > car_bad_age){
                        $("#car_age").removeClass();
                        $("#car_age").addClass('dataAgeBad');
                    }else{
                        $("#car_age").removeClass();
                        $("#car_age").addClass('dataAgeOK');
                    }
                }

                if (chase_config['pred_enabled']==false){
                    $("#pred_age").text("Predictions: No Data.");
                }else{
                    $("#pred_age").text("Predictions: " + pred_data_age.toFixed(1)+"s");
                }
            }, age_update_rate);


            // Habitat/Sondehub Chase Car Position Grabber
            var habitat_update_rate = 20000;
            window.setInterval(function(){
                if(document.getElementById("showOtherCars").checked){
                    if (chase_config.profiles[chase_config.selected_profile].online_tracker === "habitat"){
                        get_habitat_vehicles();
                    }
                    else if (chase_config.profiles[chase_config.selected_profile].online_tracker === "sondehub"){
                        get_sondehub_vehicles();
                    }
                    else if (chase_config.profiles[chase_config.selected_profile].online_tracker === "sondehubamateur"){
                        get_sondehub_amateur_vehicles();
                    }
                    else{
                        // Do nothing...
                    }
                }
            }, habitat_update_rate); 

            // Sadly we can't request location information unless chasemapper is served up via HTTPS
            // which is a bit difficult to make happen.
            // window.setInterval(function(){
            //     if(document.getElementById('useDevicePosition').checked){
            //         if(navigator.geolocation){
            //             car_bad_age = 20.0;
            //             navigator.geolocation.getCurrentPosition(devicePositionCallback,devicePositionError,{enableHighAccuracy:true});
            //         }
            //     }
            // }, 5000);


            window.setInterval(function(){
                if(Object.keys(bearing_store).length > 0){
                    $.ajax({
                          url: "/server_time",
                          dataType: 'json',
                          async: true,
                          success: function(data) {
                              latest_server_timestamp = data;
                              restyleBearings();
                          }
                    });
                }
            },10000); 
        });
    </script>
</head>
<body>

        <!-- Dialog boxes. These are activated from the telemetry table - see tables.js -->
        <div id="telemetry-select-dialog" title="Payload Selection" style='display:none;'>
            <div class="paramRow">
                <b>Current Position:</b> <div style='float:right;' id='telemDialogPosition'></div><br/>
            </div>
            <div class="paramRow">
                <b>Predicted Landing:</b> <div style='float:right;' id='telemDialogPredPosition'></div><br/>
            </div>
            <div class="paramRow">
                <b>Select Action:</b><br/>
            </div>
        </div>

        <div id="mark-recovered-dialog" title="Mark Payload Recovered" style='display:none;'>
            <div class="paramRow">
                <b>Last Position:</b> <div style='float:right;' id='recoveryPosition'></div><br/>
            </div>
            <div class="paramRow">
                <b>Recovery Successful:</b> <input type="checkbox" class="paramSelector" id="recoverySuccessful" checked><br/>
            </div>
            <div class="paramRow">
                <b>Use Car Position:</b> <input type="checkbox" class="paramSelector" id="recoveryCarPosition" onclick='setRecoveryCarPosition();'><br/>
            </div>
            <div class="paramRow">
                <b>Title:</b><input type="text" class="paramEntry" size="40" id="customRecoveryTitle"><br/>
            </div>
            <div class="paramRow">
                <b>Message:</b><input type="text" class="paramEntry" size="40" id="customRecoveryMessage"><br/>
            </div>
        </div>

        <div id="sidebar" class="sidebar collapsed">
        <!-- Nav tabs -->
        <div class="sidebar-tabs">
            <ul role="tablist">
                <li><a href="#home" role="tab"><i class="fa fa-bars"></i></a></li>
                <li><a href="#settings" role="tab"><i class="fa fa-gear"></i></a></li>
                <li><a href="#car-settings" role="tab"><i class="fa fa-car"></i></a></li>
                <li><a href="#df-settings" role="tab"><i class="fa fa-compass"></i></a></li>
            </ul>
        </div>

        <!-- Tab panes -->
        <div class="sidebar-content">
            <div class="sidebar-pane" id="home">
                <div class="paramRow">
                    <b>Chasemapper Version: </b> <div id="chasemapper_version" class="paramEntry">Unknown</div></br>
                </div>
            </br>
                <h1 class="sidebar-header">
                    Log Messages
                    <span class="sidebar-close"><i class="fa fa-caret-left"></i></span>
                </h1>

                <div id="log_data" class="logText"></div>

            </div>

            <div class="sidebar-pane" id="settings">
                <h1 class="sidebar-header">Settings<span class="sidebar-close"><i class="fa fa-caret-left"></i></span></h1>
                </hr>
                <h3>Data Source</h3>
                <select id="profileSelect" name="profileSelect">
                </select>

                <h3>Map</h3>
                <h4>Auto-Follow</h4>
                <form>
                  <input type="radio" name="autoFollow" value="payload" checked> Payload<br>
                  <input type="radio" name="autoFollow" value="car"> Chase Car<br>
                  <input type="radio" name="autoFollow" value="none"> None
                </form>
                </hr>
                <div class="paramRow">
                    <b>Show Car Track</b> <input type="checkbox" class="paramSelector" id="chaseCarTrack" onclick='setChaseCarTrack();' checked>
                </div>

                </hr>
                <h3>Predictor</h3>
                <div class="paramRow" id="predictorModel">
                    <b>Current Model: </b> <div class="predictorModelValue" id="predictorModelValue">Disabled</div>
                </div>
                <div class="paramRow">
                    <b>Download Model</b> <button type="button" class="paramSelector" id="downloadModel">Download</button>
                </div>
                <div class="paramRow">
                    <b>Enable Predictions</b> <input type="checkbox" class="paramSelector" id="predictorEnabled" onclick='clientSettingsUpdate();'>
                </div>
                <div class="paramRow">
                    <b>Show 'Abort' Predictions</b> <input type="checkbox" class="paramSelector" id="abortPredictionEnabled" onclick='clientSettingsUpdate();'>
                </div>
                <div class="paramRow">
                    <b>Burst Altitude</b><input type="text" class="paramEntry" id="burstAlt"><br/>
                </div>
                <div class="paramRow">
                    <b>Descent Rate</b><input type="text" class="paramEntry" id="descentRate"><br/>
                </div>
                <div class="paramRow">
                    <b>Update Rate</b><input type="text" class="paramEntry" id="predUpdateRate"><br/>
                </div>
                </hr>
                </hr>
                <h3>Other</h3>
                <div class="paramRow">
                    <button type="button" class="paramSelector" id="clearPayloadData">Clear Payload Data</button></br>
                </div>
                <div class="paramRow">
                    <button type="button" class="paramSelector" id="clearCarData">Clear Chase-Car Track</button></br>
                </div>
            
            </div>

            <div class="sidebar-pane" id="car-settings">
                <h1 class="sidebar-header">
                    Car Settings
                    <span class="sidebar-close"><i class="fa fa-caret-left"></i></span>
                </h1>

                <!--
                <h3>Car Position Source</h3>
                <div class="paramRow">
                    <b>Use Device Position:</b> <input type="checkbox" class="paramSelector" id="useDevicePosition">
                </div>
                --> 

                <h3>Habitat Chase Car</h3>
                <div class="paramRow">
                    <b>Show Nearby Chase-Cars:</b> <input type="checkbox" class="paramSelector" id="showOtherCars" onclick="show_habitat_vehicles();">
                </div>
                <div class="paramRow">
                    <b>Enable Chase-Car Position Upload</b> <input type="checkbox" class="paramSelector" id="habitatUploadEnabled" onclick='clientSettingsUpdate();'>
                </div>
                <div class="paramRow">
                    <b>Habitat Call:</b><input type="text" class="paramEntry" id="habitatCall"><br/>
                </div>
                <div class="paramRow">
                    <b>Update Rate (seconds):</b><input type="text" class="paramEntry" id="habitatUpdateRate"><br/>
                </div>

                <h3>Range Rings</h3>
                <div class="paramRow">
                    <b>Enable Range Rings</b> <input type="checkbox" class="paramSelector" id="rangeRingsEnabled" onclick='updateRangeRings();'>
                </div>
                <div class="paramRow">
                    <b>Ring Qty</b><input type="text" class="paramEntry" id="ringQuantity" value="5"><br/>
                </div>
                <div class="paramRow">
                    <b> <p><p id="ring_spacing">Ring Spacing (m)</p></p></b><input type="text" class="paramEntry" id="ringSpacing" value="1000"><br/>
                </div>
                <div class="paramRow">
                    <b>Ring Weight (px)</b><input type="text" class="paramEntry" id="ringWeight" value="2"><br/>
                </div>
                <div class="paramRow">
                    <b>Ring Color</b>
                    <select class="paramSelector" id="ringColorSelect" name="ringColorSelect">
                    <option value='red'>Red</option>
                    <option value='black'>Black</option>
                    <option value='green'>Green</option>
                    <option value='blue'>Blue</option>
                    <option value='custom'>Custom</option>
                    </select>
                    <br/>
                </div>
                <div class="paramRow">
                    <b>Custom Color</b><input type="text" class="paramEntry" id="ringCustomColor" value="#FF0000"><br/>
                </div>

                <h3>Speed/Heading Display</h3>
                <div class="paramRow">
                    <b>Show Chase Car Speed:</b> <input type="checkbox" class="paramSelector" id="showCarSpeed">
                </div>
                <div class="paramRow">
                    <b>Show Chase Car Heading:</b> <input type="checkbox" class="paramSelector" id="showCarHeading">
                </div>

                <h3>GPS/Heading Status</h3>
                <div class="paramRow">
                    <b>SVs Tracked:</b> <div class="predictorModelValue" id='numSVStatus'>---</div>
                </div>
                <div class="paramRow">
                    <b>Heading:</b> <div class="predictorModelValue" id='headingStatus'>---</div>
                </div>


            </div>

            <div class="sidebar-pane" id="df-settings">
                <h1 class="sidebar-header">
                    DF Settings
                    <span class="sidebar-close"><i class="fa fa-caret-left"></i></span>
                </h1>

                <div class="paramRow">
                    <b>Enable Bearings</b> <input type="checkbox" class="paramSelector" id="bearingsEnabled" checked onclick='toggleBearingsEnabled();'>
                </div>

                <div class="paramRow">
                    <b>Bearing-Only Mode</b> <input type="checkbox" class="paramSelector" id="bearingsOnlyMode" onclick='toggleBearingsOnlyMode();'>
                </div>

                <div class="paramRow">
                    <b>Enable TDOA Plot</b> <input type="checkbox" class="paramSelector" id="tdoaEnabled" checked>
                </div>

                <div class="paramRow">
                    <b>Big TDOA Plot</b> <input type="checkbox" class="paramSelector" id="bigTDOAEnabled">
                </div>

                <div class="paramRow">
                    <b>Confidence Threshold</b><input type="text" class="paramEntry" id="bearingConfidenceThreshold" value="5.0"><br/>
                </div>

                <div class="paramRow">
                    <b>Maximum Age (min)</b><input type="text" class="paramEntry" id="bearingMaximumAge" value="10"><br/>
                </div>

                <div class="paramRow">
                    <b>Show Stationary Bearings</b> <input type="checkbox" class="paramSelector" id="showStationaryBearings">
                </div>

                <div class="paramRow">
                    <button type="button" class="paramSelector" id="clearBearingsBtn" onclick='destroyAllBearings();'>Clear Map</button></br>
                </div>
                <div class="paramRow">
                    <button type="button" class="paramSelector" id="flushBearingsBtn" onclick='flushBearings();'>Flush Bearing Store</button></br>
                </div>

                <h3>Bearing Sources</h3>
                <div id="bearing_source_selector"></div>

                <h3>Bearing Style</h3>
                <div class="paramRow">
                    <b>Bearing Length (km)</b><input type="text" class="paramEntry" id="bearingLength" value="10"><br/>
                </div>
                <div class="paramRow">
                    <b>Bearing Weight (px)</b><input type="text" class="paramEntry" id="bearingWeight" value="1.0"><br/>
                </div>
                <div class="paramRow">
                    <b>Bearing Min Opacity</b><input type="text" class="paramEntry" id="bearingMinOpacity" value="0.1"><br/>
                </div>
                <div class="paramRow">
                    <b>Bearing Max Opacity</b><input type="text" class="paramEntry" id="bearingMaxOpacity" value="0.8"><br/>
                </div>
                <div class="paramRow">
                    <b>Bearing Color</b>
                    <select class="paramSelector" id="bearingColorSelect" name="bearingColorSelect">
                    <option value='black'>Black</option>
                    <option value='white'>White</option>
                    <option value='red'>Red</option>
                    <option value='green'>Green</option>
                    <option value='blue'>Blue</option>
                    <option value='custom'>Custom</option>
                    </select>
                    <br/>
                </div>
                <div class="paramRow">
                    <b>Custom Color</b><input type="text" class="paramEntry" id="bearingCustomColor" value="#FF0000"><br/>
                </div>

                <div class="paramRow">
                    <button type="button" class="paramSelector" id="redrawBearingsBtn" onclick='redrawBearings();'>Redraw Bearings</button></br>
                </div>

                <h3>Manual Bearing Entry</h3>
                <div class="paramRow">
                    <input type="text" id="bearingManualEntry" value="0"><br/><button type="button" class="paramSelector" id="manualBearingBtn" onclick='manualBearing();'>Plot</button></br>
                </div>

            </div>
        </div>
    </div>

    <div id="map" class="sidebar-map"></div>
</body>
</html>
