/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import display from '@ohos.display';
import window from '@ohos.window';
import hilog from '@ohos.hilog';
import { LengthMetrics, Position, Size } from '@ohos.arkui.node';
import curves from '@ohos.curves';
import { Callback } from '@ohos.base';
import mediaQuery from '@ohos.mediaquery';

interface Layout {
  size: Size;
  position: Position;
}

interface RegionLayout {
  primary: Layout;
  secondary: Layout;
  extra: Layout;
}

/**
 * Position enum of the extra region
 *
 * @enum { number }
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export enum ExtraRegionPosition {
  /**
   * The extra region position is in the top.
   *
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  TOP = 1,

  /**
   * The extra region position is in the bottom.
   *
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  BOTTOM = 2,
}

/**
 * The layout options for the container when the foldable screen is expanded.
 *
 * @interface ExpandedRegionLayoutOptions
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export interface ExpandedRegionLayoutOptions {
  /**
   * The ratio of the widths of two areas in the horizontal direction.
   *
   * @type { ?number }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  horizontalSplitRatio?: number;

  /**
   * The ratio of the heights of two areas in the vertical direction.
   *
   * @type { ?number }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  verticalSplitRatio?: number;

  /**
   * Does the extended area span from top to bottom within the container?
   *
   * @type { ?boolean }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  isExtraRegionPerpendicular?: boolean;

  /**
   * Specify the position of the extra area when the extra area does not vertically span the container.
   *
   * @type { ?ExtraRegionPosition }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  extraRegionPosition?: ExtraRegionPosition;
}

/**
 * The layout options for the container when the foldable screen is in hover mode.
 *
 * @interface SemiFoldedRegionLayoutOptions
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export interface HoverModeRegionLayoutOptions {
  /**
   * The ratio of the widths of two areas in the horizontal direction.
   *
   * @type { ?number }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  horizontalSplitRatio?: number;

  /**
   * Does the foldable screen display an extra area when it's in the half-folded state?
   *
   * @type { ?boolean }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  showExtraRegion?: boolean;

  /**
   * Specify the position of the extra area when the foldable screen is in the half-folded state.
   *
   * @type { ?ExtraRegionPosition }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  extraRegionPosition?: ExtraRegionPosition;
}

/**
 * The layout options for the container when the foldable screen is folded.
 *
 * @interface FoldedRegionLayoutOptions
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export interface FoldedRegionLayoutOptions {
  /**
   * The ratio of the heights of two areas in the vertical direction.
   *
   * @type { ?number }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  verticalSplitRatio?: number;
}

/**
 * Preset split ratio.
 *
 * @enum { number }
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export enum PresetSplitRatio {
  /**
   * 1:1
   *
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  LAYOUT_1V1 = 1 / 1,

  /**
   * 2:3
   *
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  LAYOUT_2V3 = 2 / 3,

  /**
   * 3:2
   *
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  LAYOUT_3V2 = 3 / 2,
}

/**
 * The status of hover mode.
 *
 * @interface HoverStatus
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export interface HoverModeStatus {
  /**
   * The fold status of devices.
   *
   * @type { display.FoldStatus }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  foldStatus: display.FoldStatus;

  /**
   * Is the app currently in hover mode?
   * In hover mode, the upper half of the screen is used for display, and the lower half is used for operation.
   *
   * @type { boolean }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  isHoverMode: boolean;

  /**
   * The angle of rotation applied.
   *
   * @type { number }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  appRotation: number;

  /**
   * The status of window.
   *
   * @type { window.WindowStatusType }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  windowStatusType: window.WindowStatusType;
}

/**
 * The handler of onHoverStatusChange event
 *
 * @typedef { function } OnHoverStatusChangeHandler
 * @param { HoverModeStatus } status - The status of hover mode
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
export type OnHoverStatusChangeHandler = (status: HoverModeStatus) => void;

function withDefaultValue<T>(value: T | undefined | null, defaultValue: T): T {
  if (value === void 0 || value === null) {
    return defaultValue;
  }
  return value;
}

function getSplitRatio(ratio: number | undefined | null, defaultRatio: number): number {
  if (ratio === void 0 || ratio === null) {
    return defaultRatio;
  }
  if (ratio <= 0) {
    return defaultRatio;
  }
  return ratio;
}

class Logger {
  static debug(format: string, ...args: ESObject[]): void {
    return hilog.debug(0x3900, 'FoldSplitContainer', format, ...args);
  }

  static info(format: string, ...args: ESObject[]): void {
    return hilog.info(0x3900, 'FoldSplitContainer', format, ...args);
  }

  static error(format: string, ...args: ESObject[]): void {
    return hilog.error(0x3900, 'FoldSplitContainer', format, ...args);
  }
}

function initLayout(): Layout {
  return {
    size: { width: 0, height: 0 },
    position: { x: 0, y: 0 },
  };
}

/**
 * Defines FoldSplitContainer container.
 *
 * @interface FoldSplitContainer
 * @syscap SystemCapability.ArkUI.ArkUI.Full
 * @crossplatform
 * @atomicservice
 * @since 12
 */
@Component
export struct FoldSplitContainer {
  /**
   * The builder function which will be rendered in the major region of container.
   *
   * @type { Callback<void> }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @BuilderParam
  primary: Callback<void>;
  /**
   * The builder function which will be rendered in the minor region of container.
   *
   * @type { Callback<void> }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @BuilderParam
  secondary: Callback<void>;
  /**
   * The builder function which will be rendered in the extra region of container.
   *
   * @type { ?Callback<void> }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @BuilderParam
  extra?: Callback<void>;
  /**
   * The layout options for the container when the foldable screen is expanded.
   *
   * @type { ExpandedRegionLayoutOptions }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @Prop
  @Watch('updateLayout')
  expandedLayoutOptions: ExpandedRegionLayoutOptions = {
    horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
    isExtraRegionPerpendicular: true,
    extraRegionPosition: ExtraRegionPosition.TOP
  };
  /**
   * The layout options for the container when the foldable screen is in hover mode.
   *
   * @type { HoverModeRegionLayoutOptions  }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @Prop
  @Watch('updateLayout')
  hoverModeLayoutOptions: HoverModeRegionLayoutOptions = {
    horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
    showExtraRegion: false,
    extraRegionPosition: ExtraRegionPosition.TOP
  };
  /**
   * The layout options for the container when the foldable screen is folded.
   *
   * @type { FoldedRegionLayoutOptions }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @Prop
  @Watch('updateLayout')
  foldedLayoutOptions: FoldedRegionLayoutOptions = {
    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1
  };
  /**
   * The animation options of layout
   *
   * @type { AnimateParam | null }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  @Prop
  animationOptions?: AnimateParam | null = undefined;
  /**
   * The callback function that is triggered when the foldable screen enters or exits hover mode.
   * In hover mode, the upper half of the screen is used for display, and the lower half is used for operation.
   *
   * @type { ?OnHoverStatusChangeHandler }
   * @syscap SystemCapability.ArkUI.ArkUI.Full
   * @crossplatform
   * @atomicservice
   * @since 12
   */
  public onHoverStatusChange?: OnHoverStatusChangeHandler = () => {
  };
  @State primaryLayout: Layout = initLayout();
  @State secondaryLayout: Layout = initLayout();
  @State extraLayout: Layout = initLayout();
  @State extraOpacity: number = 1;
  private windowStatusType: window.WindowStatusType = window.WindowStatusType.UNDEFINED;
  private foldStatus: display.FoldStatus = display.FoldStatus.FOLD_STATUS_UNKNOWN;
  private windowInstance?: window.Window;
  private containerSize: Size = { width: 0, height: 0 };
  private containerGlobalPosition: Position = { x: 0, y: 0 };
  private listener?: mediaQuery.MediaQueryListener;
  private isSmallScreen: boolean = false;
  private isHoverMode: boolean | undefined = undefined;

  aboutToAppear() {
    this.listener = mediaQuery.matchMediaSync('(width<=600vp)');
    this.isSmallScreen = this.listener.matches;
    this.listener.on('change', (result) => {
      this.isSmallScreen = result.matches;
    });

    this.foldStatus = display.getFoldStatus();
    display.on('foldStatusChange', (foldStatus) => {
      if (this.foldStatus !== foldStatus) {
        this.foldStatus = foldStatus;
        this.updateLayout();
        this.updatePreferredOrientation();
      }
    });

    window.getLastWindow(this.getUIContext().getHostContext(), (error, windowInstance) => {
      if (error && error.code) {
        Logger.error('Failed to get window instance, error code: %{public}d', error.code);
        return;
      }

      const windowId = windowInstance.getWindowProperties().id;
      if (windowId < 0) {
        Logger.error('Failed to get window instance because the window id is invalid. window id: %{public}d', windowId);
        return;
      }

      this.windowInstance = windowInstance;
      this.updatePreferredOrientation();
      this.windowInstance.on('windowStatusChange', (status) => {
        this.windowStatusType = status;
      });
    });
  }

  aboutToDisappear() {
    if (this.listener) {
      this.listener.off('change');
      this.listener = undefined;
    }
    display.off('foldStatusChange');
    if (this.windowInstance) {
      this.windowInstance.off('windowStatusChange');
    }
  }

  build() {
    Stack() {
      Column() {
        if (this.primary) {
          this.primary();
        }
      }
      .size(this.primaryLayout.size)
      .position({
        start: LengthMetrics.vp(this.primaryLayout.position.x),
        top: LengthMetrics.vp(this.primaryLayout.position.y),
      })
      .clip(true)

      Column() {
        if (this.secondary) {
          this.secondary();
        }
      }
      .size(this.secondaryLayout.size)
      .position({
        start: LengthMetrics.vp(this.secondaryLayout.position.x),
        top: LengthMetrics.vp(this.secondaryLayout.position.y),
      })
      .clip(true)

      if (this.extra) {
        Column() {
          this.extra?.();
        }
        .opacity(this.extraOpacity)
        .animation({ curve: Curve.Linear, duration: 250 })
        .size(this.extraLayout.size)
        .position({
          start: LengthMetrics.vp(this.extraLayout.position.x),
          top: LengthMetrics.vp(this.extraLayout.position.y),
        })
        .clip(true)
      }
    }
    .id('$$FoldSplitContainer$Stack$$')
    .width('100%')
    .height('100%')
    .onSizeChange((_, size) => {
      this.updateContainerSize(size);
      this.updateContainerPosition();
      this.updateLayout();
    })
  }

  private dispatchHoverStatusChange(isHoverMode: boolean) {
    if (this.onHoverStatusChange) {
      this.onHoverStatusChange({
        foldStatus: this.foldStatus,
        isHoverMode: isHoverMode,
        appRotation: display.getDefaultDisplaySync().rotation,
        windowStatusType: this.windowStatusType,
      });
    }
  }

  private hasExtraRegion(): boolean {
    return !!this.extra;
  }

  private async updatePreferredOrientation() {
    if (this.windowInstance) {
      try {
        if (this.foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
          await this.windowInstance.setPreferredOrientation(window.Orientation.AUTO_ROTATION_PORTRAIT);
        } else {
          await this.windowInstance.setPreferredOrientation(window.Orientation.AUTO_ROTATION);
        }
      } catch (err) {
        Logger.error('Failed to update preferred orientation.');
      }
    }
  }

  private updateContainerSize(size: SizeOptions) {
    this.containerSize.width = size.width as number;
    this.containerSize.height = size.height as number;
  }

  private updateContainerPosition() {
    const context = this.getUIContext();
    const frameNode = context.getFrameNodeById('$$FoldSplitContainer$Stack$$');
    if (frameNode) {
      this.containerGlobalPosition = frameNode.getPositionToWindow();
    }
  }

  private updateLayout() {
    let isHoverMode: boolean = false;
    let regionLayout: RegionLayout;
    if (this.isSmallScreen) {
      regionLayout = this.getFoldedRegionLayouts();
    } else {
      if (this.foldStatus === display.FoldStatus.FOLD_STATUS_EXPANDED) {
        regionLayout = this.getExpandedRegionLayouts();
      } else if (this.foldStatus === display.FoldStatus.FOLD_STATUS_HALF_FOLDED) {
        if (this.isPortraitOrientation()) {
          regionLayout = this.getExpandedRegionLayouts();
        } else {
          regionLayout = this.getHoverModeRegionLayouts();
          isHoverMode = true;
        }
      } else if (this.foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
        regionLayout = this.getFoldedRegionLayouts();
      } else {
        regionLayout = this.getExpandedRegionLayouts();
      }
    }

    if (this.animationOptions === null) {
      this.primaryLayout = regionLayout.primary;
      this.secondaryLayout = regionLayout.secondary;
      this.extraLayout = regionLayout.extra;
    } else if (this.animationOptions === void 0) {
      animateTo({ curve: curves.springMotion(0.35, 1, 0) }, () => {
        this.primaryLayout = regionLayout.primary;
        this.secondaryLayout = regionLayout.secondary;
        this.extraLayout = regionLayout.extra;
      });
    } else {
      animateTo(this.animationOptions, () => {
        this.primaryLayout = regionLayout.primary;
        this.secondaryLayout = regionLayout.secondary;
        this.extraLayout = regionLayout.extra;
      });
    }

    if (this.isHoverMode !== isHoverMode) {
      this.dispatchHoverStatusChange(isHoverMode);
      this.isHoverMode = isHoverMode;
    }

    if (isHoverMode && !this.hoverModeLayoutOptions.showExtraRegion) {
      this.extraOpacity = 0;
    } else {
      this.extraOpacity = 1;
    }
  }

  private getExpandedRegionLayouts(): RegionLayout {
    const width = this.containerSize.width;
    const height = this.containerSize.height;
    const primaryLayout: Layout = initLayout();
    const secondaryLayout: Layout = initLayout();
    const extraLayout: Layout = initLayout();

    const horizontalSplitRatio =
      getSplitRatio(this.expandedLayoutOptions.horizontalSplitRatio, PresetSplitRatio.LAYOUT_3V2);
    const verticalSplitRatio =
      getSplitRatio(this.expandedLayoutOptions.verticalSplitRatio, PresetSplitRatio.LAYOUT_1V1);

    if (this.hasExtraRegion()) {
      extraLayout.size.width = width / (horizontalSplitRatio + 1);
    } else {
      extraLayout.size.width = 0;
    }
    secondaryLayout.size.height = height / (verticalSplitRatio + 1);
    primaryLayout.size.height = height - secondaryLayout.size.height;
    primaryLayout.position.x = 0;
    secondaryLayout.position.x = 0;
    primaryLayout.position.y = 0;
    secondaryLayout.position.y = primaryLayout.size.height;

    const isExtraRegionPerpendicular = withDefaultValue(this.expandedLayoutOptions.isExtraRegionPerpendicular, true);
    if (isExtraRegionPerpendicular) {
      primaryLayout.size.width = width - extraLayout.size.width;
      secondaryLayout.size.width = width - extraLayout.size.width;
      extraLayout.size.height = height;
      extraLayout.position.x = primaryLayout.size.width;
      extraLayout.position.y = 0;
    } else {
      const extraRegionPosition =
        withDefaultValue(this.expandedLayoutOptions.extraRegionPosition, ExtraRegionPosition.TOP);
      if (extraRegionPosition === ExtraRegionPosition.BOTTOM) {
        primaryLayout.size.width = width;
        secondaryLayout.size.width = width - extraLayout.size.width;
        extraLayout.size.height = secondaryLayout.size.height;
        extraLayout.position.x = secondaryLayout.size.width;
        extraLayout.position.y = primaryLayout.size.height;
      } else {
        primaryLayout.size.width = width - extraLayout.size.width;
        secondaryLayout.size.width = width;
        extraLayout.size.height = primaryLayout.size.height;
        extraLayout.position.x = primaryLayout.size.width;
        extraLayout.position.y = 0;
      }
    }

    return { primary: primaryLayout, secondary: secondaryLayout, extra: extraLayout };
  }

  private getHoverModeRegionLayouts(): RegionLayout {
    const width = this.containerSize.width;
    const height = this.containerSize.height;
    const primaryLayout: Layout = initLayout();
    const secondaryLayout: Layout = initLayout();
    const extraLayout: Layout = initLayout();
    const creaseRegionRect = this.getCreaseRegionRect();
    primaryLayout.position.x = 0;
    primaryLayout.position.y = 0;
    secondaryLayout.position.x = 0;
    secondaryLayout.position.y = creaseRegionRect.top + creaseRegionRect.height;
    secondaryLayout.size.height = height - secondaryLayout.position.y;
    primaryLayout.size.height = creaseRegionRect.top;

    const showExtraRegion = withDefaultValue(this.hoverModeLayoutOptions.showExtraRegion, false);

    if (!showExtraRegion) {
      primaryLayout.size.width = width;
      secondaryLayout.size.width = width;
      extraLayout.position.x = width;
      const isExpandedExtraRegionPerpendicular = 
        withDefaultValue(this.expandedLayoutOptions.isExtraRegionPerpendicular, true);
      if (isExpandedExtraRegionPerpendicular) {
        extraLayout.size.height = this.extraLayout.size.height;
      } else {
        const expandedExtraRegionPosition =
          withDefaultValue(this.expandedLayoutOptions.extraRegionPosition, ExtraRegionPosition.TOP);
        if (expandedExtraRegionPosition === ExtraRegionPosition.BOTTOM) {
          extraLayout.size.height = secondaryLayout.size.height;
          extraLayout.position.y = secondaryLayout.position.y;
        } else {
          extraLayout.size.height = primaryLayout.size.height;
          extraLayout.position.y = 0;
        }
      }
    } else {
      const horizontalSplitRatio =
        getSplitRatio(this.hoverModeLayoutOptions.horizontalSplitRatio, PresetSplitRatio.LAYOUT_3V2);
      const extraRegionPosition =
        withDefaultValue(this.hoverModeLayoutOptions.extraRegionPosition, ExtraRegionPosition.TOP);
      if (this.hasExtraRegion()) {
        extraLayout.size.width = width / (horizontalSplitRatio + 1);
      } else {
        extraLayout.size.width = 0;
      }
      if (extraRegionPosition === ExtraRegionPosition.BOTTOM) {
        primaryLayout.size.width = width;
        secondaryLayout.size.width = width - extraLayout.size.width;
        extraLayout.size.height = secondaryLayout.size.height;
        extraLayout.position.x = secondaryLayout.size.width;
        extraLayout.position.y = secondaryLayout.position.y;
      } else {
        extraLayout.size.height = primaryLayout.size.height;
        primaryLayout.size.width = width - extraLayout.size.width;
        secondaryLayout.size.width = width;
        extraLayout.position.x = primaryLayout.position.x + primaryLayout.size.width;
        extraLayout.position.y = 0;
      }
    }

    return { primary: primaryLayout, secondary: secondaryLayout, extra: extraLayout };
  }

  private getFoldedRegionLayouts(): RegionLayout {
    const width = this.containerSize.width;
    const height = this.containerSize.height;
    const primaryLayout: Layout = initLayout();
    const secondaryLayout: Layout = initLayout();
    const extraLayout: Layout = initLayout();

    const verticalSplitRatio =
      getSplitRatio(this.foldedLayoutOptions.verticalSplitRatio, PresetSplitRatio.LAYOUT_1V1);

    secondaryLayout.size.height = height / (verticalSplitRatio + 1);
    primaryLayout.size.height = height - secondaryLayout.size.height;
    extraLayout.size.height = 0;
    primaryLayout.size.width = width;
    secondaryLayout.size.width = width;
    extraLayout.size.width = 0;
    primaryLayout.position.x = 0;
    secondaryLayout.position.x = 0;
    extraLayout.position.x = width;
    primaryLayout.position.y = 0;
    secondaryLayout.position.y = primaryLayout.size.height;
    extraLayout.position.y = 0;

    return { primary: primaryLayout, secondary: secondaryLayout, extra: extraLayout };
  }

  private getCreaseRegionRect(): display.Rect {
    const creaseRegion = display.getCurrentFoldCreaseRegion();
    const rects = creaseRegion.creaseRects;
    let left: number = 0;
    let top: number = 0;
    let width: number = 0;
    let height: number = 0;
    if (rects && rects.length) {
      const rect = rects[0];
      left = px2vp(rect.left) - this.containerGlobalPosition.x;
      top = px2vp(rect.top) - this.containerGlobalPosition.y;
      width = px2vp(rect.width);
      height = px2vp(rect.height);
    }

    return { left, top, width, height };
  }

  private isPortraitOrientation() {
    const defaultDisplay = display.getDefaultDisplaySync();
    switch (defaultDisplay.orientation) {
      case display.Orientation.PORTRAIT:
      case display.Orientation.PORTRAIT_INVERTED:
        return true;
      case display.Orientation.LANDSCAPE:
      case display.Orientation.LANDSCAPE_INVERTED:
      default:
        return false;
    }
  }
}