/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * 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.
 */

package androidx.window.common;

import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import android.annotation.SuppressLint;
import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Rect;
import android.util.RotationUtils;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.UiContext;

/**
 * Util class for both Sidecar and Extensions.
 */
public final class ExtensionHelper {

    private ExtensionHelper() {
        // Util class, no instances should be created.
    }

    /**
     * Rotates the input rectangle specified in default display orientation to the current display
     * rotation.
     *
     * @param displayInfo the display information.
     * @param rotation the target rotation relative to the default display orientation.
     * @param inOutRect the input/output Rect as specified in the default display orientation.
     */
    // We suppress the Lint error CheckResult for Rect#intersect because in case the displayInfo and
    // folding features are out of sync, e.g. when a foldable devices is unfolding, it is acceptable
    // to provide the original folding feature Rect even if they don't intersect.
    @SuppressLint("RectIntersectReturnValueIgnored")
    public static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo,
            @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
        // The inOutRect is specified in the default display orientation, so here we need to get
        // the display width and height in the default orientation to perform the intersection and
        // rotation.
        final boolean isSideRotation =
                displayInfo.rotation == ROTATION_90 || displayInfo.rotation == ROTATION_270;
        final int baseDisplayWidth =
                isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
        final int baseDisplayHeight =
                isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;

        inOutRect.intersect(0, 0, baseDisplayWidth, baseDisplayHeight);

        RotationUtils.rotateBounds(inOutRect, baseDisplayWidth, baseDisplayHeight, rotation);
    }

    /** Transforms rectangle from absolute coordinate space to the window coordinate space. */
    public static void transformToWindowSpaceRect(@NonNull @UiContext Context context,
            Rect inOutRect) {
        transformToWindowSpaceRect(getWindowBounds(context), inOutRect);
    }

    /** @see ExtensionHelper#transformToWindowSpaceRect(Context, Rect) */
    public static void transformToWindowSpaceRect(@NonNull WindowConfiguration windowConfiguration,
            Rect inOutRect) {
        transformToWindowSpaceRect(windowConfiguration.getBounds(), inOutRect);
    }

    private static void transformToWindowSpaceRect(@NonNull Rect bounds, @NonNull Rect inOutRect) {
        if (!inOutRect.intersect(bounds)) {
            inOutRect.setEmpty();
            return;
        }
        inOutRect.offset(-bounds.left, -bounds.top);
    }

    /**
     * Gets the current window bounds in absolute coordinates.
     */
    @NonNull
    private static Rect getWindowBounds(@NonNull @UiContext Context context) {
        return context.getSystemService(WindowManager.class).getCurrentWindowMetrics().getBounds();
    }

    /**
     * Checks if both dimensions of the given rect are zero at the same time.
     */
    public static boolean isZero(@NonNull Rect rect) {
        return rect.height() == 0 && rect.width() == 0;
    }
}
