import { profile } from '../profiling';
import { isEmbedded } from '../ui/embedding';
import { IOSHelper } from '../ui/core/view/view-helper';
import { getWindow } from '../utils/native-helper';
import { SDK_VERSION } from '../utils/constants';
import { ios as iosUtils, dataSerialize } from '../utils/native-helper';
import { ApplicationCommon, initializeSdkVersionClass, SceneEvents } from './application-common';
import { Observable } from '../data/observable';
import { Trace } from '../trace';
import { AccessibilityServiceEnabledPropName, CommonA11YServiceEnabledObservable, SharedA11YObservable, a11yServiceClasses, a11yServiceDisabledClass, a11yServiceEnabledClass, fontScaleCategoryClasses, fontScaleExtraLargeCategoryClass, fontScaleExtraSmallCategoryClass, fontScaleMediumCategoryClass, getCurrentA11YServiceClass, getCurrentFontScaleCategory, getCurrentFontScaleClass, getFontScaleCssClasses, setCurrentA11YServiceClass, setCurrentFontScaleCategory, setCurrentFontScaleClass, setFontScaleCssClasses, FontScaleCategory, getClosestValidFontScale, VALID_FONT_SCALES, setFontScale, getFontScale, setInitFontScale, getFontScaleCategory, setInitAccessibilityCssHelper, notifyAccessibilityFocusState, AccessibilityLiveRegion, AccessibilityRole, AccessibilityState, AccessibilityTrait, isA11yEnabled, setA11yEnabled, enforceArray, } from '../accessibility/accessibility-common';
import { CoreTypes } from '../core-types';
import { getiOSWindow, setA11yUpdatePropertiesCallback, setApplicationPropertiesCallback, setAppMainEntry, setiOSWindow, setRootView, setToggleApplicationEventListenersCallback } from './helpers-common';
var NotificationObserver = (function (_super) {
    __extends(NotificationObserver, _super);
    function NotificationObserver() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    NotificationObserver.initWithCallback = function (onReceiveCallback) {
        var observer = _super.new.call(this);
        observer._onReceiveCallback = onReceiveCallback;
        return observer;
    };
    NotificationObserver.prototype.onReceive = function (notification) {
        this._onReceiveCallback(notification);
    };
    NotificationObserver.ObjCExposedMethods = {
        onReceive: { returns: interop.types.void, params: [NSNotification] },
    };
    return NotificationObserver;
}(NSObject));
var CADisplayLinkTarget = (function (_super) {
    __extends(CADisplayLinkTarget, _super);
    function CADisplayLinkTarget() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    CADisplayLinkTarget.initWithOwner = function (owner) {
        var target = CADisplayLinkTarget.new();
        target._owner = owner;
        return target;
    };
    CADisplayLinkTarget.prototype.onDisplayed = function (link) {
        link.invalidate();
        var owner = this._owner.deref();
        if (!owner) {
            return;
        }
        owner.displayedOnce = true;
        owner.notify({
            eventName: owner.displayedEvent,
            object: owner,
            ios: UIApplication.sharedApplication,
        });
        owner.displayedLinkTarget = null;
        owner.displayedLink = null;
    };
    CADisplayLinkTarget.ObjCExposedMethods = {
        onDisplayed: { returns: interop.types.void, params: [CADisplayLink] },
    };
    return CADisplayLinkTarget;
}(NSObject));
/**
 * Detect if the app supports scenes.
 * When an app configures UIApplicationSceneManifest in Info.plist
 * it will use scene lifecycle management.
 */
let sceneManifest;
function supportsScenes() {
    if (SDK_VERSION < 13) {
        return false;
    }
    if (typeof sceneManifest === 'undefined') {
        // Check if scene manifest exists in Info.plist
        sceneManifest = NSBundle.mainBundle.objectForInfoDictionaryKey('UIApplicationSceneManifest');
    }
    return !!sceneManifest;
}
function supportsMultipleScenes() {
    if (SDK_VERSION < 13) {
        return false;
    }
    return UIApplication.sharedApplication?.supportsMultipleScenes;
}
var Responder = (function (_super) {
    __extends(Responder, _super);
    function Responder() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Object.defineProperty(Responder.prototype, "window", {
        get: function () {
            return Application.ios.window;
        },
        set: function (value) {
        },
        enumerable: true,
        configurable: true
    });
    Responder.ObjCProtocols = [UIApplicationDelegate];
    return Responder;
}(UIResponder));
if (supportsScenes()) {
    /**
     * This method is called when a new scene session is being created.
     * Important: When this method is implemented, the app assumes scene-based lifecycle management.
     * Detected by the Info.plist existence 'UIApplicationSceneManifest'.
     * If this method is implemented when there is no manifest defined,
     * the app will boot to a white screen.
     */
    Responder.prototype.applicationConfigurationForConnectingSceneSessionOptions = function (application, connectingSceneSession, options) {
        const config = UISceneConfiguration.configurationWithNameSessionRole('Default Configuration', connectingSceneSession.role);
        config.sceneClass = UIWindowScene;
        config.delegateClass = SceneDelegate;
        return config;
    };
    // scene session destruction handling
    Responder.prototype.applicationDidDiscardSceneSessions = function (application, sceneSessions) {
        // Note: we could emit an event here if needed
        // console.log('Scene sessions discarded:', sceneSessions.count);
    };
}
var SceneDelegate = (function (_super) {
    __extends(SceneDelegate, _super);
    function SceneDelegate() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Object.defineProperty(SceneDelegate.prototype, "window", {
        get: function () {
            return this._window;
        },
        set: function (value) {
            this._window = value;
        },
        enumerable: true,
        configurable: true
    });
    SceneDelegate.prototype.sceneWillConnectToSessionOptions = function (scene, session, connectionOptions) {
        if (Trace.isEnabled()) {
            Trace.write("SceneDelegate.sceneWillConnectToSessionOptions called with role: ".concat(session.role), Trace.categories.NativeLifecycle);
        }
        if (!(scene instanceof UIWindowScene)) {
            return;
        }
        this._scene = scene;
        this._window = UIWindow.alloc().initWithWindowScene(scene);
        Application.ios._setWindowForScene(this._window, scene);
        Application.ios._setupWindowForScene(this._window, scene);
        Application.ios.notify({
            eventName: SceneEvents.sceneWillConnect,
            object: Application.ios,
            scene: scene,
            window: this._window,
            connectionOptions: connectionOptions,
        });
        if (scene === Application.ios.getPrimaryScene()) {
            this._window.makeKeyAndVisible();
        }
        else {
            Application.ios.notify({
                eventName: SceneEvents.sceneContentSetup,
                object: Application.ios,
                scene: scene,
                window: this._window,
                connectionOptions: connectionOptions,
            });
        }
        if (!Application.ios.getPrimaryScene()) {
            Application.ios._notifySceneAppStarted();
        }
    };
    SceneDelegate.prototype.sceneDidBecomeActive = function (scene) {
    };
    SceneDelegate.prototype.sceneWillResignActive = function (scene) {
        Application.ios.notify({
            eventName: SceneEvents.sceneWillResignActive,
            object: Application.ios,
            scene: scene,
        });
    };
    SceneDelegate.prototype.sceneWillEnterForeground = function (scene) {
    };
    SceneDelegate.prototype.sceneDidEnterBackground = function (scene) {
    };
    SceneDelegate.prototype.sceneDidDisconnect = function (scene) {
    };
    SceneDelegate.ObjCProtocols = [UIWindowSceneDelegate];
    return SceneDelegate;
}(UIResponder));
// ensure available globally
global.SceneDelegate = SceneDelegate;
export class iOSApplication extends ApplicationCommon {
    /**
     * @internal - should not be constructed by the user.
     */
    constructor() {
        super();
        this._delegateHandlers = new Map();
        this._windowSceneMap = new Map();
        this._primaryScene = null;
        this._openedScenesById = new Map();
        this._notificationObservers = [];
        this.displayedOnce = false;
        this.addNotificationObserver(UIApplicationDidFinishLaunchingNotification, this.didFinishLaunchingWithOptions.bind(this));
        this.addNotificationObserver(UIApplicationDidBecomeActiveNotification, this.didBecomeActive.bind(this));
        this.addNotificationObserver(UIApplicationDidEnterBackgroundNotification, this.didEnterBackground.bind(this));
        this.addNotificationObserver(UIApplicationWillTerminateNotification, this.willTerminate.bind(this));
        this.addNotificationObserver(UIApplicationDidReceiveMemoryWarningNotification, this.didReceiveMemoryWarning.bind(this));
        this.addNotificationObserver(UIApplicationDidChangeStatusBarOrientationNotification, this.didChangeStatusBarOrientation.bind(this));
        // Add scene lifecycle notification observers only if scenes are supported
        if (this.supportsScenes()) {
            this.addNotificationObserver('UISceneWillConnectNotification', this.sceneWillConnect.bind(this));
            this.addNotificationObserver('UISceneDidActivateNotification', this.sceneDidActivate.bind(this));
            this.addNotificationObserver('UISceneWillEnterForegroundNotification', this.sceneWillEnterForeground.bind(this));
            this.addNotificationObserver('UISceneDidEnterBackgroundNotification', this.sceneDidEnterBackground.bind(this));
            this.addNotificationObserver('UISceneDidDisconnectNotification', this.sceneDidDisconnect.bind(this));
        }
    }
    getRootView() {
        return this._rootView;
    }
    resetRootView(view) {
        super.resetRootView(view);
        this.setWindowContent();
    }
    run(entry) {
        setAppMainEntry(typeof entry === 'string' ? { moduleName: entry } : entry);
        this.started = true;
        if (this.nativeApp) {
            this.runAsEmbeddedApp();
        }
        else {
            this.runAsMainApp();
        }
    }
    runAsMainApp() {
        UIApplicationMain(0, null, null, this.delegate ? NSStringFromClass(this.delegate) : NSStringFromClass(Responder));
    }
    runAsEmbeddedApp() {
        // TODO: this rootView should be held alive until rootController dismissViewController is called.
        const rootView = this.createRootView(this._rootView, true);
        if (!rootView) {
            return;
        }
        this._rootView = rootView;
        setRootView(rootView);
        // Attach to the existing iOS app
        const window = getWindow();
        if (!window) {
            return;
        }
        const rootController = window.rootViewController;
        if (!rootController) {
            return;
        }
        const controller = this.getViewController(rootView);
        const embedderDelegate = NativeScriptEmbedder.sharedInstance().delegate;
        rootView._setupAsRootView({});
        rootView.on(IOSHelper.traitCollectionColorAppearanceChangedEvent, () => {
            const userInterfaceStyle = controller.traitCollection.userInterfaceStyle;
            const newSystemAppearance = this.getSystemAppearanceValue(userInterfaceStyle);
            this.setSystemAppearance(newSystemAppearance);
        });
        rootView.on(IOSHelper.traitCollectionLayoutDirectionChangedEvent, () => {
            const layoutDirection = controller.traitCollection.layoutDirection;
            const newLayoutDirection = this.getLayoutDirectionValue(layoutDirection);
            this.setLayoutDirection(newLayoutDirection);
        });
        if (embedderDelegate) {
            this.setViewControllerView(rootView);
            embedderDelegate.presentNativeScriptApp(controller);
        }
        else {
            const visibleVC = iosUtils.getVisibleViewController(rootController);
            visibleVC.presentViewControllerAnimatedCompletion(controller, true, null);
        }
        this.initRootView(rootView);
        this.notifyAppStarted();
    }
    getViewController(rootView) {
        let viewController = rootView.viewController || rootView.ios;
        if (!(viewController instanceof UIViewController)) {
            // We set UILayoutViewController dynamically to the root view if it doesn't have a view controller
            // At the moment the root view doesn't have its native view created. We set it in the setViewControllerView func
            viewController = IOSHelper.UILayoutViewController.initWithOwner(new WeakRef(rootView));
            rootView.viewController = viewController;
        }
        return viewController;
    }
    setViewControllerView(view) {
        const viewController = view.viewController || view.ios;
        const nativeView = view.ios || view.nativeViewProtected;
        if (!nativeView || !viewController) {
            throw new Error('Root should be either UIViewController or UIView');
        }
        if (viewController instanceof IOSHelper.UILayoutViewController) {
            viewController.view.addSubview(nativeView);
        }
    }
    setMaxRefreshRate(options) {
        const adjustRefreshRate = () => {
            if (!this.displayedLink) {
                return;
            }
            const minFrameRateDisabled = NSBundle.mainBundle.objectForInfoDictionaryKey('CADisableMinimumFrameDurationOnPhone');
            if (minFrameRateDisabled) {
                let max = 120;
                const deviceMaxFrames = iosUtils.getMainScreen().maximumFramesPerSecond;
                if (options?.max) {
                    if (deviceMaxFrames) {
                        // iOS 10.3
                        max = options.max <= deviceMaxFrames ? options.max : deviceMaxFrames;
                    }
                    else if (this.displayedLink.preferredFramesPerSecond) {
                        // iOS 10.0
                        max = options.max <= this.displayedLink.preferredFramesPerSecond ? options.max : this.displayedLink.preferredFramesPerSecond;
                    }
                }
                if (SDK_VERSION >= 15 || __VISIONOS__) {
                    const min = options?.min || max / 2;
                    const preferred = options?.preferred || max;
                    this.displayedLink.preferredFrameRateRange = CAFrameRateRangeMake(min, max, preferred);
                }
                else {
                    this.displayedLink.preferredFramesPerSecond = max;
                }
            }
        };
        if (this.displayedOnce) {
            adjustRefreshRate();
            return;
        }
        this.displayedLinkTarget = CADisplayLinkTarget.initWithOwner(new WeakRef(this));
        this.displayedLink = CADisplayLink.displayLinkWithTargetSelector(this.displayedLinkTarget, 'onDisplayed');
        adjustRefreshRate();
        this.displayedLink.addToRunLoopForMode(NSRunLoop.mainRunLoop, NSDefaultRunLoopMode);
        this.displayedLink.addToRunLoopForMode(NSRunLoop.mainRunLoop, UITrackingRunLoopMode);
    }
    get rootController() {
        return this.window?.rootViewController;
    }
    get nativeApp() {
        return UIApplication.sharedApplication;
    }
    get window() {
        // TODO: consideration
        // may not want to cache this value given the potential of multiple scenes
        // particularly with SwiftUI app lifecycle based apps
        if (!getiOSWindow()) {
            // Note: NativeScriptViewFactory.getKeyWindow will always be used in SwiftUI app lifecycle based apps
            setiOSWindow(getWindow());
        }
        return getiOSWindow();
    }
    get delegate() {
        return this._delegate;
    }
    set delegate(value) {
        if (this._delegate !== value) {
            this._delegate = value;
        }
    }
    addDelegateHandler(methodName, handler) {
        // safe-guard against invalid handlers
        if (typeof handler !== 'function') {
            return;
        }
        // ensure we have a delegate
        this.delegate ?? (this.delegate = Responder);
        const handlers = this._delegateHandlers.get(methodName) ?? [];
        if (!this._delegateHandlers.has(methodName)) {
            const originalHandler = this.delegate.prototype[methodName];
            if (originalHandler) {
                // if there is an original handler, we add it to the handlers array to be called first.
                handlers.push(originalHandler);
            }
            // replace the original method implementation with one that will call all handlers.
            this.delegate.prototype[methodName] = function (...args) {
                let res;
                for (const handler of handlers) {
                    if (typeof handler !== 'function') {
                        continue;
                    }
                    res = handler.apply(this, args);
                }
                return res;
            };
            // store the handlers
            this._delegateHandlers.set(methodName, handlers);
        }
        handlers.push(handler);
    }
    getNativeApplication() {
        return this.nativeApp;
    }
    addNotificationObserver(notificationName, onReceiveCallback) {
        const observer = NotificationObserver.initWithCallback(onReceiveCallback);
        NSNotificationCenter.defaultCenter.addObserverSelectorNameObject(observer, 'onReceive', notificationName, null);
        this._notificationObservers.push(observer);
        return observer;
    }
    removeNotificationObserver(observer /* NotificationObserver */, notificationName) {
        const index = this._notificationObservers.indexOf(observer);
        if (index >= 0) {
            this._notificationObservers.splice(index, 1);
            NSNotificationCenter.defaultCenter.removeObserverNameObject(observer, notificationName, null);
        }
    }
    getSystemAppearance() {
        // userInterfaceStyle is available on UITraitCollection since iOS 12.
        if ((!__VISIONOS__ && SDK_VERSION <= 11) || !this.rootController) {
            return null;
        }
        const userInterfaceStyle = this.rootController.traitCollection.userInterfaceStyle;
        return this.getSystemAppearanceValue(userInterfaceStyle);
    }
    getSystemAppearanceValue(userInterfaceStyle) {
        switch (userInterfaceStyle) {
            case 2 /* UIUserInterfaceStyle.Dark */:
                return 'dark';
            case 1 /* UIUserInterfaceStyle.Light */:
            case 0 /* UIUserInterfaceStyle.Unspecified */:
                return 'light';
        }
    }
    getLayoutDirection() {
        if (!this.rootController) {
            return null;
        }
        const layoutDirection = this.rootController.traitCollection.layoutDirection;
        return this.getLayoutDirectionValue(layoutDirection);
    }
    getLayoutDirectionValue(layoutDirection) {
        switch (layoutDirection) {
            case 0 /* UITraitEnvironmentLayoutDirection.LeftToRight */:
                return CoreTypes.LayoutDirection.ltr;
            case 1 /* UITraitEnvironmentLayoutDirection.RightToLeft */:
                return CoreTypes.LayoutDirection.rtl;
        }
    }
    getOrientation() {
        let statusBarOrientation;
        if (__VISIONOS__) {
            statusBarOrientation = NativeScriptEmbedder.sharedInstance().windowScene.interfaceOrientation;
        }
        else {
            statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
        }
        return this.getOrientationValue(statusBarOrientation);
    }
    getOrientationValue(orientation) {
        switch (orientation) {
            case 3 /* UIInterfaceOrientation.LandscapeRight */:
            case 4 /* UIInterfaceOrientation.LandscapeLeft */:
                return 'landscape';
            case 2 /* UIInterfaceOrientation.PortraitUpsideDown */:
            case 1 /* UIInterfaceOrientation.Portrait */:
                return 'portrait';
            case 0 /* UIInterfaceOrientation.Unknown */:
                return 'unknown';
        }
    }
    notifyAppStarted(notification) {
        const root = this.notifyLaunch({
            ios: notification?.userInfo?.objectForKey('UIApplicationLaunchOptionsLocalNotificationKey') ?? null,
        });
        if (getiOSWindow()) {
            if (root !== null && !isEmbedded()) {
                this.setWindowContent(root);
            }
        }
        else {
            setiOSWindow(this.window);
        }
    }
    // Public method for scene-based app startup
    _notifySceneAppStarted() {
        this.notifyAppStarted();
    }
    _onLivesync(context) {
        // Handle application root module
        const isAppRootModuleChanged = context && context.path && context.path.includes(this.getMainEntry().moduleName) && context.type !== 'style';
        // Set window content when:
        // + Application root module is changed
        // + View did not handle the change
        // Note:
        // The case when neither app root module is changed, nor livesync is handled on View,
        // then changes will not apply until navigate forward to the module.
        if (isAppRootModuleChanged || (this._rootView && !this._rootView._onLivesync(context))) {
            this.setWindowContent();
        }
    }
    setWindowContent(view) {
        if (this._rootView) {
            // if we already have a root view, we reset it.
            this._rootView._onRootViewReset();
        }
        const rootView = this.createRootView(view);
        const controller = this.getViewController(rootView);
        this._rootView = rootView;
        setRootView(rootView);
        // setup view as styleScopeHost
        rootView._setupAsRootView({});
        this.setViewControllerView(rootView);
        const win = this.window;
        const haveController = win.rootViewController !== null;
        win.rootViewController = controller;
        if (!haveController) {
            win.makeKeyAndVisible();
        }
        this.initRootView(rootView);
        rootView.on(IOSHelper.traitCollectionColorAppearanceChangedEvent, () => {
            const userInterfaceStyle = controller.traitCollection.userInterfaceStyle;
            const newSystemAppearance = this.getSystemAppearanceValue(userInterfaceStyle);
            this.setSystemAppearance(newSystemAppearance);
        });
        rootView.on(IOSHelper.traitCollectionLayoutDirectionChangedEvent, () => {
            const layoutDirection = controller.traitCollection.layoutDirection;
            const newLayoutDirection = this.getLayoutDirectionValue(layoutDirection);
            this.setLayoutDirection(newLayoutDirection);
        });
    }
    // Observers
    didFinishLaunchingWithOptions(notification) {
        if (__DEV__) {
            /**
             * v9+ runtime crash handling
             * When crash occurs during boot, we let runtime take over
             */
            if (notification.userInfo) {
                const isBootCrash = notification.userInfo.objectForKey('NativeScriptBootCrash');
                if (isBootCrash) {
                    // fatal crash will show in console without app exiting
                    // allowing hot reload fixes to continue
                    return;
                }
            }
        }
        this.setMaxRefreshRate();
        // Only set up window if NOT using scene-based lifecycle
        if (!this.supportsScenes()) {
            // Traditional single-window app setup
            // ensures window is assigned to proper window scene
            setiOSWindow(this.window);
            if (!getiOSWindow()) {
                // if still no window, create one
                setiOSWindow(UIWindow.alloc().initWithFrame(UIScreen.mainScreen.bounds));
            }
            if (!__VISIONOS__) {
                this.window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
            }
            this.notifyAppStarted(notification);
        }
        else {
            // Scene-based app - window creation will happen in scene delegate
        }
    }
    didBecomeActive(notification) {
        const additionalData = {
            ios: UIApplication.sharedApplication,
        };
        this.setInBackground(false, additionalData);
        this.setSuspended(false, additionalData);
        const rootView = this._rootView;
        if (rootView && !rootView.isLoaded) {
            rootView.callLoaded();
        }
    }
    didEnterBackground(notification) {
        const additionalData = {
            ios: UIApplication.sharedApplication,
        };
        this.setInBackground(true, additionalData);
        this.setSuspended(true, additionalData);
        const rootView = this._rootView;
        if (rootView && rootView.isLoaded) {
            rootView.callUnloaded();
        }
    }
    willTerminate(notification) {
        this.notify({
            eventName: this.exitEvent,
            object: this,
            ios: this.ios,
        });
        // const rootView = this._rootView;
        // if (rootView && rootView.isLoaded) {
        // 	rootView.callUnloaded();
        // }
    }
    didReceiveMemoryWarning(notification) {
        this.notify({
            eventName: this.lowMemoryEvent,
            object: this,
            ios: this.ios,
        });
    }
    didChangeStatusBarOrientation(notification) {
        const statusBarOrientation = UIApplication.sharedApplication.statusBarOrientation;
        const newOrientation = this.getOrientationValue(statusBarOrientation);
        this.setOrientation(newOrientation);
    }
    // Scene lifecycle notification handlers
    sceneWillConnect(notification) {
        const scene = notification.object;
        if (!scene || !(scene instanceof UIWindowScene)) {
            return;
        }
        // Store as primary scene if it's the first one
        if (!this._primaryScene) {
            this._primaryScene = scene;
        }
        this.notify({
            eventName: SceneEvents.sceneWillConnect,
            object: this,
            scene: scene,
            userInfo: notification.userInfo,
        });
    }
    sceneDidActivate(notification) {
        const scene = notification.object;
        this.notify({
            eventName: SceneEvents.sceneDidActivate,
            object: this,
            scene: scene,
        });
        // If this is the primary scene, trigger traditional app lifecycle
        if (scene === this._primaryScene) {
            const additionalData = {
                ios: UIApplication.sharedApplication,
                scene: scene,
            };
            this.setInBackground(false, additionalData);
            this.setSuspended(false, additionalData);
            if (this._rootView && !this._rootView.isLoaded) {
                this._rootView.callLoaded();
            }
        }
    }
    sceneWillEnterForeground(notification) {
        const scene = notification.object;
        this.notify({
            eventName: SceneEvents.sceneWillEnterForeground,
            object: this,
            scene: scene,
        });
    }
    sceneDidEnterBackground(notification) {
        const scene = notification.object;
        this.notify({
            eventName: SceneEvents.sceneDidEnterBackground,
            object: this,
            scene: scene,
        });
        // If this is the primary scene, trigger traditional app lifecycle
        if (scene === this._primaryScene) {
            const additionalData = {
                ios: UIApplication.sharedApplication,
                scene: scene,
            };
            this.setInBackground(true, additionalData);
            this.setSuspended(true, additionalData);
            if (this._rootView && this._rootView.isLoaded) {
                this._rootView.callUnloaded();
            }
        }
    }
    sceneDidDisconnect(notification) {
        const scene = notification.object;
        this._removeWindowForScene(scene);
        // If primary scene disconnected, clear it
        if (scene === this._primaryScene) {
            this._primaryScene = null;
        }
        if (this._primaryScene) {
            if (SDK_VERSION >= 17) {
                const request = UISceneSessionActivationRequest.requestWithSession(this._primaryScene.session);
                UIApplication.sharedApplication.activateSceneSessionForRequestErrorHandler(request, (err) => {
                    if (err) {
                        console.log('Failed to activate primary scene:', err.localizedDescription);
                    }
                });
            }
            else {
                UIApplication.sharedApplication.requestSceneSessionActivationUserActivityOptionsErrorHandler(this._primaryScene.session, null, null, (err) => {
                    if (err) {
                        console.log('Failed to activate primary scene (legacy):', err.localizedDescription);
                    }
                });
            }
        }
        this.notify({
            eventName: SceneEvents.sceneDidDisconnect,
            object: this,
            scene: scene,
        });
    }
    // Scene management helper methods
    _setWindowForScene(window, scene) {
        this._windowSceneMap.set(scene, window);
    }
    _removeWindowForScene(scene) {
        this._windowSceneMap.delete(scene);
        // also untrack opened scene id
        try {
            const s = scene;
            if (s && s.session) {
                const id = this._getSceneId(s);
                this._openedScenesById.delete(id);
            }
        }
        catch { }
    }
    _getWindowForScene(scene) {
        return this._windowSceneMap.get(scene);
    }
    _setupWindowForScene(window, scene) {
        if (!window) {
            return;
        }
        // track opened scene
        try {
            const id = this._getSceneId(scene);
            this._openedScenesById.set(id, scene);
        }
        catch { }
        // Set up window background
        if (!__VISIONOS__) {
            window.backgroundColor = SDK_VERSION <= 12 || !UIColor.systemBackgroundColor ? UIColor.whiteColor : UIColor.systemBackgroundColor;
        }
        // If this is the primary scene, set up the main application content
        if (scene === this._primaryScene || !this._primaryScene) {
            this._primaryScene = scene;
            if (!getiOSWindow()) {
                setiOSWindow(window);
            }
            // Set up the window content for the primary scene
            this.setWindowContent();
        }
    }
    get sceneDelegate() {
        if (!this._sceneDelegate) {
            this._sceneDelegate = SceneDelegate.new();
        }
        return this._sceneDelegate;
    }
    set sceneDelegate(value) {
        this._sceneDelegate = value;
    }
    /**
     * Multi-window support
     */
    /**
     * Opens a new window with the specified data.
     * @param data The data to pass to the new window.
     */
    openWindow(data) {
        if (!supportsMultipleScenes()) {
            console.log('Cannot create a new scene - not supported on this device.');
            return;
        }
        try {
            const app = UIApplication.sharedApplication;
            // iOS 17+
            if (SDK_VERSION >= 17) {
                // Create a new scene activation request with proper role
                let request;
                try {
                    // Use the correct factory method to create request with role
                    // Based on the type definitions, this is the proper way
                    request = UISceneSessionActivationRequest.requestWithRole(UIWindowSceneSessionRoleApplication);
                    // Note: may be useful to allow user defined activity type through optional string typed data in future
                    const activity = NSUserActivity.alloc().initWithActivityType(`${NSBundle.mainBundle.bundleIdentifier}.scene`);
                    activity.userInfo = dataSerialize(data);
                    request.userActivity = activity;
                    // Set proper options with requesting scene
                    const options = UISceneActivationRequestOptions.new();
                    // Note: explore secondary windows spawning other windows
                    // and if this context needs to change in those cases
                    const mainWindow = Application.ios.getPrimaryWindow();
                    options.requestingScene = mainWindow?.windowScene;
                    /**
                     * Note: This does not work in testing but worth exploring further sometime
                     * regarding the size/dimensions of opened secondary windows.
                     * The initial size is ultimately determined by the system
                     * based on available space and user context.
                     */
                    // Get the size restrictions from the window scene
                    // const sizeRestrictions = (options.requestingScene as UIWindowScene).sizeRestrictions;
                    // // Set your minimum and maximum dimensions
                    // sizeRestrictions.minimumSize = CGSizeMake(320, 400);
                    // sizeRestrictions.maximumSize = CGSizeMake(600, 800);
                    request.options = options;
                }
                catch (roleError) {
                    console.log('Error creating request:', roleError);
                    return;
                }
                app.activateSceneSessionForRequestErrorHandler(request, (error) => {
                    if (error) {
                        console.log('Error creating new scene (iOS 17+):', error);
                        // Log additional debugging info
                        if (error.userInfo) {
                            console.error(`Error userInfo: ${error.userInfo.description}`);
                        }
                        // Handle specific error types
                        if (error.localizedDescription.includes('role') && error.localizedDescription.includes('nil')) {
                            this.createSceneWithLegacyAPI(data);
                        }
                        else if (error.domain === 'FBSWorkspaceErrorDomain' && error.code === 2) {
                            this.createSceneWithLegacyAPI(data);
                        }
                    }
                });
            }
            // iOS 13-16 - Use the legacy requestSceneSessionActivationUserActivityOptionsErrorHandler method
            else if (SDK_VERSION >= 13 && SDK_VERSION < 17) {
                app.requestSceneSessionActivationUserActivityOptionsErrorHandler(null, // session
                null, // userActivity
                null, // options
                (error) => {
                    if (error) {
                        console.log('Error creating new scene (legacy):', error);
                    }
                });
            }
            // Fallback for older iOS versions or unsupported configurations
            else {
                console.log('Neither new nor legacy scene activation methods are available');
            }
        }
        catch (error) {
            console.error('Error requesting new scene:', error);
        }
    }
    /**
     * Closes a secondary window/scene.
     * Usage examples:
     *  - Application.ios.closeWindow() // best-effort close of a non-primary scene
     *  - Application.ios.closeWindow(button) // from a tap handler within the scene
     *  - Application.ios.closeWindow(window)
     *  - Application.ios.closeWindow(scene)
     *  - Application.ios.closeWindow('scene-id')
     */
    closeWindow(target) {
        if (!__APPLE__) {
            return;
        }
        try {
            const scene = this._resolveScene(target);
            if (!scene) {
                console.log('closeWindow: No scene resolved for target');
                return;
            }
            // Don't allow closing the primary scene
            if (scene === this._primaryScene) {
                console.log('closeWindow: Refusing to close the primary scene');
                return;
            }
            const session = scene.session;
            if (!session) {
                console.log('closeWindow: Scene has no session to destroy');
                return;
            }
            const app = UIApplication.sharedApplication;
            if (app.requestSceneSessionDestructionOptionsErrorHandler) {
                app.requestSceneSessionDestructionOptionsErrorHandler(session, null, (error) => {
                    if (error) {
                        console.log('closeWindow: destruction error', error);
                    }
                    else {
                        // clean up tracked id
                        const id = this._getSceneId(scene);
                        this._openedScenesById.delete(id);
                    }
                });
            }
            else {
                console.info('closeWindow: Scene destruction API not available on this iOS version');
            }
        }
        catch (err) {
            console.log('closeWindow: Unexpected error', err);
        }
    }
    getAllWindows() {
        return Array.from(this._windowSceneMap.values());
    }
    getAllScenes() {
        return Array.from(this._windowSceneMap.keys());
    }
    getWindowScenes() {
        return this.getAllScenes().filter((scene) => scene instanceof UIWindowScene);
    }
    getPrimaryWindow() {
        if (this._primaryScene) {
            return this._getWindowForScene(this._primaryScene) || getiOSWindow();
        }
        return getiOSWindow();
    }
    getPrimaryScene() {
        return this._primaryScene;
    }
    // Scene lifecycle management
    supportsScenes() {
        return supportsScenes();
    }
    supportsMultipleScenes() {
        return supportsMultipleScenes();
    }
    isUsingSceneLifecycle() {
        return this.supportsScenes() && this._windowSceneMap.size > 0;
    }
    // Call this to set up scene-based configuration
    configureForScenes() {
        if (!this.supportsScenes()) {
            console.warn('Scene-based lifecycle is only supported on iOS 13+ iPad or visionOS with multi-scene enabled apps.');
            return;
        }
        // Additional scene configuration can be added here
        // For now, the notification observers are already set up in the constructor
    }
    // Stable scene id for lookups
    _getSceneId(scene) {
        try {
            if (!scene) {
                return 'Unknown';
            }
            // Prefer session persistentIdentifier when available (stable across lifetime)
            const session = scene.session;
            const persistentId = session && session.persistentIdentifier;
            if (persistentId) {
                return `${persistentId}`;
            }
            // Fallbacks
            if (scene.hash != null) {
                return `${scene.hash}`;
            }
            const desc = scene.description;
            if (desc) {
                return `${desc}`;
            }
        }
        catch (err) {
            // ignore
        }
        return 'Unknown';
    }
    // Resolve a UIWindowScene from various input types
    _resolveScene(target) {
        if (!__APPLE__) {
            return null;
        }
        if (!target) {
            // Try to pick a non-primary foreground active scene, else last known scene
            const scenes = this.getWindowScenes?.() || [];
            const nonPrimary = scenes.filter((s) => s !== this._primaryScene);
            return nonPrimary[0] || scenes[0] || null;
        }
        // If a View was passed, derive its window.scene
        if (target && typeof target === 'object') {
            // UIWindowScene
            if (target.session && target.activationState !== undefined) {
                return target;
            }
            // UIWindow
            if (target.windowScene) {
                return target.windowScene;
            }
            // NativeScript View
            if (target?.nativeViewProtected) {
                const uiView = target.nativeViewProtected;
                const win = uiView?.window;
                return win?.windowScene || null;
            }
        }
        // String id lookup
        if (typeof target === 'string') {
            if (this._openedScenesById.has(target)) {
                return this._openedScenesById.get(target);
            }
            // Try matching by persistentIdentifier or hash among known scenes
            const scenes = this.getWindowScenes?.() || [];
            for (const s of scenes) {
                const sid = this._getSceneId(s);
                if (sid === target) {
                    return s;
                }
            }
        }
        return null;
    }
    createSceneWithLegacyAPI(data) {
        const windowScene = this.window?.windowScene;
        if (!windowScene) {
            return;
        }
        // Create user activity for the new scene
        const userActivity = NSUserActivity.alloc().initWithActivityType(`${NSBundle.mainBundle.bundleIdentifier}.scene`);
        userActivity.userInfo = dataSerialize(data);
        // Use the legacy API
        const options = UISceneActivationRequestOptions.new();
        options.requestingScene = windowScene;
        UIApplication.sharedApplication.requestSceneSessionActivationUserActivityOptionsErrorHandler(null, // session - null for new scene
        userActivity, options, (error) => {
            if (error) {
                console.error(`Legacy scene API failed: ${error.localizedDescription}`);
            }
        });
    }
    /**
     * Creates a simple view controller with a NativeScript view for a scene window.
     * @param window The UIWindow to set content for
     * @param view The NativeScript View to set as root content
     */
    setWindowRootView(window, view) {
        if (!window || !view) {
            return;
        }
        if (view.ios) {
            window.rootViewController = view.viewController;
            window.makeKeyAndVisible();
        }
        else {
            console.warn('View does not have a native iOS implementation');
        }
    }
    get ios() {
        // ensures Application.ios is defined when running on iOS
        return this;
    }
}
__decorate([
    profile,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [NSNotification]),
    __metadata("design:returntype", void 0)
], iOSApplication.prototype, "didFinishLaunchingWithOptions", null);
__decorate([
    profile,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [NSNotification]),
    __metadata("design:returntype", void 0)
], iOSApplication.prototype, "didBecomeActive", null);
const iosApp = new iOSApplication();
// Attach on global, so it can also be overwritten to implement different logic based on flavor
global.__onLiveSyncCore = function (context) {
    iosApp._onLivesync(context);
};
export * from './application-common';
export const Application = iosApp;
export const AndroidApplication = undefined;
function fontScaleChanged(origFontScale) {
    const oldValue = getFontScale();
    setFontScale(getClosestValidFontScale(origFontScale));
    const currentFontScale = getFontScale();
    if (oldValue !== currentFontScale) {
        Application.notify({
            eventName: Application.fontScaleChangedEvent,
            object: Application,
            newValue: currentFontScale,
        });
    }
}
export function getCurrentFontScale() {
    setupConfigListener();
    return getFontScale();
}
const sizeMap = new Map([
    [UIContentSizeCategoryExtraSmall, 0.5],
    [UIContentSizeCategorySmall, 0.7],
    [UIContentSizeCategoryMedium, 0.85],
    [UIContentSizeCategoryLarge, 1],
    [UIContentSizeCategoryExtraLarge, 1.15],
    [UIContentSizeCategoryExtraExtraLarge, 1.3],
    [UIContentSizeCategoryExtraExtraExtraLarge, 1.5],
    [UIContentSizeCategoryAccessibilityMedium, 2],
    [UIContentSizeCategoryAccessibilityLarge, 2.5],
    [UIContentSizeCategoryAccessibilityExtraLarge, 3],
    [UIContentSizeCategoryAccessibilityExtraExtraLarge, 3.5],
    [UIContentSizeCategoryAccessibilityExtraExtraExtraLarge, 4],
]);
function contentSizeUpdated(fontSize) {
    if (sizeMap.has(fontSize)) {
        fontScaleChanged(sizeMap.get(fontSize));
        return;
    }
    fontScaleChanged(1);
}
function useIOSFontScale() {
    if (Application.ios.nativeApp) {
        contentSizeUpdated(Application.ios.nativeApp.preferredContentSizeCategory);
    }
    else {
        fontScaleChanged(1);
    }
}
let fontSizeObserver;
function setupConfigListener(attempt = 0) {
    if (fontSizeObserver) {
        return;
    }
    if (!Application.ios.nativeApp) {
        if (attempt > 100) {
            fontScaleChanged(1);
            return;
        }
        // Couldn't get launchEvent to trigger.
        setTimeout(() => setupConfigListener(attempt + 1), 1);
        return;
    }
    fontSizeObserver = Application.ios.addNotificationObserver(UIContentSizeCategoryDidChangeNotification, (args) => {
        const fontSize = args.userInfo.valueForKey(UIContentSizeCategoryNewValueKey);
        contentSizeUpdated(fontSize);
    });
    Application.on(Application.exitEvent, () => {
        if (fontSizeObserver) {
            Application.ios.removeNotificationObserver(fontSizeObserver, UIContentSizeCategoryDidChangeNotification);
            fontSizeObserver = null;
        }
        Application.off(Application.resumeEvent, useIOSFontScale);
    });
    Application.on(Application.resumeEvent, useIOSFontScale);
    useIOSFontScale();
}
setInitFontScale(setupConfigListener);
/**
 * Convert array of values into a bitmask.
 *
 * @param values string values
 * @param map    map lower-case name to integer value.
 */
function inputArrayToBitMask(values, map) {
    return (enforceArray(values)
        .filter((value) => !!value)
        .map((value) => `${value}`.toLocaleLowerCase())
        .filter((value) => map.has(value))
        .reduce((res, value) => res | map.get(value), 0) || 0);
}
let AccessibilityTraitsMap;
let RoleTypeMap;
let nativeFocusedNotificationObserver;
let lastFocusedView;
function ensureNativeClasses() {
    if (AccessibilityTraitsMap && nativeFocusedNotificationObserver) {
        return;
    }
    AccessibilityTraitsMap = new Map([
        [AccessibilityTrait.AllowsDirectInteraction, UIAccessibilityTraitAllowsDirectInteraction],
        [AccessibilityTrait.CausesPageTurn, UIAccessibilityTraitCausesPageTurn],
        [AccessibilityTrait.NotEnabled, UIAccessibilityTraitNotEnabled],
        [AccessibilityTrait.Selected, UIAccessibilityTraitSelected],
        [AccessibilityTrait.UpdatesFrequently, UIAccessibilityTraitUpdatesFrequently],
    ]);
    RoleTypeMap = new Map([
        [AccessibilityRole.Adjustable, UIAccessibilityTraitAdjustable],
        [AccessibilityRole.Button, UIAccessibilityTraitButton],
        [AccessibilityRole.Checkbox, UIAccessibilityTraitButton],
        [AccessibilityRole.Header, UIAccessibilityTraitHeader],
        [AccessibilityRole.KeyboardKey, UIAccessibilityTraitKeyboardKey],
        [AccessibilityRole.Image, UIAccessibilityTraitImage],
        [AccessibilityRole.ImageButton, UIAccessibilityTraitImage | UIAccessibilityTraitButton],
        [AccessibilityRole.Link, UIAccessibilityTraitLink],
        [AccessibilityRole.None, UIAccessibilityTraitNone],
        [AccessibilityRole.PlaysSound, UIAccessibilityTraitPlaysSound],
        [AccessibilityRole.RadioButton, UIAccessibilityTraitButton],
        [AccessibilityRole.Search, UIAccessibilityTraitSearchField],
        [AccessibilityRole.StaticText, UIAccessibilityTraitStaticText],
        [AccessibilityRole.StartsMediaSession, UIAccessibilityTraitStartsMediaSession],
        [AccessibilityRole.Summary, UIAccessibilityTraitSummaryElement],
        [AccessibilityRole.Switch, UIAccessibilityTraitButton],
    ]);
    nativeFocusedNotificationObserver = Application.ios.addNotificationObserver(UIAccessibilityElementFocusedNotification, (args) => {
        const uiView = args.userInfo?.objectForKey(UIAccessibilityFocusedElementKey);
        if (!uiView?.tag) {
            return;
        }
        const rootView = Application.getRootView();
        // We use the UIView's tag to find the NativeScript View by its domId.
        let view = rootView.getViewByDomId(uiView?.tag);
        if (!view) {
            for (const modalView of rootView._getRootModalViews()) {
                view = modalView.getViewByDomId(uiView?.tag);
                if (view) {
                    break;
                }
            }
        }
        if (!view) {
            return;
        }
        const lastView = lastFocusedView?.deref();
        if (lastView && view !== lastView) {
            const lastFocusedUIView = lastView.nativeViewProtected;
            if (lastFocusedUIView) {
                lastFocusedView = null;
                notifyAccessibilityFocusState(lastView, false, true);
            }
        }
        lastFocusedView = new WeakRef(view);
        notifyAccessibilityFocusState(view, true, false);
    });
    Application.on(Application.exitEvent, () => {
        if (nativeFocusedNotificationObserver) {
            Application.ios.removeNotificationObserver(nativeFocusedNotificationObserver, UIAccessibilityElementFocusedNotification);
        }
        nativeFocusedNotificationObserver = null;
        lastFocusedView = null;
    });
}
export function updateAccessibilityProperties(view) {
    const uiView = view.nativeViewProtected;
    if (!uiView) {
        return;
    }
    ensureNativeClasses();
    const accessibilityRole = view.accessibilityRole;
    const accessibilityState = view.accessibilityState;
    if (!view.accessible || view.accessibilityHidden) {
        uiView.accessibilityTraits = UIAccessibilityTraitNone;
        return;
    }
    // NOTE: left here for various core inspection passes while running the toolbox app
    // console.log('--- Accessible element: ', view.constructor.name);
    // console.log('accessibilityLabel: ', view.accessibilityLabel);
    // console.log('accessibilityRole: ', accessibilityRole);
    // console.log('accessibilityState: ', accessibilityState);
    // console.log('accessibilityValue: ', view.accessibilityValue);
    let a11yTraits = UIAccessibilityTraitNone;
    if (RoleTypeMap.has(accessibilityRole)) {
        a11yTraits |= RoleTypeMap.get(accessibilityRole);
    }
    switch (accessibilityRole) {
        case AccessibilityRole.Checkbox:
        case AccessibilityRole.RadioButton:
        case AccessibilityRole.Switch: {
            if (accessibilityState === AccessibilityState.Checked) {
                a11yTraits |= AccessibilityTraitsMap.get(AccessibilityTrait.Selected);
            }
            break;
        }
        default: {
            if (accessibilityState === AccessibilityState.Selected) {
                a11yTraits |= AccessibilityTraitsMap.get(AccessibilityTrait.Selected);
            }
            if (accessibilityState === AccessibilityState.Disabled) {
                a11yTraits |= AccessibilityTraitsMap.get(AccessibilityTrait.NotEnabled);
            }
            break;
        }
    }
    const UpdatesFrequentlyTrait = AccessibilityTraitsMap.get(AccessibilityTrait.UpdatesFrequently);
    switch (view.accessibilityLiveRegion) {
        case AccessibilityLiveRegion.Polite:
        case AccessibilityLiveRegion.Assertive: {
            a11yTraits |= UpdatesFrequentlyTrait;
            break;
        }
        default: {
            a11yTraits &= ~UpdatesFrequentlyTrait;
            break;
        }
    }
    // NOTE: left here for various core inspection passes while running the toolbox app
    // if (view.accessibilityLiveRegion) {
    // 	console.log('accessibilityLiveRegion:', view.accessibilityLiveRegion);
    // }
    if (view.accessibilityMediaSession) {
        a11yTraits |= RoleTypeMap.get(AccessibilityRole.StartsMediaSession);
    }
    // NOTE: There were duplicated types in traits and roles previously which we conslidated
    // not sure if this is still needed
    // accessibilityTraits used to be stored on {N} view component but if the above
    // is combining all traits fresh each time through, don't believe we need to keep track or previous traits
    // if (view.accessibilityTraits) {
    // 	a11yTraits |= inputArrayToBitMask(view.accessibilityTraits, AccessibilityTraitsMap);
    // }
    // NOTE: left here for various core inspection passes while running the toolbox app
    // console.log('a11yTraits:', a11yTraits);
    // console.log('    ');
    uiView.accessibilityTraits = a11yTraits;
}
setA11yUpdatePropertiesCallback(updateAccessibilityProperties);
export const sendAccessibilityEvent = () => { };
export function isAccessibilityServiceEnabled() {
    const accessibilityServiceEnabled = isA11yEnabled();
    if (typeof accessibilityServiceEnabled === 'boolean') {
        return accessibilityServiceEnabled;
    }
    let isVoiceOverRunning;
    if (typeof UIAccessibilityIsVoiceOverRunning === 'function') {
        isVoiceOverRunning = UIAccessibilityIsVoiceOverRunning;
    }
    else {
        // iOS is too old to tell us if voice over is enabled
        if (typeof UIAccessibilityIsVoiceOverRunning !== 'function') {
            setA11yEnabled(false);
            return isA11yEnabled();
        }
    }
    setA11yEnabled(isVoiceOverRunning());
    let voiceOverStatusChangedNotificationName = null;
    if (typeof UIAccessibilityVoiceOverStatusDidChangeNotification !== 'undefined') {
        voiceOverStatusChangedNotificationName = UIAccessibilityVoiceOverStatusDidChangeNotification;
    }
    else if (typeof UIAccessibilityVoiceOverStatusChanged !== 'undefined') {
        voiceOverStatusChangedNotificationName = UIAccessibilityVoiceOverStatusChanged;
    }
    if (voiceOverStatusChangedNotificationName) {
        nativeObserver = Application.ios.addNotificationObserver(voiceOverStatusChangedNotificationName, () => {
            setA11yEnabled(isVoiceOverRunning());
        });
        Application.on(Application.exitEvent, () => {
            if (nativeObserver) {
                Application.ios.removeNotificationObserver(nativeObserver, voiceOverStatusChangedNotificationName);
            }
            setA11yEnabled(undefined);
            nativeObserver = null;
        });
    }
    Application.on(Application.resumeEvent, () => {
        setA11yEnabled(isVoiceOverRunning());
    });
    return isA11yEnabled();
}
export function getAndroidAccessibilityManager() {
    return null;
}
let sharedA11YObservable;
let nativeObserver;
function getSharedA11YObservable() {
    if (sharedA11YObservable) {
        return sharedA11YObservable;
    }
    sharedA11YObservable = new SharedA11YObservable();
    let isVoiceOverRunning;
    if (typeof UIAccessibilityIsVoiceOverRunning === 'function') {
        isVoiceOverRunning = UIAccessibilityIsVoiceOverRunning;
    }
    else {
        if (typeof UIAccessibilityIsVoiceOverRunning !== 'function') {
            Trace.write(`UIAccessibilityIsVoiceOverRunning() - is not a function`, Trace.categories.Accessibility, Trace.messageType.error);
            isVoiceOverRunning = () => false;
        }
    }
    sharedA11YObservable.set(AccessibilityServiceEnabledPropName, isVoiceOverRunning());
    let voiceOverStatusChangedNotificationName = null;
    if (typeof UIAccessibilityVoiceOverStatusDidChangeNotification !== 'undefined') {
        // iOS 11+
        voiceOverStatusChangedNotificationName = UIAccessibilityVoiceOverStatusDidChangeNotification;
    }
    else if (typeof UIAccessibilityVoiceOverStatusChanged !== 'undefined') {
        // iOS <11
        voiceOverStatusChangedNotificationName = UIAccessibilityVoiceOverStatusChanged;
    }
    if (voiceOverStatusChangedNotificationName) {
        nativeObserver = Application.ios.addNotificationObserver(voiceOverStatusChangedNotificationName, () => {
            sharedA11YObservable?.set(AccessibilityServiceEnabledPropName, isVoiceOverRunning());
        });
        Application.on(Application.exitEvent, () => {
            if (nativeObserver) {
                Application.ios.removeNotificationObserver(nativeObserver, voiceOverStatusChangedNotificationName);
            }
            nativeObserver = null;
            if (sharedA11YObservable) {
                sharedA11YObservable.removeEventListener(Observable.propertyChangeEvent);
                sharedA11YObservable = null;
            }
        });
    }
    Application.on(Application.resumeEvent, () => sharedA11YObservable.set(AccessibilityServiceEnabledPropName, isVoiceOverRunning()));
    return sharedA11YObservable;
}
export class AccessibilityServiceEnabledObservable extends CommonA11YServiceEnabledObservable {
    constructor() {
        super(getSharedA11YObservable());
    }
}
let accessibilityServiceObservable;
export function ensureClasses() {
    if (accessibilityServiceObservable) {
        return;
    }
    setFontScaleCssClasses(new Map(VALID_FONT_SCALES.map((fs) => [fs, `a11y-fontscale-${Number(fs * 100).toFixed(0)}`])));
    accessibilityServiceObservable = new AccessibilityServiceEnabledObservable();
    // Initialize SDK version CSS class once
    initializeSdkVersionClass(Application.getRootView());
}
export function updateCurrentHelperClasses(applyRootCssClass) {
    const fontScale = getFontScale();
    const fontScaleCategory = getFontScaleCategory();
    const fontScaleCssClasses = getFontScaleCssClasses();
    const oldFontScaleClass = getCurrentFontScaleClass();
    if (fontScaleCssClasses.has(fontScale)) {
        setCurrentFontScaleClass(fontScaleCssClasses.get(fontScale));
    }
    else {
        setCurrentFontScaleClass(fontScaleCssClasses.get(1));
    }
    if (oldFontScaleClass !== getCurrentFontScaleClass()) {
        applyRootCssClass([...fontScaleCssClasses.values()], getCurrentFontScaleClass());
    }
    const oldActiveFontScaleCategory = getCurrentFontScaleCategory();
    switch (fontScaleCategory) {
        case FontScaleCategory.ExtraSmall: {
            setCurrentFontScaleCategory(fontScaleExtraSmallCategoryClass);
            break;
        }
        case FontScaleCategory.Medium: {
            setCurrentFontScaleCategory(fontScaleMediumCategoryClass);
            break;
        }
        case FontScaleCategory.ExtraLarge: {
            setCurrentFontScaleCategory(fontScaleExtraLargeCategoryClass);
            break;
        }
        default: {
            setCurrentFontScaleCategory(fontScaleMediumCategoryClass);
            break;
        }
    }
    if (oldActiveFontScaleCategory !== getCurrentFontScaleCategory()) {
        applyRootCssClass(fontScaleCategoryClasses, getCurrentFontScaleCategory());
    }
    const oldA11YStatusClass = getCurrentA11YServiceClass();
    if (accessibilityServiceObservable.accessibilityServiceEnabled) {
        setCurrentA11YServiceClass(a11yServiceEnabledClass);
    }
    else {
        setCurrentA11YServiceClass(a11yServiceDisabledClass);
    }
    if (oldA11YStatusClass !== getCurrentA11YServiceClass()) {
        applyRootCssClass(a11yServiceClasses, getCurrentA11YServiceClass());
    }
}
function applyRootCssClass(cssClasses, newCssClass) {
    const rootView = Application.getRootView();
    if (!rootView) {
        return;
    }
    Application.applyCssClass(rootView, cssClasses, newCssClass);
    const rootModalViews = rootView._getRootModalViews();
    rootModalViews.forEach((rootModalView) => Application.applyCssClass(rootModalView, cssClasses, newCssClass));
}
function applyFontScaleToRootViews() {
    const rootView = Application.getRootView();
    if (!rootView) {
        return;
    }
    const fontScale = getCurrentFontScale();
    rootView.style.fontScaleInternal = fontScale;
    const rootModalViews = rootView._getRootModalViews();
    rootModalViews.forEach((rootModalView) => (rootModalView.style.fontScaleInternal = fontScale));
}
export function initAccessibilityCssHelper() {
    ensureClasses();
    updateCurrentHelperClasses(applyRootCssClass);
    applyFontScaleToRootViews();
    Application.on(Application.fontScaleChangedEvent, () => {
        updateCurrentHelperClasses(applyRootCssClass);
        applyFontScaleToRootViews();
    });
    accessibilityServiceObservable.on(AccessibilityServiceEnabledObservable.propertyChangeEvent, () => updateCurrentHelperClasses(applyRootCssClass));
}
setInitAccessibilityCssHelper(initAccessibilityCssHelper);
const applicationEvents = [Application.orientationChangedEvent, Application.systemAppearanceChangedEvent];
function toggleApplicationEventListeners(toAdd, callback) {
    for (const eventName of applicationEvents) {
        if (toAdd) {
            Application.on(eventName, callback);
        }
        else {
            Application.off(eventName, callback);
        }
    }
}
setToggleApplicationEventListenersCallback(toggleApplicationEventListeners);
setApplicationPropertiesCallback(() => {
    return {
        orientation: Application.orientation(),
        systemAppearance: Application.systemAppearance(),
    };
});
//# sourceMappingURL=application.ios.js.map