import { GoogleTms, Nztm2000QuadTms, Nztm2000Tms, Projection } from '@basemaps/geo';
import { Config } from './config.js';
import { WindowUrl } from './url.js';
export class TileGrid {
    constructor(tileMatrix, extraZoomLevels = 0) {
        Object.defineProperty(this, "tileMatrix", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "extraZoomLevels", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this.tileMatrix = tileMatrix;
        this.extraZoomLevels = extraZoomLevels;
    }
    getStyle(cfg) {
        return WindowUrl.toTileUrl({
            urlType: "style" /* MapOptionType.Style */,
            tileMatrix: this.tileMatrix,
            layerId: cfg.layerId,
            style: cfg.style,
            config: cfg.config ?? Config.map.config,
            terrain: cfg.terrain ?? Config.map.terrain,
            labels: cfg.labels ?? Config.map.labels,
        });
    }
}
const Nztm2000TileGrid = new TileGrid(Nztm2000Tms, 2);
const Nztm2000QuadTileGrid = new TileGrid(Nztm2000QuadTms);
const GoogleTileGrid = new TileGrid(GoogleTms);
const Grids = [Nztm2000TileGrid, Nztm2000QuadTileGrid, GoogleTileGrid];
export function getTileGrid(id) {
    for (const g of Grids) {
        if (id === g.tileMatrix.identifier)
            return g;
    }
    return GoogleTileGrid;
}
function isGoogle(tms) {
    return tms.identifier === GoogleTms.identifier;
}
/**
 * Transform the location coordinate between maplibre and another tileMatrix.
 *
 * One of the tileMatrix or targetTileMatrix has to be GoogleTms
 */
export function locationTransform(location, tileMatrix, targetTileMatrix) {
    if (tileMatrix.identifier === targetTileMatrix.identifier)
        return location;
    if (!isGoogle(tileMatrix) && !isGoogle(targetTileMatrix)) {
        throw new Error('Either tileMatrix or targetTileMatrix must be GoogleTms');
    }
    // Transform the source to the the tile it would be rendered on
    const coords = Projection.get(tileMatrix).fromWgs84([location.lon, location.lat]);
    const point = tileMatrix.sourceToPixels(coords[0], coords[1], Math.round(location.zoom));
    const tile = { x: point.x / tileMatrix.tileSize, y: point.y / tileMatrix.tileSize, z: Math.round(location.zoom) };
    // Translate the tile location into the target tile matrix
    const source = targetTileMatrix.tileToSource(tile);
    const lonLat = Projection.get(targetTileMatrix).toWgs84([source.x, source.y]);
    return { lon: Math.round(lonLat[0] * 1e8) / 1e8, lat: Math.round(lonLat[1] * 1e8) / 1e8, zoom: location.zoom };
}
/**
 * Covert map Bounds to tileMatrix BBox
 */
export function mapToBoundingBox(map, zoom, tileMatrix) {
    const bounds = map.getBounds();
    const swLocation = { lon: bounds.getWest(), lat: bounds.getSouth(), zoom: zoom };
    const neLocation = { lon: bounds.getEast(), lat: bounds.getNorth(), zoom: zoom };
    const swCoord = locationTransform(swLocation, GoogleTms, tileMatrix);
    const neCoord = locationTransform(neLocation, GoogleTms, tileMatrix);
    // Truncate all coordiantes to 8 DP (~1mm)
    const bbox = [
        Math.round(swCoord.lon * 1e8) / 1e8,
        Math.round(swCoord.lat * 1e8) / 1e8,
        Math.round(neCoord.lon * 1e8) / 1e8,
        Math.round(neCoord.lat * 1e8) / 1e8,
    ];
    return bbox;
}
/**
 * Project a geojson object into the target tile matrix with use with maplibre
 *
 * *Warning* This will overwrite the existing object
 */
export function projectGeoJson(g, targetTileMatrix) {
    if (g.type === 'FeatureCollection') {
        for (const f of g.features) {
            projectFeature(f, targetTileMatrix);
        }
    }
    else if (g.type === 'Feature') {
        projectFeature(g, targetTileMatrix);
    }
}
function projectFeature(f, targetTileMatrix) {
    if (f.geometry.type === 'Polygon') {
        for (const poly of f.geometry.coordinates) {
            for (const coord of poly) {
                const output = locationTransform({ lat: coord[1], lon: coord[0], zoom: targetTileMatrix.maxZoom }, targetTileMatrix, GoogleTms);
                coord[0] = output.lon;
                coord[1] = output.lat;
            }
        }
    }
    else if (f.geometry.type === 'MultiPolygon') {
        for (const multiPoly of f.geometry.coordinates) {
            for (const poly of multiPoly) {
                for (const coord of poly) {
                    const output = locationTransform({ lat: coord[1], lon: coord[0], zoom: targetTileMatrix.maxZoom }, targetTileMatrix, GoogleTms);
                    coord[0] = output.lon;
                    coord[1] = output.lat;
                }
            }
        }
    }
    else {
        throw new Error(`Geometry feature type: ${f.geometry.type} not supported`);
    }
}
//# sourceMappingURL=tile.matrix.js.map