import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { GoogleTms } from '@basemaps/geo';
import maplibre from 'maplibre-gl';
import { Component } from 'react';
import { MapAttribution } from '../attribution.js';
import { Config } from '../config.js';
import { getTileGrid, locationTransform } from '../tile.matrix.js';
import { WindowUrl } from '../url.js';
import { Debug } from './debug.js';
import { MapSwitcher } from './map.switcher.js';
/**
 * Map loading in maplibre is weird, the on('load') event is different to 'loaded'
 * this function waits until the map.loaded() function is true before being run.
 */
export function onMapLoaded(map, cb) {
    if (map.loaded())
        return cb();
    setTimeout(() => onMapLoaded(map, cb), 100);
}
export class Basemaps extends Component {
    constructor() {
        super(...arguments);
        /** Ignore the location updates */
        this.ignoreNextLocationUpdate = false;
        this.updateLocation = () => {
            if (this.ignoreNextLocationUpdate) {
                this.ignoreNextLocationUpdate = false;
                return;
            }
            const location = Config.map.location;
            this.map.setZoom(location.zoom);
            this.map.setCenter([location.lon, location.lat]);
        };
        this.updateBounds = (bounds) => {
            if (Config.map.tileMatrix !== GoogleTms) {
                // Transform bounds to current tileMatrix
                const lngLatBounds = maplibre.LngLatBounds.convert(bounds);
                const upperLeft = lngLatBounds.getNorthEast();
                const lowerRight = lngLatBounds.getSouthWest();
                const zoom = this.map.getZoom();
                const upperLeftLocation = locationTransform({ lat: upperLeft.lat, lon: upperLeft.lng, zoom }, Config.map.tileMatrix, GoogleTms);
                const lowerRightLocation = locationTransform({ lat: lowerRight.lat, lon: lowerRight.lng, zoom }, Config.map.tileMatrix, GoogleTms);
                bounds = [
                    [upperLeftLocation.lon, upperLeftLocation.lat],
                    [lowerRightLocation.lon, lowerRightLocation.lat],
                ];
            }
            this.map.fitBounds(bounds);
        };
        this.updateStyle = () => {
            this.ensureGeoControl();
            const tileGrid = getTileGrid(Config.map.tileMatrix.identifier);
            const style = tileGrid.getStyle(Config.map.layerId, Config.map.style);
            this.map.setStyle(style);
            if (Config.map.tileMatrix !== GoogleTms)
                this.map.setMaxBounds([-180, -85.06, 180, 85.06]);
            else
                this.map.setMaxBounds();
            this.forceUpdate();
        };
        this._events = [];
        this.updateUrlTimer = null;
        this.onRender = () => {
            if (this.updateUrlTimer != null)
                return;
            this.updateUrlTimer = setTimeout(() => this.setLocationUrl(), 1000);
        };
    }
    /**
     * Only show the geocontrol on GoogleTMS
     * As it does not work with the projection logic we are currently using
     */
    ensureGeoControl() {
        if (Config.map.debug['debug.screenshot'])
            return;
        if (Config.map.tileMatrix === GoogleTms) {
            if (this.controlGeo != null)
                return;
            this.controlGeo = new maplibre.GeolocateControl({});
            this.map.addControl(this.controlGeo, 'top-left');
        }
        else {
            if (this.controlGeo == null)
                return;
            this.map.removeControl(this.controlGeo);
        }
    }
    componentDidMount() {
        // Force the URL to be read before loading the map
        Config.map.updateFromUrl();
        this.el = document.getElementById('map');
        if (this.el == null)
            throw new Error('Unable to find #map element');
        const cfg = Config.map;
        const tileGrid = getTileGrid(cfg.tileMatrix.identifier);
        const style = tileGrid.getStyle(cfg.layerId, cfg.style);
        const location = locationTransform(cfg.location, cfg.tileMatrix, GoogleTms);
        this.map = new maplibre.Map({
            container: this.el,
            style,
            center: [location.lon, location.lat],
            zoom: location.zoom,
            attributionControl: false,
        });
        this.mapAttr = new MapAttribution(this.map);
        if (Config.map.debug['debug.screenshot'] !== true) {
            const nav = new maplibre.NavigationControl({ visualizePitch: true });
            this.map.addControl(nav, 'top-left');
            if (!Config.map.isDebug)
                this.map.addControl(new maplibre.FullscreenControl({ container: this.el }));
        }
        this.map.on('render', this.onRender);
        onMapLoaded(this.map, () => {
            this._events.push(Config.map.on('location', this.updateLocation), Config.map.on('tileMatrix', this.updateStyle), Config.map.on('layer', this.updateStyle), Config.map.on('bounds', this.updateBounds));
            this.updateStyle();
            // Need to ensure the debug layer has access to the map
            this.forceUpdate();
        });
    }
    componentWillUnmount() {
        if (this.map)
            this.map.remove();
        for (const unbind of this._events)
            unbind();
        this._events = [];
    }
    render() {
        const isLayerSwitcherEnabled = Config.map.tileMatrix === GoogleTms && !Config.map.isDebug;
        return (_jsxs("div", { style: { flex: 1, position: 'relative' }, children: [_jsx("div", { id: "map", style: { width: '100%', height: '100%' } }), Config.map.isDebug ? _jsx(Debug, { map: this.map }) : undefined, isLayerSwitcherEnabled ? _jsx(MapSwitcher, {}) : undefined] }));
    }
    /** Update the window.location with the current location information */
    setLocationUrl() {
        this.updateUrlTimer = null;
        const location = Config.map.getLocation(this.map);
        this.ignoreNextLocationUpdate = true;
        Config.map.setLocation(location);
        const path = WindowUrl.toHash(location);
        window.history.replaceState(null, '', path);
    }
}
//# sourceMappingURL=map.js.map