// Requires
import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty, testIDProperty } from './view-common';
import { hiddenProperty } from '../view-base';
import { Trace } from '../../../trace';
import { layout, ios as iosUtils, SDK_VERSION } from '../../../utils';
import { IOSHelper } from './view-helper';
import { ios as iosBackground } from '../../styling/background';
import { perspectiveProperty, visibilityProperty, opacityProperty, rotateProperty, rotateXProperty, rotateYProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty } from '../../styling/style-properties';
import { profile } from '../../../profiling';
import { accessibilityEnabledProperty, accessibilityHiddenProperty, accessibilityHintProperty, accessibilityIdentifierProperty, accessibilityLabelProperty, accessibilityLanguageProperty, accessibilityLiveRegionProperty, accessibilityMediaSessionProperty, accessibilityRoleProperty, accessibilityStateProperty, accessibilityValueProperty, accessibilityIgnoresInvertColorsProperty } from '../../../accessibility/accessibility-properties';
import { IOSPostAccessibilityNotificationType, isAccessibilityServiceEnabled, updateAccessibilityProperties } from '../../../accessibility';
import { CoreTypes } from '../../../core-types';
import { SharedTransition } from '../../transition/shared-transition';
export * from './view-common';
// helpers (these are okay re-exported here)
export * from './view-helper';
// This one can eventually be cleaned up but causes issues with a lot of ui-suite plugins in particular if not exported here
export * from '../properties';
const PFLAG_FORCE_LAYOUT = 1;
const PFLAG_MEASURED_DIMENSION_SET = 1 << 1;
const PFLAG_LAYOUT_REQUIRED = 1 << 2;
export class View extends ViewCommon {
    constructor() {
        super(...arguments);
        this._isLaidOut = false;
        this._hasTransform = false;
        this._hasPendingTransform = false;
        this._privateFlags = PFLAG_LAYOUT_REQUIRED | PFLAG_FORCE_LAYOUT;
        this._suspendCATransaction = false;
    }
    get isLayoutRequired() {
        return (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
    }
    get isLayoutRequested() {
        return (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT;
    }
    disposeNativeView() {
        super.disposeNativeView();
        this._cachedFrame = null;
        this._isLaidOut = false;
        this._hasTransform = false;
        this._hasPendingTransform = false;
    }
    requestLayout() {
        this._privateFlags |= PFLAG_FORCE_LAYOUT;
        super.requestLayout();
        const nativeView = this.nativeViewProtected;
        if (nativeView && nativeView.setNeedsLayout) {
            nativeView.setNeedsLayout();
        }
        if (this.viewController && this.viewController.view !== nativeView) {
            this.viewController.view.setNeedsLayout();
        }
    }
    measure(widthMeasureSpec, heightMeasureSpec) {
        const measureSpecsChanged = this._setCurrentMeasureSpecs(widthMeasureSpec, heightMeasureSpec);
        const forceLayout = (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT;
        if (this.nativeViewProtected && (forceLayout || measureSpecsChanged)) {
            // first clears the measured dimension flag
            this._privateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
            // measure ourselves, this should set the measured dimension flag back
            this.onMeasure(widthMeasureSpec, heightMeasureSpec);
            this._privateFlags |= PFLAG_LAYOUT_REQUIRED;
            // flag not set, setMeasuredDimension() was not invoked, we trace
            // the exception to warn the developer
            if ((this._privateFlags & PFLAG_MEASURED_DIMENSION_SET) !== PFLAG_MEASURED_DIMENSION_SET) {
                if (Trace.isEnabled()) {
                    Trace.write('onMeasure() did not set the measured dimension by calling setMeasuredDimension() ' + this, Trace.categories.Layout, Trace.messageType.error);
                }
            }
        }
    }
    layout(left, top, right, bottom, setFrame = true) {
        const result = this._setCurrentLayoutBounds(left, top, right, bottom);
        let { sizeChanged } = result;
        if (setFrame) {
            this.layoutNativeView(left, top, right, bottom);
        }
        const needsLayout = result.boundsChanged || (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
        if (needsLayout) {
            let position;
            if (this.nativeViewProtected && SDK_VERSION > 10) {
                // on iOS 11+ it is possible to have a changed layout frame due to safe area insets
                // get the frame and adjust the position, so that onLayout works correctly
                position = IOSHelper.getPositionFromFrame(this.nativeViewProtected.frame);
                if (!sizeChanged) {
                    // If frame has actually changed, there is the need to update view background and border styles as they depend on native view bounds
                    // To trigger the needed visual update, mark size as changed
                    if (position.left !== left || position.top !== top || position.right !== right || position.bottom !== bottom) {
                        sizeChanged = true;
                    }
                }
            }
            else {
                position = { left, top, right, bottom };
            }
            this.onLayout(position.left, position.top, position.right, position.bottom);
            this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED;
        }
        this.updateBackground(sizeChanged, needsLayout);
        if (this._hasPendingTransform) {
            this.updateNativeTransform();
            this._hasPendingTransform = false;
        }
        this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
    }
    updateBackground(sizeChanged, needsLayout) {
        if (sizeChanged) {
            this._onSizeChanged();
        }
        else if (this._nativeBackgroundState === 'invalid') {
            const background = this.style.backgroundInternal;
            this._redrawNativeBackground(background);
        }
        else {
            // Update layers that don't belong to view's layer (e.g. shadow layers)
            if (needsLayout) {
                this.layoutOuterShadows();
            }
        }
    }
    layoutOuterShadows() {
        const nativeView = this.nativeViewProtected;
        if (nativeView?.outerShadowContainerLayer) {
            CATransaction.setDisableActions(true);
            nativeView.outerShadowContainerLayer.bounds = nativeView.bounds;
            nativeView.outerShadowContainerLayer.position = nativeView.center;
            CATransaction.setDisableActions(false);
        }
    }
    setMeasuredDimension(measuredWidth, measuredHeight) {
        super.setMeasuredDimension(measuredWidth, measuredHeight);
        this._privateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }
    onMeasure(widthMeasureSpec, heightMeasureSpec) {
        const view = this.nativeViewProtected;
        const width = layout.getMeasureSpecSize(widthMeasureSpec);
        const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
        const height = layout.getMeasureSpecSize(heightMeasureSpec);
        const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
        let nativeWidth = 0;
        let nativeHeight = 0;
        if (view) {
            const nativeSize = layout.measureNativeView(view, width, widthMode, height, heightMode);
            nativeWidth = nativeSize.width;
            nativeHeight = nativeSize.height;
        }
        const measureWidth = Math.max(nativeWidth, this.effectiveMinWidth);
        const measureHeight = Math.max(nativeHeight, this.effectiveMinHeight);
        const widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0);
        const heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0);
        this.setMeasuredDimension(widthAndState, heightAndState);
    }
    onLayout(left, top, right, bottom) {
        //
    }
    _setNativeViewFrame(nativeView, frame) {
        const oldFrame = this._cachedFrame || nativeView.frame;
        if (!CGRectEqualToRect(oldFrame, frame)) {
            if (Trace.isEnabled()) {
                Trace.write(this + ' :_setNativeViewFrame: ' + JSON.stringify(IOSHelper.getPositionFromFrame(frame)), Trace.categories.Layout);
            }
            this._cachedFrame = frame;
            let adjustedFrame = null;
            let transform = null;
            if (this._hasTransform) {
                // Always set identity transform before setting frame;
                transform = nativeView.layer.transform;
                nativeView.layer.transform = CATransform3DIdentity;
                nativeView.frame = frame;
            }
            else {
                nativeView.frame = frame;
            }
            adjustedFrame = this.applySafeAreaInsets(frame);
            if (adjustedFrame) {
                nativeView.frame = adjustedFrame;
            }
            if (this._hasTransform) {
                // re-apply the transform after the frame is adjusted
                nativeView.layer.transform = transform;
            }
            const boundsOrigin = nativeView.bounds.origin;
            const boundsFrame = adjustedFrame || frame;
            nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, boundsFrame.size.width, boundsFrame.size.height);
            nativeView.layoutIfNeeded();
            this._raiseLayoutChangedEvent();
            this._isLaidOut = true;
        }
        else if (!this._isLaidOut) {
            // Rects could be equal on the first layout and an event should be raised.
            this._raiseLayoutChangedEvent();
            // But make sure event is raised only once if rects are equal on the first layout as
            // this method is called twice with equal rects in landscape mode (vs only once in portrait)
            this._isLaidOut = true;
        }
    }
    get isLayoutValid() {
        if (this.nativeViewProtected) {
            return this._isLayoutValid;
        }
        return false;
    }
    layoutNativeView(left, top, right, bottom) {
        if (!this.nativeViewProtected) {
            return;
        }
        const nativeView = this.nativeViewProtected;
        const frame = IOSHelper.getFrameFromPosition({
            left,
            top,
            right,
            bottom,
        });
        this._setNativeViewFrame(nativeView, frame);
    }
    _layoutParent() {
        if (this.nativeViewProtected) {
            const frame = this.nativeViewProtected.frame;
            const origin = frame.origin;
            const size = frame.size;
            const left = layout.toDevicePixels(origin.x);
            const top = layout.toDevicePixels(origin.y);
            const width = layout.toDevicePixels(size.width);
            const height = layout.toDevicePixels(size.height);
            this._setLayoutFlags(left, top, width + left, height + top);
        }
        super._layoutParent();
    }
    _setLayoutFlags(left, top, right, bottom) {
        const width = right - left;
        const height = bottom - top;
        const widthSpec = layout.makeMeasureSpec(width, layout.EXACTLY);
        const heightSpec = layout.makeMeasureSpec(height, layout.EXACTLY);
        this._setCurrentMeasureSpecs(widthSpec, heightSpec);
        this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
        this.setMeasuredDimension(width, height);
        const { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
        this.updateBackground(sizeChanged, boundsChanged);
        this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED;
    }
    focus() {
        if (this.ios) {
            return this.ios.becomeFirstResponder();
        }
        return false;
    }
    applySafeAreaInsets(frame) {
        if (!__VISIONOS__ && SDK_VERSION <= 10) {
            return null;
        }
        if (this.iosIgnoreSafeArea) {
            return frame;
        }
        if (!this.iosOverflowSafeArea || !this.iosOverflowSafeAreaEnabled) {
            return IOSHelper.shrinkToSafeArea(this, frame);
        }
        else if (this.nativeViewProtected && this.nativeViewProtected.window) {
            return IOSHelper.expandBeyondSafeArea(this, frame);
        }
        return null;
    }
    getSafeAreaInsets() {
        const safeAreaInsets = this.nativeViewProtected && this.nativeViewProtected.safeAreaInsets;
        const insets = { left: 0, top: 0, right: 0, bottom: 0 };
        if (this.iosIgnoreSafeArea) {
            return insets;
        }
        if (safeAreaInsets) {
            insets.left = layout.round(layout.toDevicePixels(safeAreaInsets.left));
            insets.top = layout.round(layout.toDevicePixels(safeAreaInsets.top));
            insets.right = layout.round(layout.toDevicePixels(safeAreaInsets.right));
            insets.bottom = layout.round(layout.toDevicePixels(safeAreaInsets.bottom));
        }
        return insets;
    }
    getLocationInWindow() {
        if (!this.nativeViewProtected || !this.nativeViewProtected.window) {
            return undefined;
        }
        const pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
        return {
            x: pointInWindow.x,
            y: pointInWindow.y,
        };
    }
    getLocationOnScreen() {
        if (!this.nativeViewProtected || !this.nativeViewProtected.window) {
            return undefined;
        }
        const pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
        const pointOnScreen = this.nativeViewProtected.window.convertPointToWindow(pointInWindow, null);
        return {
            x: pointOnScreen.x,
            y: pointOnScreen.y,
        };
    }
    getLocationRelativeTo(otherView) {
        if (!this.nativeViewProtected || !this.nativeViewProtected.window || !otherView.nativeViewProtected || !otherView.nativeViewProtected.window || this.nativeViewProtected.window !== otherView.nativeViewProtected.window) {
            return undefined;
        }
        const myPointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
        const otherPointInWindow = otherView.nativeViewProtected.convertPointToView(otherView.nativeViewProtected.bounds.origin, null);
        return {
            x: myPointInWindow.x - otherPointInWindow.x,
            y: myPointInWindow.y - otherPointInWindow.y,
        };
    }
    _onSizeChanged() {
        const nativeView = this.nativeViewProtected;
        if (!nativeView) {
            return;
        }
        const background = this.style.backgroundInternal;
        const backgroundDependsOnSize = (background.image && background.image !== 'none') || background.clipPath || !background.hasUniformBorder() || background.hasBorderRadius() || background.hasBoxShadow();
        if (this._nativeBackgroundState === 'invalid' || (this._nativeBackgroundState === 'drawn' && backgroundDependsOnSize)) {
            this._redrawNativeBackground(background);
        }
    }
    updateNativeTransform() {
        if (!this.isLayoutValid) {
            this._hasPendingTransform = true;
            return;
        }
        const scaleX = this.scaleX || 1e-6;
        const scaleY = this.scaleY || 1e-6;
        const perspective = this.perspective || 300;
        const nativeView = this.nativeViewProtected;
        let transform = new CATransform3D(CATransform3DIdentity);
        // Only set perspective if there is 3D rotation
        if (this.rotateX || this.rotateY) {
            transform.m34 = -1 / perspective;
        }
        transform = CATransform3DTranslate(transform, this.translateX, this.translateY, 0);
        transform = iosUtils.applyRotateTransform(transform, this.rotateX, this.rotateY, this.rotate);
        transform = CATransform3DScale(transform, scaleX, scaleY, 1);
        const needsTransform = !CATransform3DEqualToTransform(this.nativeViewProtected.layer.transform, transform) || (nativeView.outerShadowContainerLayer && !CATransform3DEqualToTransform(nativeView.outerShadowContainerLayer.transform, transform));
        if (needsTransform) {
            const updateSuspended = this._isPresentationLayerUpdateSuspended();
            if (!updateSuspended) {
                CATransaction.begin();
            }
            // Disable CALayer animatable property changes
            CATransaction.setDisableActions(true);
            this.nativeViewProtected.layer.transform = transform;
            if (nativeView.outerShadowContainerLayer) {
                nativeView.outerShadowContainerLayer.transform = transform;
            }
            this._hasTransform = this.nativeViewProtected && !CATransform3DEqualToTransform(this.nativeViewProtected.transform3D, CATransform3DIdentity);
            CATransaction.setDisableActions(false);
            if (!updateSuspended) {
                CATransaction.commit();
            }
        }
    }
    updateOriginPoint(originX, originY) {
        const nativeView = this.nativeViewProtected;
        const newPoint = CGPointMake(originX, originY);
        // Disable CALayer animatable property changes
        CATransaction.setDisableActions(true);
        nativeView.layer.anchorPoint = newPoint;
        // Bounds have to be recalculated after anchor point update
        if (this._cachedFrame) {
            const frame = this._cachedFrame;
            this._cachedFrame = null;
            this._setNativeViewFrame(nativeView, frame);
        }
        // Make sure new origin also applies to outer shadow layers
        if (nativeView.outerShadowContainerLayer) {
            // This is the new frame after view origin point update
            const frame = nativeView.frame;
            nativeView.outerShadowContainerLayer.anchorPoint = newPoint;
            nativeView.outerShadowContainerLayer.position = CGPointMake(frame.origin.x + frame.size.width * originX, frame.origin.y + frame.size.height * originY);
        }
        CATransaction.setDisableActions(false);
    }
    // By default we update the view's presentation layer when setting backgroundColor and opacity properties.
    // This is done by calling CATransaction begin and commit methods.
    // This action should be disabled when updating those properties during an animation.
    _suspendPresentationLayerUpdates() {
        this._suspendCATransaction = true;
    }
    _resumePresentationLayerUpdates() {
        this._suspendCATransaction = false;
    }
    _isPresentationLayerUpdateSuspended() {
        return this._suspendCATransaction || this._suspendNativeUpdatesCount > 0;
    }
    _showNativeModalView(parent, options) {
        const parentWithController = IOSHelper.getParentWithViewController(parent);
        if (!parentWithController) {
            Trace.write(`Could not find parent with viewController for ${parent} while showing modal view.`, Trace.categories.ViewHierarchy, Trace.messageType.error);
            return;
        }
        const parentController = parentWithController.viewController;
        if (parentController.presentedViewController) {
            Trace.write('Parent is already presenting view controller. Close the current modal page before showing another one!', Trace.categories.ViewHierarchy, Trace.messageType.error);
            return;
        }
        if (!parentController.view || !parentController.view.window) {
            Trace.write('Parent page is not part of the window hierarchy.', Trace.categories.ViewHierarchy, Trace.messageType.error);
            return;
        }
        this._setupAsRootView({});
        super._showNativeModalView(parentWithController, options);
        let controller = this.viewController;
        if (!controller) {
            const nativeView = this.ios || this.nativeViewProtected;
            controller = IOSHelper.UILayoutViewController.initWithOwner(new WeakRef(this));
            if (nativeView instanceof UIView) {
                controller.view.addSubview(nativeView);
            }
            this.viewController = controller;
        }
        if (options.transition) {
            controller.modalPresentationStyle = 4 /* UIModalPresentationStyle.Custom */;
            if (options.transition.instance) {
                this._transitioningDelegate = UIViewControllerTransitioningDelegateImpl.initWithOwner(new WeakRef(options.transition.instance));
                controller.transitioningDelegate = this._transitioningDelegate;
                this.transitionId = options.transition.instance.id;
                const transitionState = SharedTransition.getState(options.transition.instance.id);
                if (transitionState?.interactive?.dismiss) {
                    // interactive transitions via gestures
                    // TODO - these could be typed as: boolean | (view: View) => void
                    // to allow users to define their own custom gesture dismissals
                    options.transition.instance.setupInteractiveGesture(this._closeModalCallback.bind(this), this);
                }
            }
        }
        else if (options.fullscreen) {
            controller.modalPresentationStyle = 0 /* UIModalPresentationStyle.FullScreen */;
        }
        else {
            controller.modalPresentationStyle = 2 /* UIModalPresentationStyle.FormSheet */;
            //check whether both height and width is provided and are positive numbers
            // set it has prefered content size to the controller presenting the dialog
            if (options.ios && options.ios.width > 0 && options.ios.height > 0) {
                controller.preferredContentSize = CGSizeMake(options.ios.width, options.ios.height);
            }
            else {
                //use CSS & attribute width & height if option is not provided
                const handler = () => {
                    if (this.viewController) {
                        const w = (this.width || this.style.width);
                        const h = (this.height || this.style.height);
                        //TODO: only numeric value is supported, percentage value is not supported like Android
                        if (w > 0 && h > 0) {
                            this.viewController.preferredContentSize = CGSizeMake(w, h);
                        }
                    }
                    this.off(View.loadedEvent, handler);
                };
                this.on(View.loadedEvent, handler);
            }
        }
        if (options.ios && options.ios.presentationStyle) {
            const presentationStyle = options.ios.presentationStyle;
            controller.modalPresentationStyle = presentationStyle;
            if (presentationStyle === 7 /* UIModalPresentationStyle.Popover */) {
                this._setupPopoverControllerDelegate(controller, parent);
            }
        }
        const cancelable = options.cancelable !== undefined ? !!options.cancelable : true;
        if (SDK_VERSION >= 13) {
            if (cancelable) {
                // Listen for dismiss modal callback.
                this._setupAdaptiveControllerDelegate(controller);
            }
            else {
                // Prevent users from dismissing the modal.
                controller.modalInPresentation = true;
            }
        }
        this.horizontalAlignment = 'stretch';
        this.verticalAlignment = 'stretch';
        this._raiseShowingModallyEvent();
        const animated = options.animated === undefined ? true : !!options.animated;
        if (!this._modalAnimatedOptions) {
            // track the user's animated options to use upon close as well
            this._modalAnimatedOptions = [];
        }
        this._modalAnimatedOptions.push(animated);
        // TODO: a11y
        // controller.accessibilityViewIsModal = true;
        // controller.accessibilityPerformEscape = () => {
        //   console.log('accessibilityPerformEscape!!')
        //   return true;
        // }
        parentController.presentViewControllerAnimatedCompletion(controller, animated, null);
        const transitionCoordinator = parentController.transitionCoordinator;
        if (transitionCoordinator) {
            transitionCoordinator.animateAlongsideTransitionCompletion(null, () => {
                setTimeout(() => {
                    // ensure raised on main queue
                    this._raiseShownModallyEvent();
                });
            });
        }
        else {
            // Apparently iOS 9+ stops all transitions and animations upon application suspend and transitionCoordinator becomes null here in this case.
            // Since we are not waiting for any transition to complete, i.e. transitionCoordinator is null, we can directly raise our shownModally event.
            // Take a look at https://github.com/NativeScript/NativeScript/issues/2173 for more info and a sample project.
            this._raiseShownModallyEvent();
        }
        controller = null;
    }
    _hideNativeModalView(parent, whenClosedCallback) {
        if (!parent || !parent.viewController) {
            Trace.error('Trying to hide modal view but no parent with viewController specified.');
            return;
        }
        // modal view has already been closed by UI, probably as a popover
        if (!parent.viewController.presentedViewController) {
            whenClosedCallback();
            return;
        }
        const parentController = parent.viewController;
        let animated = true;
        if (this._modalAnimatedOptions?.length) {
            animated = this._modalAnimatedOptions.slice(-1)[0];
        }
        parentController.dismissViewControllerAnimatedCompletion(animated, () => {
            const transitionState = SharedTransition.getState(this.transitionId);
            if (!transitionState?.interactiveCancelled) {
                this._transitioningDelegate = null;
                // this.off('pan', this._interactiveDismissGesture);
                if (this._modalAnimatedOptions) {
                    this._modalAnimatedOptions.pop();
                }
            }
            whenClosedCallback();
        });
    }
    [isEnabledProperty.getDefault]() {
        const nativeView = this.nativeViewProtected;
        return nativeView instanceof UIControl ? nativeView.enabled : true;
    }
    [isEnabledProperty.setNative](value) {
        const nativeView = this.nativeViewProtected;
        if (nativeView instanceof UIControl) {
            nativeView.enabled = value;
        }
    }
    [originXProperty.getDefault]() {
        return this.nativeViewProtected.layer.anchorPoint.x;
    }
    [originXProperty.setNative](value) {
        this.updateOriginPoint(value, this.originY);
    }
    [originYProperty.getDefault]() {
        return this.nativeViewProtected.layer.anchorPoint.y;
    }
    [originYProperty.setNative](value) {
        this.updateOriginPoint(this.originX, value);
    }
    [testIDProperty.setNative](value) {
        this.setAccessibilityIdentifier(this.nativeViewProtected, value);
    }
    setAccessibilityIdentifier(view, value) {
        view.accessibilityIdentifier = value;
        if (this.testID && this.testID !== value)
            this.testID = value;
        if (this.accessibilityIdentifier !== value)
            this.accessibilityIdentifier = value;
    }
    [accessibilityEnabledProperty.setNative](value) {
        this.nativeViewProtected.isAccessibilityElement = !!value;
        updateAccessibilityProperties(this);
    }
    [accessibilityIdentifierProperty.getDefault]() {
        return this.nativeViewProtected.accessibilityIdentifier;
    }
    [accessibilityIdentifierProperty.setNative](value) {
        this.setAccessibilityIdentifier(this.nativeViewProtected, value);
    }
    [accessibilityRoleProperty.setNative](value) {
        this.accessibilityRole = value;
        updateAccessibilityProperties(this);
    }
    [accessibilityValueProperty.setNative](value) {
        value = value == null ? null : `${value}`;
        this.nativeViewProtected.accessibilityValue = value;
    }
    [accessibilityLabelProperty.setNative](value) {
        value = value == null ? null : `${value}`;
        // not sure if needed for Label:
        // if ((<any>this).nativeTextViewProtected) {
        //   (<any>this).nativeTextViewProtected.accessibilityLabel = value;
        // } else {
        this.nativeViewProtected.accessibilityLabel = value;
        // }
    }
    [accessibilityHintProperty.setNative](value) {
        value = value == null ? null : `${value}`;
        this.nativeViewProtected.accessibilityHint = value;
    }
    [accessibilityIgnoresInvertColorsProperty.setNative](value) {
        this.nativeViewProtected.accessibilityIgnoresInvertColors = !!value;
    }
    [accessibilityLanguageProperty.setNative](value) {
        value = value == null ? null : `${value}`;
        this.nativeViewProtected.accessibilityLanguage = value;
    }
    [accessibilityHiddenProperty.setNative](value) {
        this.nativeViewProtected.accessibilityElementsHidden = !!value;
        updateAccessibilityProperties(this);
    }
    [accessibilityLiveRegionProperty.setNative]() {
        updateAccessibilityProperties(this);
    }
    [accessibilityStateProperty.setNative](value) {
        this.accessibilityState = value;
        updateAccessibilityProperties(this);
    }
    [accessibilityMediaSessionProperty.setNative]() {
        updateAccessibilityProperties(this);
    }
    [isUserInteractionEnabledProperty.getDefault]() {
        return this.nativeViewProtected.userInteractionEnabled;
    }
    [isUserInteractionEnabledProperty.setNative](value) {
        this.nativeViewProtected.userInteractionEnabled = value;
    }
    [hiddenProperty.getDefault]() {
        return this.nativeViewProtected.hidden;
    }
    [hiddenProperty.setNative](value) {
        this.nativeViewProtected.hidden = value;
    }
    [visibilityProperty.getDefault]() {
        return this.nativeViewProtected.hidden ? CoreTypes.Visibility.collapse : CoreTypes.Visibility.visible;
    }
    [visibilityProperty.setNative](value) {
        const nativeView = this.nativeViewProtected;
        switch (value) {
            case CoreTypes.Visibility.visible:
                nativeView.hidden = false;
                break;
            case CoreTypes.Visibility.hidden:
            case CoreTypes.Visibility.collapse:
                nativeView.hidden = true;
                break;
            default:
                throw new Error(`Invalid visibility value: ${value}. Valid values are: "${CoreTypes.Visibility.visible}", "${CoreTypes.Visibility.hidden}", "${CoreTypes.Visibility.collapse}".`);
        }
        // Apply visibility value to shadows as well
        if (nativeView.outerShadowContainerLayer) {
            nativeView.outerShadowContainerLayer.hidden = nativeView.hidden;
        }
    }
    [opacityProperty.getDefault]() {
        return this.nativeViewProtected.alpha;
    }
    [opacityProperty.setNative](value) {
        const nativeView = this.nativeViewProtected;
        const updateSuspended = this._isPresentationLayerUpdateSuspended();
        if (!updateSuspended) {
            CATransaction.begin();
        }
        // Disable CALayer animatable property changes
        CATransaction.setDisableActions(true);
        nativeView.alpha = value;
        // Apply opacity value to shadows as well
        if (nativeView.outerShadowContainerLayer) {
            nativeView.outerShadowContainerLayer.opacity = value;
        }
        CATransaction.setDisableActions(false);
        if (!updateSuspended) {
            CATransaction.commit();
        }
    }
    [rotateProperty.getDefault]() {
        return 0;
    }
    [rotateProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [rotateXProperty.getDefault]() {
        return 0;
    }
    [rotateXProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [rotateYProperty.getDefault]() {
        return 0;
    }
    [rotateYProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [perspectiveProperty.getDefault]() {
        return 300;
    }
    [perspectiveProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [scaleXProperty.getDefault]() {
        return 1;
    }
    [scaleXProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [scaleYProperty.getDefault]() {
        return 1;
    }
    [scaleYProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [translateXProperty.getDefault]() {
        return 0;
    }
    [translateXProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [translateYProperty.getDefault]() {
        return 0;
    }
    [translateYProperty.setNative](value) {
        this.updateNativeTransform();
    }
    [zIndexProperty.getDefault]() {
        return 0;
    }
    [zIndexProperty.setNative](value) {
        const nativeView = this.nativeViewProtected;
        nativeView.layer.zPosition = value;
        // Apply z-index to shadows as well
        if (nativeView.outerShadowContainerLayer) {
            nativeView.outerShadowContainerLayer.zPosition = value;
        }
    }
    [backgroundInternalProperty.getDefault]() {
        return this.nativeViewProtected.backgroundColor;
    }
    [backgroundInternalProperty.setNative](value) {
        this._nativeBackgroundState = 'invalid';
        if (this.isLayoutValid) {
            this._redrawNativeBackground(value);
        }
    }
    sendAccessibilityEvent(options) {
        if (!isAccessibilityServiceEnabled()) {
            return;
        }
        if (!options.iosNotificationType) {
            return;
        }
        let notification;
        let args = this.nativeViewProtected;
        if (options?.message) {
            args = options.message;
        }
        switch (options.iosNotificationType) {
            case IOSPostAccessibilityNotificationType.Announcement: {
                notification = UIAccessibilityAnnouncementNotification;
                break;
            }
            case IOSPostAccessibilityNotificationType.Layout: {
                notification = UIAccessibilityLayoutChangedNotification;
                break;
            }
            case IOSPostAccessibilityNotificationType.Screen: {
                notification = UIAccessibilityScreenChangedNotification;
                break;
            }
            default: {
                return;
            }
        }
        UIAccessibilityPostNotification(notification, args ?? null);
    }
    accessibilityAnnouncement(msg = this.accessibilityLabel) {
        this.sendAccessibilityEvent({
            iosNotificationType: IOSPostAccessibilityNotificationType.Announcement,
            message: msg,
        });
    }
    accessibilityScreenChanged() {
        this.sendAccessibilityEvent({
            iosNotificationType: IOSPostAccessibilityNotificationType.Screen,
        });
    }
    _getCurrentLayoutBounds() {
        const nativeView = this.nativeViewProtected;
        if (nativeView && !this.isCollapsed) {
            const frame = nativeView.frame;
            const origin = frame.origin;
            const size = frame.size;
            return {
                left: Math.round(layout.toDevicePixels(origin.x)),
                top: Math.round(layout.toDevicePixels(origin.y)),
                right: Math.round(layout.toDevicePixels(origin.x + size.width)),
                bottom: Math.round(layout.toDevicePixels(origin.y + size.height)),
            };
        }
        else {
            return { left: 0, top: 0, right: 0, bottom: 0 };
        }
    }
    _redrawNativeBackground(value) {
        const updateSuspended = this._isPresentationLayerUpdateSuspended();
        if (!updateSuspended) {
            CATransaction.begin();
        }
        // Disable CALayer animatable property changes
        CATransaction.setDisableActions(true);
        const nativeView = this.nativeViewProtected;
        if (nativeView) {
            if (value instanceof UIColor) {
                nativeView.backgroundColor = value;
            }
            else {
                iosBackground.createBackgroundUIColor(this, (color) => {
                    nativeView.backgroundColor = color;
                });
                this._setNativeClipToBounds();
            }
        }
        CATransaction.setDisableActions(false);
        if (!updateSuspended) {
            CATransaction.commit();
        }
        this._nativeBackgroundState = 'drawn';
    }
    _setNativeClipToBounds() {
        const view = this.nativeViewProtected;
        if (view) {
            const backgroundInternal = this.style.backgroundInternal;
            view.clipsToBounds = view instanceof UIScrollView || backgroundInternal.hasBorderWidth() || backgroundInternal.hasBorderRadius();
        }
    }
    _setupPopoverControllerDelegate(controller, parent) {
        const popoverPresentationController = controller.popoverPresentationController;
        this._popoverPresentationDelegate = IOSHelper.UIPopoverPresentationControllerDelegateImp.initWithOwnerAndCallback(new WeakRef(this), this._closeModalCallback);
        popoverPresentationController.delegate = this._popoverPresentationDelegate;
        let view;
        do {
            view = parent.nativeViewProtected;
            parent = parent.parent;
        } while (parent && !view);
        // Note: sourceView and sourceRect are needed to specify the anchor location for the popover.
        // Note: sourceView should be the button triggering the modal. If it the Page the popover might appear "behind" the page content
        popoverPresentationController.sourceView = view;
        popoverPresentationController.sourceRect = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);
    }
    _setupAdaptiveControllerDelegate(controller) {
        this._adaptivePresentationDelegate = IOSHelper.UIAdaptivePresentationControllerDelegateImp.initWithOwnerAndCallback(new WeakRef(this), this._closeModalCallback);
        if (controller?.presentationController) {
            controller.presentationController.delegate = this._adaptivePresentationDelegate;
        }
    }
}
__decorate([
    profile,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Number, Number, Number, Number, Object]),
    __metadata("design:returntype", void 0)
], View.prototype, "layout", null);
__decorate([
    profile,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Number, Number]),
    __metadata("design:returntype", void 0)
], View.prototype, "onMeasure", null);
View.prototype._nativeBackgroundState = 'unset';
var UIViewControllerTransitioningDelegateImpl = /** @class */ (function (_super) {
    __extends(UIViewControllerTransitioningDelegateImpl, _super);
    function UIViewControllerTransitioningDelegateImpl() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    UIViewControllerTransitioningDelegateImpl.initWithOwner = function (owner) {
        var delegate = UIViewControllerTransitioningDelegateImpl.new();
        delegate.owner = owner;
        return delegate;
    };
    UIViewControllerTransitioningDelegateImpl.prototype.animationControllerForDismissedController = function (dismissed) {
        var _a;
        var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner === null || owner === void 0 ? void 0 : owner.iosDismissedController) {
            return owner.iosDismissedController(dismissed);
        }
        return null;
    };
    UIViewControllerTransitioningDelegateImpl.prototype.animationControllerForPresentedControllerPresentingControllerSourceController = function (presented, presenting, source) {
        var _a;
        var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner === null || owner === void 0 ? void 0 : owner.iosPresentedController) {
            return owner.iosPresentedController(presented, presenting, source);
        }
        return null;
    };
    UIViewControllerTransitioningDelegateImpl.prototype.interactionControllerForDismissal = function (animator) {
        var _a;
        var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner === null || owner === void 0 ? void 0 : owner.iosInteractionDismiss) {
            var transitionState = SharedTransition.getState(owner.id);
            if (transitionState === null || transitionState === void 0 ? void 0 : transitionState.interactiveBegan) {
                return owner.iosInteractionDismiss(animator);
            }
        }
        return null;
    };
    UIViewControllerTransitioningDelegateImpl.prototype.interactionControllerForPresentation = function (animator) {
        var _a;
        var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.deref();
        if (owner === null || owner === void 0 ? void 0 : owner.iosInteractionPresented) {
            return owner.iosInteractionPresented(animator);
        }
        return null;
    };
    UIViewControllerTransitioningDelegateImpl.ObjCProtocols = [UIViewControllerTransitioningDelegate];
    return UIViewControllerTransitioningDelegateImpl;
}(NSObject));
export class ContainerView extends View {
    constructor() {
        super();
        this.iosOverflowSafeArea = true;
    }
}
export class CustomLayoutView extends ContainerView {
    createNativeView() {
        const window = iosUtils.getWindow();
        return UIView.alloc().initWithFrame(window ? window.screen.bounds : UIScreen.mainScreen.bounds);
    }
    get ios() {
        return this.nativeViewProtected;
    }
    onMeasure(widthMeasureSpec, heightMeasureSpec) {
        // Don't call super because it will set MeasureDimension. This method must be overridden and calculate its measuredDimensions.
    }
    _addViewToNativeVisualTree(child, atIndex) {
        super._addViewToNativeVisualTree(child, atIndex);
        const parentNativeView = this.nativeViewProtected;
        const childNativeView = child.nativeViewProtected;
        if (parentNativeView && childNativeView) {
            if (typeof atIndex !== 'number' || atIndex >= parentNativeView.subviews.count) {
                parentNativeView.addSubview(childNativeView);
            }
            else {
                parentNativeView.insertSubviewAtIndex(childNativeView, atIndex);
            }
            // Add outer shadow layer manually as it belongs to parent layer tree (this is needed for reusable views)
            if (childNativeView.outerShadowContainerLayer && !childNativeView.outerShadowContainerLayer.superlayer) {
                parentNativeView.layer.insertSublayerBelow(childNativeView.outerShadowContainerLayer, childNativeView.layer);
            }
            return true;
        }
        return false;
    }
    _removeViewFromNativeVisualTree(child) {
        super._removeViewFromNativeVisualTree(child);
        if (child.nativeViewProtected) {
            const nativeView = child.nativeViewProtected;
            // Remove outer shadow layer manually as it belongs to parent layer tree
            if (nativeView.outerShadowContainerLayer) {
                nativeView.outerShadowContainerLayer.removeFromSuperlayer();
            }
            nativeView.removeFromSuperview();
        }
    }
}
//# sourceMappingURL=index.ios.js.map