// Storage for the options that the server gives us. This will define our filters.
var options = {};
// Last time we updated the spots/alerts list on display.
var lastUpdateTime;

// Load and apply any URL params. This is used for "embedded mode" where another site can embed a version of
// Spothole and provide its own interface options rather than using the user's saved ones. These may select things
// from the various filter & display options, so this function needs to be called after these are set up, but if
// the URL params ask for "embedded mode", this will suppress loading settings, so this needs to be called before
// that occurs..
function loadURLParams() {
    let params = new URLSearchParams(document.location.search);

    // Handle embedded mode. We set a global to e.g. suppress loading/saving settings, and apply an attribute to the
    // top-level html element to use CSS selectors to remove bits of UI.
    let embedded = params.get("embedded");
    if (embedded != null && embedded === "true") {
        useLocalStorage = false;
        $("html").attr("embedded-mode", "true");
    }

    // Handle other params
    updateSelectFromParam(params, "color-scheme", "color-scheme");
    updateSelectFromParam(params, "time-zone", "time-zone"); // Only on Spots and Alerts pages
    updateSelectFromParam(params, "limit", "spots-to-fetch"); // Only on Spots page
    updateSelectFromParam(params, "limit", "alerts-to-fetch"); // Only on Alerts page
    updateSelectFromParam(params, "max_age", "max-spot-age"); // Only on Map & Bands pages
    updateFilterFromParam(params, "band", "band");
    updateFilterFromParam(params, "sig", "sig");
    updateFilterFromParam(params, "source", "source");
    updateFilterFromParam(params, "mode", "mode");
    updateFilterFromParam(params, "dx_continent", "dx_continent");
    updateFilterFromParam(params, "de_continent", "de_continent");
}

// Update an HTML checkbox element so that its selected matches the given parameter (which must have a true or false value)
function updateCheckboxFromParam(params, paramName, checkboxID) {
    let v = params.get(paramName);
    if (v != null) {
        $("#" + checkboxID).prop("checked", (v === "true") ? true : false);
    }
}

// Update an HTML select element so that its value matches the given parameter
function updateSelectFromParam(params, paramName, selectID) {
    let v = params.get(paramName);
    if (v != null) {
        $("#" + selectID).prop("value", v);
        // Extra check if this is the "color scheme" select
        if (selectID == "color-scheme") {
            setColorScheme(v);
        }
    }
}

// Update a set of HTML checkbox elements describing a filter of the given name, so that any items named in the
// parameter (as a comma-separated list) will be enabled, and all others disabled. e.g. if paramName is
// "filter-band" and the params contain "filter-band=20m,40m", and prefix is "band", then #filter-button-band-30m
// would be disabled but #filter-button-band-20m and #filter-button-band-40m would be enabled.
function updateFilterFromParam(params, paramName, filterName) {
    let v = params.get(paramName);
    if (v != null) {
        // First uncheck all options for the filter
        $(".filter-button-" + filterName).prop("checked", false);
        // Now find out which ones should be enabled
        let s = v.split(",");
        s.forEach(val => $("#filter-button-" + filterName + "-" + val).prop("checked", true));
    }
}

// For a parameter, such as dx_continent, get the query string for the current filter options.
function getQueryStringFor(parameter) {
    return parameter + "=" + encodeURIComponent(getSelectedFilterOptions(parameter));
}

// For a parameter, such as dx_continent, get the filter options that are currently selected in the UI.
function getSelectedFilterOptions(parameter) {
    return $(".filter-button-" + parameter).filter(function() {
        return this.checked;
    }).map(function() {
        return this.value;
    }).get().join(",");
}

// For a parameter, such as dx_continent, return true if all possible options are enabled. (In this case, we don't need
// to bother sending this as one of the query parameters to the API; no parameter provided implies "send everything".)
function allFilterOptionsSelected(parameter) {
    var filter = $(".filter-button-" + parameter).filter(function() {
        return !this.checked;
    }).get();
    return filter.length == 0;
}


// Generate a filter card with multiple toggle buttons plus All/None buttons.
function generateMultiToggleFilterCard(elementID, filterQuery, options) {
    // Create a button for each option
    options.forEach(o => {
        $(elementID).append(`<input type="checkbox" class="btn-check filter-button-${filterQuery} storeable-checkbox" name="options" id="filter-button-${filterQuery}-${o}" value="${o}" autocomplete="off" onClick="filtersUpdated()" checked><label class="btn btn-outline-success" for="filter-button-${filterQuery}-${o}">${o}</label> `);
    });
    // Create All/None buttons
    $(elementID).append(` <span style="display: inline-block"><button id="filter-button-${filterQuery}-all" type="button" class="btn btn-outline-secondary" onclick="toggleFilterButtons('${filterQuery}', true);">All</button>&nbsp;<button id="filter-button-${filterQuery}-none" type="button" class="btn btn-outline-secondary" onclick="toggleFilterButtons('${filterQuery}', false);">None</button></span>`);
}

// Method called when "All" or "None" is clicked
function toggleFilterButtons(filterQuery, state) {
    $(".filter-button-" + filterQuery).each(function() {
        $(this).prop('checked', state);
    });
    filtersUpdated();
}

// Update the refresh timing display
function updateRefreshDisplay() {
    if (lastUpdateTime != null) {
        let secSinceUpdate = moment.duration(moment().diff(lastUpdateTime)).asSeconds();
        let count = REFRESH_INTERVAL_SEC;
        let updatingString = "Updating..."
        if (secSinceUpdate < REFRESH_INTERVAL_SEC) {
            count = REFRESH_INTERVAL_SEC - secSinceUpdate;
            if (count <= 60) {
                var number = count.toFixed(0);
                updatingString = "<span class='nowrap'>Updating in " + number + " second" + (number != "1" ? "s" : "") + ".</span>";
            } else {
                var number = Math.round(count / 60.0).toFixed(0);
                updatingString = "<span class='nowrap'>Updating in " + number + " minute" + (number != "1" ? "s" : "") + ".</span>";
            }
        }
        $("#timing-container").html("Last updated at " + lastUpdateTime.format('HH:mm') + " UTC. " + updatingString);
    }
}

// When the "use local time" field is changed, reload the table and save settings
function timeZoneUpdated() {
    updateTable();
    saveSettings();
}

// When one of the column toggle checkboxes are changed, reload the table and save settings
function columnsUpdated() {
    updateTable();
    saveSettings();
}

// Function to set the colour scheme based on the state of the UI select box
function setColorSchemeFromUI() {
    let theme = $("#color-scheme option:selected").val();
    if (theme != "") {
        setColorScheme(theme);
        saveSettings();
    }
}

// Function to set the color scheme. Supported values: "dark", "light", "auto"
function setColorScheme(mode) {
    let effectiveModeDark = mode == "dark";
    if (mode == "auto") {
        effectiveModeDark = window.matchMedia('(prefers-color-scheme: dark)').matches
    }
    $("html").attr("data-bs-theme", effectiveModeDark ? "dark" : "light");
    const metaThemeColor = document.querySelector("meta[name=theme-color]");
    metaThemeColor.setAttribute("content", effectiveModeDark ? "black" : "white");
    const metaAppleStatusBarStyle = document.querySelector("meta[name=apple-mobile-web-app-status-bar-style]");
    metaAppleStatusBarStyle.setAttribute("content", effectiveModeDark ? "black-translucent" : "white-translucent");
}

// Startup function to determine whether to use light or dark mode, or leave as auto
function usePreferredTheme() {
    // Work out if we have ever explicitly saved the value of our select box. If so, we set our colour scheme now based
    // on that. If not, we let the select stay with nothing selected, so that the server sets it to whatever the
    // server's default is when the options call is retrieved.
    let val = localStorage.getItem("#color-scheme:value");
    if (val != null) {
        setColorScheme(JSON.parse(val));
    }
}

// Sets up a listener on the OS light-dark theme change. If the Spothole user theme is set to Auto, the UI will be
// updated, otherwise if the Spothole user theme is forced to light or dark, that preference will remain.
function listenForOSThemeChange() {
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
        setColorScheme($("#color-scheme option:selected").val());
    });
}

// Startup
$(document).ready(function() {
    usePreferredTheme();
    listenForOSThemeChange();
});
