import { Epsg, EpsgCode, GoogleTms, Nztm2000QuadTms, Nztm2000Tms, TileMatrixSets } from '@basemaps/geo';
import { Emitter } from '@servie/events';
import { DebugDefaults, ConfigDebug } from './config.debug.js';
import { Config } from './config.js';
import { locationTransform } from './tile.matrix.js';
import { ensureBase58, WindowUrl } from './url.js';
/** Default center point if none provided */
const DefaultCenter = {
    [GoogleTms.identifier]: { lat: -41.88999621, lon: 174.04924373, zoom: 5 },
    [Nztm2000Tms.identifier]: { lat: -41.277848, lon: 174.6763921, zoom: 3 },
    [Nztm2000QuadTms.identifier]: { lat: -41.88999621, lon: 174.04924373, zoom: 3 },
};
export class MapConfig extends Emitter {
    constructor() {
        super(...arguments);
        this.style = null;
        this.layerId = 'aerial';
        this.tileMatrix = GoogleTms;
        this.debug = { ...DebugDefaults };
    }
    get layers() {
        if (this._layers == null)
            this._layers = loadAllLayers();
        return this._layers;
    }
    get isDebug() {
        return this.debug.debug;
    }
    get location() {
        if (this._location == null) {
            window.addEventListener('popstate', () => {
                const location = {
                    ...DefaultCenter[this.tileMatrix.identifier],
                    ...WindowUrl.fromHash(window.location.hash),
                };
                this.setLocation(location);
            });
            this.updateFromUrl();
            this._location = { ...DefaultCenter[this.tileMatrix.identifier], ...WindowUrl.fromHash(window.location.hash) };
        }
        return this._location;
    }
    /** Map location in tileMatrix projection */
    get transformedLocation() {
        return this.transformLocation(this.location.lat, this.location.lon, this.location.zoom);
    }
    get isVector() {
        return this.layerId === 'topographic';
    }
    /** Key to reference the combined layer & style  */
    get layerKey() {
        if (this.style == null)
            return this.layerId;
        return `${this.layerId}::${this.style}`;
    }
    /** Key to reference combined layer & style & tile matrix */
    get layerKeyTms() {
        return `${this.layerKey}::${this.tileMatrix.identifier}`;
    }
    updateFromUrl(search = window.location.search) {
        var _a, _b, _c, _d, _e, _f;
        const urlParams = new URLSearchParams(search);
        const style = (_a = urlParams.get('s')) !== null && _a !== void 0 ? _a : urlParams.get('style');
        const config = (_b = urlParams.get('c')) !== null && _b !== void 0 ? _b : urlParams.get('config');
        const layerId = (_c = urlParams.get('i')) !== null && _c !== void 0 ? _c : 'aerial';
        const projectionParam = ((_e = (_d = urlParams.get('p')) !== null && _d !== void 0 ? _d : urlParams.get('tileMatrix')) !== null && _e !== void 0 ? _e : GoogleTms.identifier).toLowerCase();
        let tileMatrix = TileMatrixSets.All.find((f) => f.identifier.toLowerCase() === projectionParam);
        if (tileMatrix == null)
            tileMatrix = TileMatrixSets.get((_f = Epsg.parse(projectionParam)) !== null && _f !== void 0 ? _f : Epsg.Google);
        if (tileMatrix.identifier === Nztm2000Tms.identifier)
            tileMatrix = Nztm2000QuadTms;
        const debugChanged = ConfigDebug.fromUrl(this.debug, urlParams);
        if (debugChanged)
            this.emit('change');
        const previousUrl = MapConfig.toUrl(this);
        this.config = config;
        this.style = style !== null && style !== void 0 ? style : null;
        this.layerId = layerId.startsWith('im_') ? layerId.slice(3) : layerId;
        this.tileMatrix = tileMatrix;
        if (this.layerId === 'topographic' && this.style == null)
            this.style = 'topographic';
        this.emit('tileMatrix', this.tileMatrix);
        this.emit('layer', this.layerId, this.style);
        if (previousUrl !== MapConfig.toUrl(this))
            this.emit('change');
    }
    static toUrl(opts) {
        const urlParams = new URLSearchParams();
        if (opts.style)
            urlParams.append('s', opts.style);
        if (opts.config)
            urlParams.append('config', ensureBase58(opts.config));
        if (opts.layerId !== 'aerial')
            urlParams.append('i', opts.layerId);
        if (opts.tileMatrix.identifier !== GoogleTms.identifier)
            urlParams.append('p', opts.tileMatrix.identifier);
        ConfigDebug.toUrl(opts.debug, urlParams);
        return urlParams.toString();
    }
    toTileUrl(urlType, tileMatrix = this.tileMatrix, layerId = this.layerId, style = this.style, config = this.config) {
        return WindowUrl.toTileUrl(urlType, tileMatrix, layerId, style, config);
    }
    getLocation(map) {
        var _a;
        const center = map.getCenter();
        if (center == null)
            throw new Error('Invalid Map location');
        const zoom = Math.floor(((_a = map.getZoom()) !== null && _a !== void 0 ? _a : 0) * 10e3) / 10e3;
        return Config.map.transformLocation(center.lat, center.lng, zoom);
    }
    transformLocation(lat, lon, zoom) {
        return locationTransform({ lat, lon, zoom }, GoogleTms, this.tileMatrix);
    }
    setLocation(l) {
        if (l.lat === this.location.lat && l.lon === this.location.lon && l.zoom === this.location.zoom)
            return;
        this.location.lat = l.lat;
        this.location.lon = l.lon;
        this.location.zoom = l.zoom;
        this.emit('location', this.location);
        this.emit('change');
    }
    setTileMatrix(tms) {
        if (this.tileMatrix.identifier === tms.identifier)
            return;
        this.emit('tileMatrix', this.tileMatrix);
        this.emit('change');
    }
    setLayerId(layer, style) {
        if (this.layerId === layer && this.style === style)
            return;
        this.layerId = layer;
        this.style = style !== null && style !== void 0 ? style : null;
        this.emit('layer', this.layerId, this.style);
        this.emit('change');
    }
    setDebug(key, value = DebugDefaults[key]) {
        if (this.debug[key] === value)
            return;
        this.debug[key] = value;
        this.emit('change');
    }
}
async function loadAllLayers() {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j;
    const output = new Map();
    const res = await fetch(WindowUrl.toBaseWmts());
    if (!res.ok)
        return output;
    const dom = new DOMParser();
    const xmlDoc = dom.parseFromString(await res.text(), 'text/xml');
    const layers = xmlDoc.getElementsByTagName('Layer');
    const allLayers = [];
    for (let i = 0; i < layers.length; i++) {
        const layer = layers.item(i);
        if (layer == null)
            continue;
        const title = (_a = layer.getElementsByTagName('ows:Title').item(0)) === null || _a === void 0 ? void 0 : _a.textContent;
        const id = (_b = layer.getElementsByTagName('ows:Identifier').item(0)) === null || _b === void 0 ? void 0 : _b.textContent;
        if (title == null || id == null)
            continue;
        if (title === 'aerial')
            continue;
        const category = (_c = layer.getElementsByTagName('ows:Keyword').item(0)) === null || _c === void 0 ? void 0 : _c.textContent;
        const boundEl = layer.getElementsByTagName('ows:WGS84BoundingBox').item(0);
        const upperLeft = (_e = (_d = boundEl === null || boundEl === void 0 ? void 0 : boundEl.getElementsByTagName('ows:UpperCorner').item(0)) === null || _d === void 0 ? void 0 : _d.textContent) === null || _e === void 0 ? void 0 : _e.split(' ').map(Number);
        const lowerRight = (_g = (_f = boundEl === null || boundEl === void 0 ? void 0 : boundEl.getElementsByTagName('ows:LowerCorner').item(0)) === null || _f === void 0 ? void 0 : _f.textContent) === null || _g === void 0 ? void 0 : _g.split(' ').map(Number);
        const tmsTags = layer.getElementsByTagName('TileMatrixSet');
        const projections = new Set();
        for (let j = 0; j < tmsTags.length; j++) {
            const epsg = tmsIdToEpsg((_j = (_h = tmsTags.item(j)) === null || _h === void 0 ? void 0 : _h.textContent) !== null && _j !== void 0 ? _j : '');
            if (epsg == null)
                continue;
            projections.add(epsg.code);
        }
        if (upperLeft == null || lowerRight == null || upperLeft.length !== 2)
            continue;
        allLayers.push({
            id,
            name: title.replace('aerial ', ''),
            upperLeft,
            lowerRight,
            projections,
            category,
        });
    }
    allLayers.sort((a, b) => a.name.localeCompare(b.name));
    addDefaultLayers(output);
    for (const l of allLayers)
        output.set(l.id, l);
    return output;
}
function addDefaultLayers(output) {
    output.set('aerial', {
        id: 'aerial',
        name: 'Aerial Imagery',
        projections: new Set([EpsgCode.Nztm2000, EpsgCode.Google]),
        category: 'Basemaps',
    });
    output.set('topographic::topographic', {
        id: 'topographic::topographic',
        name: 'Topographic',
        projections: new Set([EpsgCode.Google]),
        category: 'Basemaps',
    });
}
/** Lookup a projection from either "EPSG:3857" or "WebMercatorQuad" */
function tmsIdToEpsg(id) {
    if (id.toLowerCase().startsWith('epsg'))
        return Epsg.parse(id);
    const tms = TileMatrixSets.find(id);
    if (tms == null)
        return null;
    return tms.projection;
}
//# sourceMappingURL=config.map.js.map