"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module NativeApp
 */
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Storage = exports.NativeApp = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const FrontendLoggerCategory_1 = require("./common/FrontendLoggerCategory");
const IpcApp_1 = require("./IpcApp");
const NativeAppLogger_1 = require("./NativeAppLogger");
const Symbols_1 = require("./common/internal/Symbols");
/** NativeApp notifications from backend */
class NativeAppNotifyHandler extends IpcApp_1.NotificationHandler {
    get channelName() { return core_common_1.nativeAppIpcStrings.notifyChannel; }
    notifyInternetConnectivityChanged(status) {
        core_bentley_1.Logger.logInfo(FrontendLoggerCategory_1.FrontendLoggerCategory.NativeApp, "Internet connectivity changed");
        NativeApp.onInternetConnectivityChanged.raiseEvent(status);
    }
}
/**
 * The frontend of a native application
 * @see [Native Applications]($docs/learning/NativeApps.md)
 * @public
 */
class NativeApp {
    /** @deprecated in 3.x. use nativeAppIpc */
    static async callNativeHost(methodName, ...args) {
        return IpcApp_1.IpcApp[Symbols_1._callIpcChannel](core_common_1.nativeAppIpcStrings.channelName, methodName, ...args);
    }
    static async setConnectivity(by, status) {
        await this.nativeAppIpc.overrideInternetConnectivity(by, status);
    }
    static hookBrowserConnectivityEvents() {
        if (typeof window === "object" && window.ononline && window.onoffline) {
            window.addEventListener("online", this._onOnline);
            window.addEventListener("offline", this._onOffline);
        }
    }
    static unhookBrowserConnectivityEvents() {
        if (typeof window === "object" && window.ononline && window.onoffline) {
            window.removeEventListener("online", this._onOnline);
            window.removeEventListener("offline", this._onOffline);
        }
    }
    /** determine whether the app currently has internet connectivity, if known */
    static async checkInternetConnectivity() {
        return this.nativeAppIpc.checkInternetConnectivity();
    }
    /** @internal */
    static async overrideInternetConnectivity(status) {
        return this.nativeAppIpc.overrideInternetConnectivity(core_common_1.OverriddenBy.User, status);
    }
    static get isValid() { return this._isValid; }
    /**
     * This is called by either ElectronApp.startup or MobileApp.startup - it should not be called directly
     * @internal
     */
    static async startup(ipc, opts) {
        await IpcApp_1.IpcApp.startup(ipc, opts);
        if (this._isValid)
            return;
        this._isValid = true;
        this._removeAppNotify = NativeAppNotifyHandler.register(); // receives notifications from backend
        _a.hookBrowserConnectivityEvents();
        // initialize current online state.
        if (window.navigator.onLine) {
            await this.setConnectivity(core_common_1.OverriddenBy.Browser, window.navigator.onLine ? core_common_1.InternetConnectivityStatus.Online : core_common_1.InternetConnectivityStatus.Offline);
        }
    }
    /** @internal */
    static async shutdown() {
        this._removeAppNotify?.();
        _a.unhookBrowserConnectivityEvents();
        await NativeAppLogger_1.NativeAppLogger.flush();
        await IpcApp_1.IpcApp.shutdown();
        this._isValid = false;
    }
    static async requestDownloadBriefcase(iTwinId, iModelId, downloadOptions, asOf = core_common_1.IModelVersion.latest(), progress) {
        const shouldReportProgress = !!progress || !!downloadOptions.progressCallback;
        let stopProgressEvents = () => { };
        if (shouldReportProgress) {
            const handleProgress = (_evt, data) => {
                progress?.(data);
                downloadOptions.progressCallback?.(data);
            };
            stopProgressEvents = IpcApp_1.IpcApp.addListener(`nativeApp.progress-${iModelId}`, handleProgress);
        }
        const briefcaseId = (undefined !== downloadOptions.briefcaseId) ? downloadOptions.briefcaseId :
            (downloadOptions.syncMode === core_common_1.SyncMode.PullOnly ? 0 : await this.nativeAppIpc.acquireNewBriefcaseId(iModelId));
        const fileName = downloadOptions.fileName ?? await this.getBriefcaseFileName({ briefcaseId, iModelId });
        const requestProps = { iModelId, briefcaseId, iTwinId, asOf: asOf.toJSON(), fileName };
        const doDownload = async () => {
            try {
                await this.nativeAppIpc.downloadBriefcase(requestProps, shouldReportProgress, downloadOptions.progressInterval);
            }
            finally {
                stopProgressEvents();
            }
        };
        const requestCancel = async () => {
            const status = await this.nativeAppIpc.requestCancelDownloadBriefcase(fileName);
            if (status)
                stopProgressEvents();
            return status;
        };
        return { briefcaseId, fileName, downloadPromise: doDownload(), requestCancel };
    }
    /** Get the full path filename for a briefcase within the briefcase cache */
    static async getBriefcaseFileName(props) {
        return this.nativeAppIpc.getBriefcaseFileName(props);
    }
    /** Delete an existing briefcase
     * @param fileName the briefcase fileName
     */
    static async deleteBriefcase(fileName) {
        await this.nativeAppIpc.deleteBriefcaseFiles(fileName);
    }
    /** Get a list of all briefcase files held in the local briefcase cache directory */
    static async getCachedBriefcases(iModelId) {
        return this.nativeAppIpc.getCachedBriefcases(iModelId);
    }
    /**
     * Open a [[Storage]]. Creates a new Storage with that name if it does not already exist.
     * @param name Should be a local filename without an extension.
     * @returns a Promise for the [[Storage]].
     */
    static async openStorage(name) {
        if (this._storages.has(name))
            return this._storages.get(name);
        const storage = new Storage(await this.nativeAppIpc.storageMgrOpen(name));
        this._storages.set(storage.id, storage);
        return storage;
    }
    /**
     * Close a Storage and optionally delete it.
     * @param storage normally not call directly instead use Storage.close()
     * @param deleteStorage if true, delete the storage from disk after closing it.
     */
    static async closeStorage(storage, deleteStorage = false) {
        if (!this._storages.has(storage.id))
            throw new Error(`Storage [Id=${storage.id}] not open`);
        await this.nativeAppIpc.storageMgrClose(storage.id, deleteStorage);
        this._storages.delete(storage.id);
    }
    /** Get the list of existing Storages on the local disk. */
    static async getStorageNames() {
        return _a.nativeAppIpc.storageMgrNames();
    }
}
exports.NativeApp = NativeApp;
_a = NativeApp;
/** A Proxy to call one of the [NativeAppFunctions]($common) functions via IPC. */
NativeApp.nativeAppIpc = IpcApp_1.IpcApp.makeIpcProxy(core_common_1.nativeAppIpcStrings.channelName);
NativeApp._storages = new Map();
NativeApp._onOnline = async () => {
    await _a.setConnectivity(core_common_1.OverriddenBy.Browser, core_common_1.InternetConnectivityStatus.Online);
};
NativeApp._onOffline = async () => {
    await _a.setConnectivity(core_common_1.OverriddenBy.Browser, core_common_1.InternetConnectivityStatus.Offline);
};
/** event called when internet connectivity changes, if known */
NativeApp.onInternetConnectivityChanged = new core_bentley_1.BeEvent();
NativeApp._isValid = false;
/**
 *  A local disk-based cache for key value pairs for NativeApps.
 * @note This should be used only for local caching, since its not guaranteed to exist permanently.
 * @public
 */
class Storage {
    constructor(id) {
        this.id = id;
    }
    /** get the type of a value for a key, or undefined if not present. */
    async getValueType(key) {
        return NativeApp.nativeAppIpc.storageGetValueType(this.id, key);
    }
    /** Get the value for a key */
    async getData(key) {
        return NativeApp.nativeAppIpc.storageGet(this.id, key);
    }
    /** Set value for a key */
    async setData(key, value) {
        return NativeApp.nativeAppIpc.storageSet(this.id, key, value);
    }
    /**
     * Return an array of all keys in this Storage.
     * @note This can be expensive, depending on the number of keys present.
     */
    async getKeys() {
        return NativeApp.nativeAppIpc.storageKeys(this.id);
    }
    /** Remove a key and its data. */
    async removeData(key) {
        return NativeApp.nativeAppIpc.storageRemove(this.id, key);
    }
    /** Remove all keys and their data. */
    async removeAll() {
        return NativeApp.nativeAppIpc.storageRemoveAll(this.id);
    }
}
exports.Storage = Storage;
//# sourceMappingURL=NativeApp.js.map