/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { assert } from "chai";
import { Helmert2DWithZOffset, } from "@itwin/core-common";
import { IModelNative } from "../../internal/NativePlatform";
import { Geometry, Point3d, Range2d } from "@itwin/core-geometry";
import { GeoCoordConfig } from "../../GeoCoordConfig";
import { getAvailableCoordinateReferenceSystems, getAvailableCRSUnits } from "../../GeographicCRSServices";
// spell-checker: disable
describe("GeoServices", () => {
    before(() => {
        GeoCoordConfig.loadDefaultDatabases();
    });
    const completionTest = async (incompleteGCS, completeCRS) => {
        const requestProps = { format: "JSON", geographicCRSDef: JSON.stringify(incompleteGCS) };
        const response = IModelNative.platform.GeoServices.getGeographicCRSInterpretation(requestProps);
        assert.isTrue(response.status === 0);
        assert.isTrue(response.geographicCRS !== undefined);
        if (response.geographicCRS !== undefined) {
            assert.isTrue(response.geographicCRS.horizontalCRS !== undefined && completeCRS.horizontalCRS !== undefined);
            assert.isTrue(response.geographicCRS.horizontalCRS.id === completeCRS.horizontalCRS.id);
            assert.isTrue(response.geographicCRS.horizontalCRS.projection !== undefined && completeCRS.horizontalCRS.projection !== undefined);
            assert.isTrue(response.geographicCRS.horizontalCRS.projection.method === completeCRS.horizontalCRS.projection.method);
            if (completeCRS.horizontalCRS.projection.falseEasting !== undefined) {
                assert.isTrue(response.geographicCRS.horizontalCRS.projection.falseEasting !== undefined);
                assert.isTrue(Math.abs(response.geographicCRS.horizontalCRS.projection.falseEasting - completeCRS.horizontalCRS.projection.falseEasting) < Geometry.smallMetricDistance);
            }
            if (completeCRS.horizontalCRS.projection.falseNorthing !== undefined) {
                assert.isTrue(response.geographicCRS.horizontalCRS.projection.falseNorthing !== undefined);
                assert.isTrue(Math.abs(response.geographicCRS.horizontalCRS.projection.falseNorthing - completeCRS.horizontalCRS.projection.falseNorthing) < Geometry.smallMetricDistance);
            }
            assert.isTrue(response.geographicCRS.horizontalCRS.datum !== undefined && completeCRS.horizontalCRS.datum !== undefined);
            assert.isTrue(response.geographicCRS.horizontalCRS.datum.id === completeCRS.horizontalCRS.datum.id);
            assert.isTrue(response.geographicCRS.horizontalCRS.datum.ellipsoid !== undefined && completeCRS.horizontalCRS.datum.ellipsoid !== undefined);
            assert.isTrue(response.geographicCRS.horizontalCRS.datum.ellipsoid.id === completeCRS.horizontalCRS.datum.ellipsoid.id);
            if (response.geographicCRS.additionalTransform !== undefined) {
                assert.isTrue(completeCRS.additionalTransform !== undefined);
                assert.isTrue(response.geographicCRS.additionalTransform.helmert2DWithZOffset !== undefined);
                assert.isTrue(completeCRS.additionalTransform.helmert2DWithZOffset !== undefined);
                assert.isTrue(Math.abs(response.geographicCRS.additionalTransform.helmert2DWithZOffset.rotDeg - completeCRS.additionalTransform.helmert2DWithZOffset.rotDeg) < Geometry.smallAngleDegrees);
                assert.isTrue(Math.abs(response.geographicCRS.additionalTransform.helmert2DWithZOffset.translationX - completeCRS.additionalTransform.helmert2DWithZOffset.translationX) < Geometry.smallMetricDistance);
                assert.isTrue(Math.abs(response.geographicCRS.additionalTransform.helmert2DWithZOffset.translationY - completeCRS.additionalTransform.helmert2DWithZOffset.translationY) < Geometry.smallMetricDistance);
                assert.isTrue(Math.abs(response.geographicCRS.additionalTransform.helmert2DWithZOffset.translationZ - completeCRS.additionalTransform.helmert2DWithZOffset.translationZ) < Geometry.smallMetricDistance);
                assert.isTrue(Math.abs(response.geographicCRS.additionalTransform.helmert2DWithZOffset.scale - completeCRS.additionalTransform.helmert2DWithZOffset.scale) < Geometry.smallFraction);
            }
            assert.isTrue(response.geographicCRS.verticalCRS !== undefined && completeCRS.verticalCRS !== undefined);
            assert.isTrue(response.geographicCRS.verticalCRS.id === completeCRS.verticalCRS.id);
        }
    };
    describe("Interpret to completion an incomplete GeographicCRS", async () => {
        it("should be able to interpret to completion britishNationalGridOld", async () => {
            const britishNationalGridOld = {
                horizontalCRS: {
                    datum: {
                        deprecated: true,
                        description: "OSGB36 - Use OSGB-7P-2. Consider OSGB/OSTN15 instead",
                        ellipsoid: {
                            description: "Airy 1830",
                            equatorialRadius: 6377563.396,
                            id: "EPSG:7001",
                            polarRadius: 6356256.909237,
                            source: "EPSG, Version 6 [EPSG]",
                        },
                        ellipsoidId: "EPSG:7001",
                        id: "EPSG:6277",
                        source: "EPSG V6.12 operation EPSG:1314 [EPSG]",
                        transforms: [
                            {
                                method: "PositionalVector",
                                positionalVector: {
                                    delta: {
                                        x: 446.448,
                                        y: -125.157,
                                        z: 542.06,
                                    },
                                    rotation: {
                                        x: 0.15,
                                        y: 0.247,
                                        z: 0.842,
                                    },
                                    scalePPM: -20.489,
                                },
                                sourceEllipsoid: {
                                    equatorialRadius: 6377563.396,
                                    id: "EPSG:7001",
                                    polarRadius: 6356256.909237,
                                },
                                targetEllipsoid: {
                                    equatorialRadius: 6378137,
                                    id: "WGS84",
                                    polarRadius: 6356752.3142,
                                },
                            }
                        ],
                    },
                    datumId: "EPSG:6277",
                    deprecated: true,
                    description: "Use other variant - OSGB British National Grid",
                    extent: {
                        northEast: {
                            latitude: 60.84,
                            longitude: 1.78,
                        },
                        southWest: {
                            latitude: 49.96,
                            longitude: -7.56,
                        },
                    },
                    id: "EPSG:27700",
                    projection: {
                        centralMeridian: -2,
                        falseEasting: 400000,
                        falseNorthing: -100000,
                        latitudeOfOrigin: 49,
                        method: "TransverseMercator",
                        scaleFactor: 0.999601272737422,
                    },
                    source: "EPSG",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "ELLIPSOID",
                },
            };
            await completionTest({ horizontalCRS: { id: "EPSG:27700" }, verticalCRS: { id: "ELLIPSOID" } }, britishNationalGridOld);
        });
        it("should be able to interpret to completion EWRGCS", async () => {
            const EWRGCS = {
                horizontalCRS: {
                    id: "EPSG:27700",
                    description: "OSGB 1936 / British National Grid",
                    source: "EPSG V6 [Large and medium scale topographic mapping and engin]",
                    datumId: "EPSG:6277",
                    datum: {
                        id: "EPSG:6277",
                        description: "OSGB36 - Use OSGB-7P-2. Consider OSGB/OSTN15 instead",
                        deprecated: true,
                        source: "EPSG V6.12 operation EPSG:1314 [EPSG]",
                        ellipsoidId: "EPSG:7001",
                        ellipsoid: {
                            equatorialRadius: 6377563.396,
                            polarRadius: 6356256.909237,
                            id: "EPSG:7001",
                            description: "Airy 1830",
                            source: "EPSG, Version 6 [EPSG]",
                        },
                        transforms: [
                            {
                                method: "PositionalVector",
                                sourceEllipsoid: {
                                    equatorialRadius: 6377563.396,
                                    polarRadius: 6356256.909237,
                                    id: "EPSG:7001",
                                },
                                targetEllipsoid: {
                                    equatorialRadius: 6378137,
                                    polarRadius: 6356752.3142,
                                    id: "WGS84",
                                },
                                positionalVector: {
                                    delta: {
                                        x: 446.448,
                                        y: -125.157,
                                        z: 542.06,
                                    },
                                    rotation: {
                                        x: 0.15,
                                        y: 0.247,
                                        z: 0.842,
                                    },
                                    scalePPM: -20.489,
                                },
                            }
                        ],
                    },
                    unit: "Meter",
                    projection: {
                        method: "TransverseMercator",
                        falseEasting: 400000,
                        falseNorthing: -100000,
                        centralMeridian: -2,
                        latitudeOfOrigin: 49,
                        scaleFactor: 0.999601272737422,
                    },
                    extent: {
                        southWest: {
                            latitude: 49.96,
                            longitude: -7.56,
                        },
                        northEast: {
                            latitude: 60.84,
                            longitude: 1.78,
                        },
                    },
                },
                verticalCRS: {
                    id: "ELLIPSOID",
                },
                additionalTransform: {
                    helmert2DWithZOffset: {
                        translationX: 284597.3343,
                        translationY: 79859.4651,
                        translationZ: 0,
                        rotDeg: 0.5263624458992088,
                        scale: 0.9996703340508721,
                    },
                },
            };
            await completionTest({ horizontalCRS: { id: "EPSG:27700" }, verticalCRS: { id: "ELLIPSOID" }, additionalTransform: { helmert2DWithZOffset: { translationX: 284597.3343, translationY: 79859.4651, translationZ: 0, rotDeg: 0.5263624458992088, scale: 0.9996703340508721 } } }, EWRGCS);
        });
        it("should be able to interpret to completion UTM27Z10", async () => {
            const UTM27Z10 = {
                horizontalCRS: {
                    datum: {
                        description: "North American Datum of 1927 (US48, AK, HI, and Canada)",
                        ellipsoid: {
                            description: "Clarke 1866, Benoit Ratio",
                            epsg: 7008,
                            equatorialRadius: 6378206.4,
                            id: "CLRK66",
                            polarRadius: 6356583.8,
                            source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        },
                        ellipsoidId: "CLRK66",
                        epsg: 6267,
                        id: "NAD27",
                        source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        transforms: [
                            {
                                gridFile: {
                                    files: [
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/conus.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/alaska.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/prvi.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/hawaii.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/stgeorge.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/stlrnc.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/stpaul.l?s",
                                            format: "NADCON",
                                        }
                                    ],
                                },
                                method: "GridFiles",
                                sourceEllipsoid: {
                                    equatorialRadius: 6378206.4,
                                    id: "CLRK66",
                                    polarRadius: 6356583.8,
                                },
                                targetEllipsoid: {
                                    equatorialRadius: 6378137,
                                    id: "GRS1980",
                                    polarRadius: 6356752.314140348,
                                },
                            }
                        ],
                    },
                    datumId: "NAD27",
                    description: "UTM with NAD27 datum, Zone 10, Meter; Central Meridian 123d W",
                    epsg: 26710,
                    extent: {
                        northEast: {
                            latitude: 84,
                            longitude: -119.5,
                        },
                        southWest: {
                            latitude: -1,
                            longitude: -126.5,
                        },
                    },
                    id: "UTM27-10",
                    projection: {
                        hemisphere: "North",
                        method: "UniversalTransverseMercator",
                        zoneNumber: 10,
                    },
                    source: "Snyder, J.P, 1987, Map Projections - A Working Manual",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "NGVD29",
                },
            };
            await completionTest({ horizontalCRS: { id: "UTM27-10" }, verticalCRS: { id: "NGVD29" } }, UTM27Z10);
        });
        it("should be able to interpret to completion UTM27Z10B", async () => {
            const UTM27Z10B = {
                horizontalCRS: {
                    datum: {
                        description: "North American Datum of 1927 (US48, AK, HI, and Canada)",
                        ellipsoid: {
                            description: "Clarke 1866, Benoit Ratio",
                            epsg: 7008,
                            equatorialRadius: 6378206.4,
                            id: "CLRK66",
                            polarRadius: 6356583.8,
                            source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        },
                        ellipsoidId: "CLRK66",
                        epsg: 6267,
                        id: "NAD27",
                        source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        transforms: [
                            {
                                gridFile: {
                                    files: [
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/conus.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/alaska.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/prvi.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/hawaii.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/stgeorge.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/stlrnc.l?s",
                                            format: "NADCON",
                                        },
                                        {
                                            direction: "Direct",
                                            fileName: "./Usa/Nadcon/stpaul.l?s",
                                            format: "NADCON",
                                        },
                                    ],
                                },
                                method: "GridFiles",
                                sourceEllipsoid: {
                                    equatorialRadius: 6378206.4,
                                    id: "CLRK66",
                                    polarRadius: 6356583.8,
                                },
                                targetEllipsoid: {
                                    equatorialRadius: 6378137,
                                    id: "GRS1980",
                                    polarRadius: 6356752.314140348,
                                },
                            },
                        ],
                    },
                    datumId: "NAD27",
                    description: "NAD27 / UTM zone 10N",
                    epsg: 26710,
                    extent: {
                        northEast: {
                            latitude: 77,
                            longitude: -120,
                        },
                        southWest: {
                            latitude: 34.4,
                            longitude: -126,
                        },
                    },
                    id: "EPSG:26710",
                    projection: {
                        centralMeridian: -123,
                        falseEasting: 500000,
                        falseNorthing: 0,
                        latitudeOfOrigin: 0,
                        method: "TransverseMercator",
                        scaleFactor: 0.9996,
                    },
                    source: "EPSG V6 [Large and medium scale topographic mapping and engin]",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "NGVD29",
                },
            };
            await completionTest({ horizontalCRS: { epsg: 26710 }, verticalCRS: { id: "NGVD29" } }, UTM27Z10B);
        });
    });
    describe("Interpretation of WKT GeographicCRS", async () => {
        const interpretWKTTest = async (testWKT, completeCRS) => {
            const requestProps = { format: "WKT", geographicCRSDef: testWKT };
            const response = IModelNative.platform.GeoServices.getGeographicCRSInterpretation(requestProps);
            assert.isTrue(response.status === 0);
            assert.isTrue(response.geographicCRS !== undefined);
            if (response.geographicCRS !== undefined) {
                assert.isTrue(response.geographicCRS.horizontalCRS !== undefined && completeCRS.horizontalCRS !== undefined);
                assert.isTrue(response.geographicCRS.horizontalCRS.id === completeCRS.horizontalCRS.id);
                assert.isTrue(response.geographicCRS.horizontalCRS.projection !== undefined && completeCRS.horizontalCRS.projection !== undefined);
                assert.isTrue(response.geographicCRS.horizontalCRS.projection.method === completeCRS.horizontalCRS.projection.method);
                if (completeCRS.horizontalCRS.projection.falseEasting !== undefined) {
                    assert.isTrue(response.geographicCRS.horizontalCRS.projection.falseEasting !== undefined);
                    assert.isTrue(Math.abs(response.geographicCRS.horizontalCRS.projection.falseEasting - completeCRS.horizontalCRS.projection.falseEasting) < Geometry.smallMetricDistance);
                }
                if (completeCRS.horizontalCRS.projection.falseNorthing !== undefined) {
                    assert.isTrue(response.geographicCRS.horizontalCRS.projection.falseNorthing !== undefined);
                    assert.isTrue(Math.abs(response.geographicCRS.horizontalCRS.projection.falseNorthing - completeCRS.horizontalCRS.projection.falseNorthing) < Geometry.smallMetricDistance);
                }
                assert.isTrue(response.geographicCRS.horizontalCRS.datum !== undefined && completeCRS.horizontalCRS.datum !== undefined);
                assert.isTrue(response.geographicCRS.horizontalCRS.datum.id === completeCRS.horizontalCRS.datum.id);
                assert.isTrue(response.geographicCRS.horizontalCRS.datum.ellipsoid !== undefined && completeCRS.horizontalCRS.datum.ellipsoid !== undefined);
                assert.isTrue(response.geographicCRS.horizontalCRS.datum.ellipsoid.id === completeCRS.horizontalCRS.datum.ellipsoid.id);
                assert.isTrue(response.geographicCRS.verticalCRS !== undefined && completeCRS.verticalCRS !== undefined);
                assert.isTrue(response.geographicCRS.verticalCRS.id === completeCRS.verticalCRS.id);
                // WKTs cannot define an additional transform
                assert.isTrue(response.geographicCRS.additionalTransform === undefined);
            }
        };
        it("should be able to interpret airportGrid2007 WKT", async () => {
            const airportGrid2007 = {
                horizontalCRS: {
                    datum: {
                        description: "Heathrow T5 Datum",
                        ellipsoid: {
                            description: "Airy, 1830",
                            epsg: 7001,
                            equatorialRadius: 6377563.396,
                            id: "AIRY30",
                            polarRadius: 6356256.909,
                            source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        },
                        ellipsoidId: "AIRY30",
                        id: "HeathrowT5",
                        source: "Bentley Client",
                        transforms: [
                            {
                                method: "PositionalVector",
                                positionalVector: {
                                    delta: {
                                        x: 358.398212181898,
                                        y: -213.702844870731,
                                        z: 495.318319769716,
                                    },
                                    rotation: {
                                        x: 668.806139320047,
                                        y: -4.72664217602752,
                                        z: 719.671097181396,
                                    },
                                    scalePPM: -6.26386076385543,
                                },
                                sourceEllipsoid: {
                                    equatorialRadius: 6377563.396,
                                    id: "AIRY30",
                                    polarRadius: 6356256.909,
                                },
                                targetEllipsoid: {
                                    equatorialRadius: 6378137,
                                    id: "WGS84",
                                    polarRadius: 6356752.3142,
                                },
                            },
                        ],
                    },
                    datumId: "HeathrowT5",
                    description: "AirportGrid2007",
                    id: "AirportGrid2007",
                    projection: {
                        centralMeridian: -0.41832591666666674,
                        falseEasting: 7334.81,
                        falseNorthing: 5637.423,
                        latitudeOfOrigin: 51.47011065555556,
                        method: "TransverseMercator",
                        scaleFactor: 0.999995,
                    },
                    source: "WKT",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "ELLIPSOID",
                },
            };
            await interpretWKTTest('PROJCS["AirportGrid2007", GEOGCS["HeathrowT5.LL",DATUM["Heathrow T5", SPHEROID["AIRY30",6377563.396,299.32496127],358.398,-213.7028,495.3183,-668.80613932004700,4.72664217602752,-719.67109718139600,-6.26386076385543],PRIMEM["Greenwich",0],UNIT["Decimal Degree",0.017453292519943295]],PROJECTION["Transverse Mercator"],PARAMETER["latitude_of_origin",51.470110655555558],PARAMETER["central_meridian",-0.41832591666666669],PARAMETER["scale_factor",0.999995],PARAMETER["false_easting",7334.810],PARAMETER["false_northing",5637.423],UNIT["Meter",1.00000000000000]]', airportGrid2007);
        });
        it("should be able to interpret denmarkED50 WKT", async () => {
            const denmarkED50 = {
                horizontalCRS: {
                    datum: {
                        description: "European 1950, Denmark, for System 34",
                        ellipsoid: {
                            description: "Hayford, 1924 (aka 1909); same as International 1924",
                            epsg: 7022,
                            equatorialRadius: 6378388,
                            id: "HAYFORD",
                            polarRadius: 6356911.9461279465,
                            source: "Snyder, J.P., 1987, Map Projections - A Working Manual",
                        },
                        ellipsoidId: "HAYFORD",
                        id: "ED50-DK34",
                        source: "KMSTrans, by Kort-og Matrikelstyrelsen (Nov 1999)",
                        transforms: [
                            {
                                method: "PositionalVector",
                                positionalVector: {
                                    delta: {
                                        x: -81.0703,
                                        y: -89.3603,
                                        z: -115.7526,
                                    },
                                    rotation: {
                                        x: 0.48488,
                                        y: 0.02436,
                                        z: 0.41321,
                                    },
                                    scalePPM: -0.540645,
                                },
                                sourceEllipsoid: {
                                    equatorialRadius: 6378388,
                                    id: "HAYFORD",
                                    polarRadius: 6356911.9461279465,
                                },
                                targetEllipsoid: {
                                    equatorialRadius: 6378137,
                                    id: "WGS84",
                                    polarRadius: 6356752.3142,
                                },
                            },
                        ],
                    },
                    datumId: "ED50-DK34",
                    description: "DummyName",
                    extent: {
                        northEast: {
                            latitude: 90,
                            longitude: 180,
                        },
                        southWest: {
                            latitude: -90,
                            longitude: -180,
                        },
                    },
                    id: "DummyName",
                    projection: {
                        method: "None",
                    },
                    source: "Extracted from WKT string; description field carries WKT name.",
                    unit: "Degree",
                },
                verticalCRS: {
                    id: "ELLIPSOID",
                },
            };
            await interpretWKTTest('GEOGCS[ "DummyName", DATUM ["European 1950 (Denmark)", SPHEROID ["International 1924", 6378388, 297],-81.0703, -89.3603, -115.7526, .48488, .02436, .41321, -.540645], PRIMEM [ "Greenwich", 0.000000 ], UNIT ["Decimal Degree", 0.01745329251994330]]', denmarkED50);
        });
        it("should be able to interpret californiaStateZone2 WKT", async () => {
            const californiaStateZone2 = {
                horizontalCRS: {
                    datum: {
                        description: "North American Datum of 1983",
                        ellipsoid: {
                            description: "Geodetic Reference System of 1980",
                            epsg: 7019,
                            equatorialRadius: 6378137,
                            id: "GRS1980",
                            polarRadius: 6356752.314140348,
                            source: "Stem, L.E., Jan 1989, State Plane Coordinate System of 1983",
                        },
                        ellipsoidId: "GRS1980",
                        epsg: 6269,
                        id: "NAD83",
                        source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        transforms: [
                            {
                                method: "None",
                            },
                        ],
                    },
                    datumId: "NAD83",
                    description: "NAD_1983_StatePlane_California_II_FIPS_0402_Feet",
                    id: "NAD_1983_StatePlane_Cal",
                    projection: {
                        falseEasting: 6561666.666666666,
                        falseNorthing: 1640416.666666667,
                        latitudeOfOrigin: 37.66666666666666,
                        longitudeOfOrigin: -122,
                        method: "LambertConformalConicTwoParallels",
                        standardParallel1: 38.33333333333334,
                        standardParallel2: 39.83333333333334,
                    },
                    source: "WKT",
                    unit: "USSurveyFoot",
                },
                verticalCRS: {
                    id: "NAVD88",
                },
            };
            await interpretWKTTest('PROJCS["NAD_1983_StatePlane_California_II_FIPS_0402_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",6561666.666666666],PARAMETER["False_Northing",1640416.666666667],PARAMETER["Central_Meridian",-122],PARAMETER["Standard_Parallel_1",38.33333333333334],PARAMETER["Standard_Parallel_2",39.83333333333334],PARAMETER["Latitude_Of_Origin",37.66666666666666],UNIT["Foot_US",0.30480060960121924]]', californiaStateZone2);
        });
        it("should be able to interpret utm84Zone34S WKT", async () => {
            const utm84Zone34S = {
                horizontalCRS: {
                    datum: {
                        description: "World Geodetic System of 1984",
                        ellipsoid: {
                            description: "World Geodetic System of 1984, GEM 10C",
                            epsg: 7030,
                            equatorialRadius: 6378137,
                            id: "WGS84",
                            polarRadius: 6356752.3142,
                            source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        },
                        ellipsoidId: "WGS84",
                        epsg: 6326,
                        id: "WGS84",
                        source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        transforms: [
                            {
                                method: "None",
                            },
                        ],
                    },
                    datumId: "WGS84",
                    description: "WGS 84 / UTM zone 34S",
                    id: "WGS 84 / UTM zone 34S",
                    projection: {
                        centralMeridian: 20.999999999999982,
                        falseEasting: 500000,
                        falseNorthing: 10000000,
                        latitudeOfOrigin: 0,
                        method: "TransverseMercator",
                        scaleFactor: 0.9996,
                    },
                    source: "WKT",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "ELLIPSOID",
                },
            };
            await interpretWKTTest('PROJCS["WGS 84 / UTM zone 34S", GEOGCS [ "WGS 84", DATUM ["World Geodetic System 1984 (EPSG ID 6326)", SPHEROID ["WGS 84 (EPSG ID 7030)", 6378137, 298.257223563]], PRIMEM [ "Greenwich", 0.000000 ], UNIT ["Decimal Degree", 0.01745329251994328]], PROJECTION ["UTM zone 34S (EPSG OP 16134)"], PARAMETER ["Latitude_Of_Origin", 0], PARAMETER ["Central_Meridian", 21], PARAMETER ["Scale_Factor", .9996], PARAMETER ["False_Easting", 500000], PARAMETER ["False_Northing", 10000000], UNIT ["Meter", 1]]', utm84Zone34S);
        });
        it("should be able to interpret utm84Zone32NGeoid WKT", async () => {
            const utm84Zone32NGeoid = {
                horizontalCRS: {
                    datum: {
                        description: "World Geodetic System of 1984",
                        ellipsoid: {
                            description: "World Geodetic System of 1984, GEM 10C",
                            epsg: 7030,
                            equatorialRadius: 6378137,
                            id: "WGS84",
                            polarRadius: 6356752.3142,
                            source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        },
                        ellipsoidId: "WGS84",
                        epsg: 6326,
                        id: "WGS84",
                        source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        transforms: [
                            {
                                method: "None",
                            },
                        ],
                    },
                    datumId: "WGS84",
                    description: "WGS 84 / UTM zone32N",
                    id: "WGS 84 / UTM zone32N",
                    projection: {
                        centralMeridian: 9,
                        falseEasting: 500000,
                        falseNorthing: 0,
                        latitudeOfOrigin: 0,
                        method: "TransverseMercator",
                        scaleFactor: 0.9996,
                    },
                    source: "WKT",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "GEOID",
                },
            };
            await interpretWKTTest('COMPD_CS["WGS 84 / UTM zone 32N + EGM96 geoid height",PROJCS["WGS 84 / UTM zone32N",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",9],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","32632"]],VERT_CS["EGM96 geoid height",VERT_DATUM["EGM96 geoid",2005,EXTENSION["PROJ4_GRIDS","egm96_15.gtx"],AUTHORITY["EPSG","5171"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Up",UP],AUTHORITY["EPSG","5773"]]]', utm84Zone32NGeoid);
        });
        it("should be able to interpret utm84Zone18NGeoid WKT", async () => {
            const utm84Zone18NGeoid = {
                horizontalCRS: {
                    datum: {
                        description: "World Geodetic System of 1984",
                        ellipsoid: {
                            description: "World Geodetic System of 1984, GEM 10C",
                            epsg: 7030,
                            equatorialRadius: 6378137,
                            id: "WGS84",
                            polarRadius: 6356752.3142,
                            source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        },
                        ellipsoidId: "WGS84",
                        epsg: 6326,
                        id: "WGS84",
                        source: "US Defense Mapping Agency, TR-8350.2-B, December 1987",
                        transforms: [
                            {
                                method: "None",
                            },
                        ],
                    },
                    datumId: "WGS84",
                    description: "UTM84-18N",
                    id: "UTM84-18N",
                    projection: {
                        hemisphere: "North",
                        method: "UniversalTransverseMercator",
                        zoneNumber: 18,
                    },
                    source: "WKT",
                    unit: "Meter",
                },
                verticalCRS: {
                    id: "GEOID",
                },
            };
            await interpretWKTTest('COMPD_CS["UTM84-18N",PROJCS["UTM84-18N",GEOGCS["LL84",DATUM["WGS84",SPHEROID["WGS84",6378137.000,298.25722293]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Universal Transverse Mercator System"],PARAMETER["UTM Zone Number (1 - 60)",18.0],PARAMETER["Hemisphere, North or South",1.0],UNIT["Meter",1.00000000000000]],VERT_CS["Geoid Height",VERT_DATUM["EGM96 geoid",2005],UNIT["METER",1.000000]]]', utm84Zone18NGeoid);
        });
    });
    describe("Verify list of CRS", async () => {
        const validationRange = 50;
        const validationRangeSmall = 10;
        const validateCRSList = async (options) => {
            const { expectedCount, allowedRange, extent, includeWorld } = options;
            const listOfCRS = await getAvailableCoordinateReferenceSystems({ extent, includeWorld });
            // Check fields of returned coordinate reference systems
            const extentRange = Range2d.fromJSON(extent);
            for (const crs of listOfCRS) {
                // Validate extent
                if (extent !== undefined) {
                    const crsExtentRange = Range2d.fromJSON(crs.crsExtent);
                    const intersects = extentRange.intersectsRange(crsExtentRange);
                    assert.isTrue(intersects);
                }
                // These fields should always be present
                assert.isTrue(crs.name !== undefined);
                assert.isTrue(crs.description !== undefined);
                assert.isTrue(crs.deprecated === true || crs.deprecated === false);
            }
            assert.isTrue(listOfCRS.length > expectedCount - allowedRange && listOfCRS.length < expectedCount + allowedRange);
        };
        const validateExtent = (expectedExtent, crsExtent) => {
            const crsExtentRange = Range2d.fromJSON(crsExtent);
            assert.equal(crsExtentRange.low.x, expectedExtent.low.x);
            assert.equal(crsExtentRange.low.y, expectedExtent.low.y);
            assert.equal(crsExtentRange.high.x, expectedExtent.high.x);
            assert.equal(crsExtentRange.high.y, expectedExtent.high.y);
        };
        it("should get all CRS", async () => {
            await validateCRSList({ expectedCount: 12_332, allowedRange: validationRange, includeWorld: true });
        });
        it("should get all CRS, excluding world crs", async () => {
            await validateCRSList({ expectedCount: 11_975, allowedRange: validationRange });
        });
        it("should return CRS that are in the specified range (1)", async () => {
            const extent = { low: { x: 60.1, y: 61.2 }, high: { x: 62.3, y: 63.4 } };
            await validateCRSList({ expectedCount: 82, allowedRange: validationRangeSmall, extent });
            await validateCRSList({ expectedCount: 439, allowedRange: validationRangeSmall, extent, includeWorld: true });
        });
        it("should return CRS that are in the specified range (2)", async () => {
            const extent = { low: { x: 0, y: 2 }, high: { x: 1, y: 3 } };
            await validateCRSList({ expectedCount: 67, allowedRange: validationRangeSmall, extent });
            await validateCRSList({ expectedCount: 424, allowedRange: validationRangeSmall, extent, includeWorld: true });
        });
        it("should return CRS that are in the specified range (3)", async () => {
            const extent = { low: { x: 0.3, y: 2.4 }, high: { x: 1.6, y: 3.77 } };
            await validateCRSList({ expectedCount: 62, allowedRange: validationRangeSmall, extent });
            await validateCRSList({ expectedCount: 419, allowedRange: validationRangeSmall, extent, includeWorld: true });
        });
        it("should retrieve the whole list of CRS and validate the properties for a few selected CRS.", async () => {
            const listOfCRS = await getAvailableCoordinateReferenceSystems({ includeWorld: true });
            let nbFound = 0;
            for (const crs of listOfCRS) {
                switch (crs.name) {
                    case "3TM111-83":
                        nbFound++;
                        assert.equal(crs.description, "Use NAD83-AB/3TM-111 instead.");
                        assert.equal(crs.deprecated, true);
                        validateExtent(Range2d.fromJSON({ low: { x: -113, y: 48 }, high: { x: -109, y: 84 } }), crs.crsExtent);
                        break;
                    case "NAD27-CAN.MTM-1":
                        nbFound++;
                        assert.equal(crs.description, "NAD27 / MTM zone 1");
                        assert.equal(crs.deprecated, false);
                        validateExtent(Range2d.fromJSON({ low: { x: -54.5, y: 45 }, high: { x: -50.5, y: 55 } }), crs.crsExtent);
                        break;
                    case "AL83-EF":
                        nbFound++;
                        assert.equal(crs.description, "NAD83 Alabama State Plane, East Zone, US Foot");
                        assert.equal(crs.deprecated, false);
                        validateExtent(Range2d.fromJSON({ low: { x: -87.5, y: 30 }, high: { x: -84, y: 35.75 } }), crs.crsExtent);
                        break;
                    case "ME-E":
                        nbFound++;
                        assert.equal(crs.description, "NAD27 Maine State Plane, East Zone(1801), US Foot");
                        assert.equal(crs.deprecated, false);
                        validateExtent(Range2d.fromJSON({ low: { x: -71, y: 43.5 }, high: { x: -66, y: 48 } }), crs.crsExtent);
                        break;
                    // world CRS
                    case "EPSG:4326":
                        nbFound++;
                        assert.equal(crs.description, "WGS 84");
                        assert.equal(crs.deprecated, false);
                        validateExtent(Range2d.fromJSON({ low: { x: -180, y: -90 }, high: { x: 180, y: 90 } }), crs.crsExtent);
                        break;
                }
            }
            assert.equal(nbFound, 5);
        });
        it("check CRS units", () => {
            const expectedUnits = ["Meter", "Degree", "USSurveyFoot", "InternationalFoot"];
            const definitiveListOfUnits = getAvailableCRSUnits();
            assert.isAtLeast(definitiveListOfUnits.length, expectedUnits.length);
            for (const unit of expectedUnits) {
                assert.include(definitiveListOfUnits, unit);
            }
        });
        it("can filter by each CRS unit", async () => {
            const minExpectedCounts = new Map([
                ["Meter", 8000],
                ["Degree", 1000],
                ["USSurveyFoot", 100],
                ["InternationalFoot", 50],
            ]);
            const units = getAvailableCRSUnits();
            for (const unit of units) {
                const listOfCRS = await getAvailableCoordinateReferenceSystems({
                    includeWorld: true,
                    unit,
                });
                const minExpected = minExpectedCounts.get(unit) ?? 1;
                assert.isAtLeast(listOfCRS.length, minExpected, `Expected at least ${minExpected} CRS with unit "${unit}", got ${listOfCRS.length}`);
                for (const crs of listOfCRS) {
                    assert.equal(crs.unit, unit, `CRS "${crs.name}" has unexpected unit "${crs.unit}" (expected "${unit}")`);
                }
            }
        });
        it("can filter by unit case-insensitively", async () => {
            const units = getAvailableCRSUnits();
            for (const unit of units) {
                const canonicalList = await getAvailableCoordinateReferenceSystems({
                    includeWorld: true,
                    unit,
                });
                const lowerCaseFilterList = await getAvailableCoordinateReferenceSystems({
                    includeWorld: true,
                    unit: unit.toLowerCase(),
                });
                assert.sameMembers(lowerCaseFilterList.map((crs) => crs.name), canonicalList.map((crs) => crs.name), `Expected lowercase unit filter to match canonical filter for "${unit}"`);
            }
        });
    });
    it("should not be able to interpret an invalid GeographicCRS", async () => {
        const interpretInvalidTest = async (formatCRS, testInvalid) => {
            const requestProps = { format: formatCRS, geographicCRSDef: testInvalid };
            const response = IModelNative.platform.GeoServices.getGeographicCRSInterpretation(requestProps);
            // At the moment return codes are not really error specific (we mostly return 32768) so we do not validate
            // actual error code for now.
            assert.isFalse(response.status === 0);
        };
        // WKT Without datum or projection clause
        await interpretInvalidTest("WKT", 'PROJCS["AirportGrid2007", GEOGCS["HeathrowT5.LL",PRIMEM["Greenwich",0],UNIT["Decimal Degree",0.017453292519943295]],UNIT["Meter",1.00000000000000]]');
        // Plain garbage
        await interpretInvalidTest("WKT", "Some invalid content");
        // Format is JSON but content is WKT
        await interpretInvalidTest("JSON", 'GEOGCS[ "Longitude / Latitude (ED 50 Denmark)", DATUM ["European 1950 (Denmark)", SPHEROID ["International 1924", 6378388, 297],-81.0703, -89.3603, -115.7526, .48488, .02436, .41321, -.540645], PRIMEM [ "Greenwich", 0.000000 ], UNIT ["Decimal Degree", 0.01745329251994330]]');
        // Vertical datum invalid for horizontal definition
        await interpretInvalidTest("JSON", '{ horizontalCRS: { id: "EPSG:27700" }, verticalCRS: { id: "NAVD29" } }');
        // No horizontal CRS
        await interpretInvalidTest("JSON", '{ verticalCRS: { id: "NAVD29" } }');
        // Unknown identifier
        await interpretInvalidTest("JSON", '{ horizontalCRS: { id: "UNKNOWN" }, verticalCRS: { id: "NAVD29" } }');
    });
    it("should return expected Transform from Helmert2DWithZOffset object", async () => {
        const helmertTransform = new Helmert2DWithZOffset({ translationX: 1, translationY: 1, translationZ: 1, rotDeg: 90, scale: 2 });
        const convertedTransform = helmertTransform.convertHelmertToTransform();
        const originExpected = Point3d.fromJSON({ x: 1, y: 1, z: 1 });
        assert(convertedTransform.origin.isAlmostEqual(originExpected));
        const expectedCoffs = [0, -2, 0, 2, 0, 0, 0, 0, 1];
        const actualCoffs = Array.from(convertedTransform.matrix.coffs);
        for (let i = 0; i < expectedCoffs.length; ++i) {
            assert(Math.abs(actualCoffs[i] - expectedCoffs[i]) < 1e-12, `Matrix coefficient at index ${i} differs: expected ${expectedCoffs[i]}, got ${actualCoffs[i]}`);
        }
    });
});
//# sourceMappingURL=GeoServices.test.js.map