"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.OPCFormatInterpreter = void 0;
const core_common_1 = require("@itwin/core-common");
const core_geometry_1 = require("@itwin/core-geometry");
const core_orbitgt_1 = require("@itwin/core-orbitgt");
const FrontendLoggerCategory_1 = require("../../common/FrontendLoggerCategory");
const core_bentley_1 = require("@itwin/core-bentley");
const RealityDataSource_1 = require("../../RealityDataSource");
const loggerCategory = FrontendLoggerCategory_1.FrontendLoggerCategory.RealityData;
/**
 * This class provide methods used to interpret Orbit Point Cloud (OPC) format
 */
class OPCFormatInterpreter {
    /** Gets an OPC file reader from a blobFileUrl
     * @param blobFileURL the name of the file.
     * @returns return a file reader open to read provided blob file
     */
    static async getFileReaderFromBlobFileURL(blobFileURL) {
        if (core_orbitgt_1.Downloader.INSTANCE == null)
            core_orbitgt_1.Downloader.INSTANCE = new core_orbitgt_1.DownloaderXhr();
        if (core_orbitgt_1.CRSManager.ENGINE == null)
            core_orbitgt_1.CRSManager.ENGINE = await core_orbitgt_1.OnlineEngine.create();
        // let blobFileURL: string = rdUrl;
        // if (accountName.length > 0) blobFileURL = UrlFS.getAzureBlobSasUrl(opcConfig.accountName, opcConfig.containerName, opcConfig.blobFileName, opcConfig.sasToken);
        const urlFS = new core_orbitgt_1.UrlFS();
        // wrap a caching layer (16 MB) around the blob file
        const blobFileSize = await urlFS.getFileLength(blobFileURL);
        core_bentley_1.Logger.logTrace(loggerCategory, `OPC File Size is ${blobFileSize.toString()}`);
        const blobFile = new core_orbitgt_1.PageCachedFile(urlFS, blobFileURL, blobFileSize, 128 * 1024 /* pageSize */, 128 /* maxPageCount */);
        const fileReader = await core_orbitgt_1.OPCReader.openFile(blobFile, blobFileURL, true /* lazyLoading */);
        return fileReader;
    }
    /** Gets reality data spatial location and extents
     * @param fileReader a file reader instance obtains from call to getFileReaderFromBlobFileURL
     * @returns spatial location and volume of interest, in meters, centered around `spatial location`
     * @throws [[RealityDataError]] if source is invalid or cannot be read
     */
    static async getSpatialLocationAndExtents(fileReader) {
        let worldRange = new core_geometry_1.Range3d();
        let location;
        let isGeolocated = true;
        const bounds = fileReader.getFileBounds();
        worldRange = core_geometry_1.Range3d.createXYZXYZ(bounds.getMinX(), bounds.getMinY(), bounds.getMinZ(), bounds.getMaxX(), bounds.getMaxY(), bounds.getMaxZ());
        isGeolocated = false;
        const fileCrs = fileReader.getFileCRS();
        // the CRS 9300 is not defined in the CRS registry database, so we cannot use CRSManager
        // Check to isGeographicCRS and isProjectedCRS are both going to return false in that case and we will fallback to
        // use un-georeferenced code path.
        await core_orbitgt_1.CRSManager.ENGINE.prepareForArea(fileCrs, bounds);
        const isGeographicCRS = core_orbitgt_1.CRSManager.ENGINE.isGeographicCRS(fileCrs);
        const isProjectedCRS = core_orbitgt_1.CRSManager.ENGINE.isProjectedCRS(fileCrs);
        if (fileCrs && (isProjectedCRS || isGeographicCRS)) {
            try {
                const wgs84ECEFCrs = "4978";
                await core_orbitgt_1.CRSManager.ENGINE.prepareForArea(wgs84ECEFCrs, new core_orbitgt_1.OrbitGtBounds());
                const ecefBounds = core_orbitgt_1.CRSManager.transformBounds(bounds, fileCrs, wgs84ECEFCrs);
                const ecefRange = core_geometry_1.Range3d.createXYZXYZ(ecefBounds.getMinX(), ecefBounds.getMinY(), ecefBounds.getMinZ(), ecefBounds.getMaxX(), ecefBounds.getMaxY(), ecefBounds.getMaxZ());
                const ecefCenter = (0, core_bentley_1.expectDefined)(ecefRange.localXYZToWorld(.5, .5, .5));
                const cartoCenter = (0, core_bentley_1.expectDefined)(core_common_1.Cartographic.fromEcef(ecefCenter));
                cartoCenter.height = 0;
                const ecefLocation = core_common_1.EcefLocation.createFromCartographicOrigin(cartoCenter);
                location = ecefLocation;
                // this.iModelDb.setEcefLocation(ecefLocation);
                const ecefToWorld = (0, core_bentley_1.expectDefined)(ecefLocation.getTransform().inverse());
                worldRange = ecefToWorld.multiplyRange(ecefRange);
                isGeolocated = true;
            }
            catch (e) {
                core_bentley_1.Logger.logWarning(loggerCategory, `Error getSpatialLocationAndExtents - cannot interpret point cloud`);
                const errorProps = core_bentley_1.BentleyError.getErrorProps(e);
                const getMetaData = () => {
                    return { errorProps };
                };
                const error = new RealityDataSource_1.RealityDataError(core_bentley_1.RealityDataStatus.InvalidData, "Invalid or unknown data", getMetaData);
                throw error;
            }
        }
        else {
            // NoGCS case
            isGeolocated = false;
            const centerOfEarth = new core_common_1.EcefLocation({ origin: { x: 0.0, y: 0.0, z: 0.0 }, orientation: { yaw: 0.0, pitch: 0.0, roll: 0.0 } });
            location = centerOfEarth;
            core_bentley_1.Logger.logTrace(loggerCategory, "OPC RealityData NOT Geolocated", () => ({ ...location }));
        }
        const spatialLocation = { location, worldRange, isGeolocated };
        return spatialLocation;
    }
}
exports.OPCFormatInterpreter = OPCFormatInterpreter;
//# sourceMappingURL=OPCFormatInterpreter.js.map