/*
 * 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 com.android.wm.shell.common.split;

import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
import static android.view.RoundedCorner.POSITION_TOP_LEFT;
import static android.view.RoundedCorner.POSITION_TOP_RIGHT;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.RoundedCorner;
import android.view.View;

import androidx.annotation.Nullable;

import com.android.wm.shell.R;

/**
 * Draws inverted rounded corners beside divider bar to keep splitting tasks cropped with proper
 * rounded corners.
 */
public class DividerRoundedCorner extends View {
    private final int mDividerWidth;
    private final Paint mDividerBarBackground;
    private final Point mStartPos = new Point();
    private InvertedRoundedCornerDrawInfo mTopLeftCorner;
    private InvertedRoundedCornerDrawInfo mTopRightCorner;
    private InvertedRoundedCornerDrawInfo mBottomLeftCorner;
    private InvertedRoundedCornerDrawInfo mBottomRightCorner;

    public DividerRoundedCorner(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mDividerWidth = getResources().getDimensionPixelSize(R.dimen.split_divider_bar_width);
        mDividerBarBackground = new Paint();
        mDividerBarBackground.setColor(
                getResources().getColor(R.color.split_divider_background, null));
        mDividerBarBackground.setFlags(Paint.ANTI_ALIAS_FLAG);
        mDividerBarBackground.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mTopLeftCorner = new InvertedRoundedCornerDrawInfo(POSITION_TOP_LEFT);
        mTopRightCorner = new InvertedRoundedCornerDrawInfo(POSITION_TOP_RIGHT);
        mBottomLeftCorner = new InvertedRoundedCornerDrawInfo(POSITION_BOTTOM_LEFT);
        mBottomRightCorner = new InvertedRoundedCornerDrawInfo(POSITION_BOTTOM_RIGHT);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();

        mTopLeftCorner.calculateStartPos(mStartPos);
        canvas.translate(mStartPos.x, mStartPos.y);
        canvas.drawPath(mTopLeftCorner.mPath, mDividerBarBackground);

        canvas.translate(-mStartPos.x, -mStartPos.y);
        mTopRightCorner.calculateStartPos(mStartPos);
        canvas.translate(mStartPos.x, mStartPos.y);
        canvas.drawPath(mTopRightCorner.mPath, mDividerBarBackground);

        canvas.translate(-mStartPos.x, -mStartPos.y);
        mBottomLeftCorner.calculateStartPos(mStartPos);
        canvas.translate(mStartPos.x, mStartPos.y);
        canvas.drawPath(mBottomLeftCorner.mPath, mDividerBarBackground);

        canvas.translate(-mStartPos.x, -mStartPos.y);
        mBottomRightCorner.calculateStartPos(mStartPos);
        canvas.translate(mStartPos.x, mStartPos.y);
        canvas.drawPath(mBottomRightCorner.mPath, mDividerBarBackground);

        canvas.restore();
    }

    @Override
    public boolean hasOverlappingRendering() {
        return false;
    }

    private boolean isLandscape() {
        return getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
    }

    /**
     * Holds draw information of the inverted rounded corner at a specific position.
     *
     * @see {@link com.android.launcher3.taskbar.TaskbarDragLayer}
     */
    private class InvertedRoundedCornerDrawInfo {
        @RoundedCorner.Position
        private final int mCornerPosition;

        private final int mRadius;

        private final Path mPath = new Path();

        InvertedRoundedCornerDrawInfo(@RoundedCorner.Position int cornerPosition) {
            mCornerPosition = cornerPosition;

            final RoundedCorner roundedCorner = getDisplay().getRoundedCorner(cornerPosition);
            mRadius = roundedCorner == null ? 0 : roundedCorner.getRadius();

            // Starts with a filled square, and then subtracting out a circle from the appropriate
            // corner.
            final Path square = new Path();
            square.addRect(0, 0, mRadius, mRadius, Path.Direction.CW);
            final Path circle = new Path();
            circle.addCircle(
                    isLeftCorner() ? mRadius : 0 /* x */,
                    isTopCorner() ? mRadius : 0 /* y */,
                    mRadius, Path.Direction.CW);
            mPath.op(square, circle, Path.Op.DIFFERENCE);
        }

        private void calculateStartPos(Point outPos) {
            if (isLandscape()) {
                // Place left corner at the right side of the divider bar.
                outPos.x = isLeftCorner()
                        ? getWidth() / 2 + mDividerWidth / 2
                        : getWidth() / 2 - mDividerWidth / 2 - mRadius;
                outPos.y = isTopCorner() ? 0 : getHeight() - mRadius;
            } else {
                outPos.x = isLeftCorner() ? 0 : getWidth() - mRadius;
                // Place top corner at the bottom of the divider bar.
                outPos.y = isTopCorner()
                        ? getHeight() / 2 + mDividerWidth / 2
                        : getHeight() / 2 - mDividerWidth / 2 - mRadius;
            }
        }

        private boolean isLeftCorner() {
            return mCornerPosition == POSITION_TOP_LEFT || mCornerPosition == POSITION_BOTTOM_LEFT;
        }

        private boolean isTopCorner() {
            return mCornerPosition == POSITION_TOP_LEFT || mCornerPosition == POSITION_TOP_RIGHT;
        }
    }
}
