/*
 * Copyright (C) 2016 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.documentsui;

import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.Nullable;

import com.android.documentsui.DragAndDropManager.State;

import java.text.NumberFormat;

class DragShadowBuilder extends View.DragShadowBuilder {

    private final View mShadowView;
    private final TextView mTitle;
    private final DropBadgeView mIcon;
    private final int mWidth;
    private final int mHeight;
    private final int mShadowRadius;
    private final int mPadding;
    private Paint paint;
    // This will be null if use_material3 flag is OFF.
    private final @Nullable View mAdditionalShadowView;
    // This will always be 0 if the use_material3 flag is OFF.
    private int mDragFileCount = 0;
    // The following 5 dimensions will be 0 if the use_material3 flag is OFF.
    private final int mDragContentRadius;
    private final int mAdditionalLayerOffset;
    private final int mDragFileCounterOffset;
    private final int mShadow2Radius;
    private final int mShadowYOffset;

    DragShadowBuilder(Context context) {
        mWidth = context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_width);
        mHeight = context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_height);
        mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_radius);
        mPadding = context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_padding);

        mShadowView = LayoutInflater.from(context).inflate(R.layout.drag_shadow_layout, null);
        mTitle = (TextView) mShadowView.findViewById(android.R.id.title);
        mIcon = (DropBadgeView) mShadowView.findViewById(android.R.id.icon);
        if (isUseMaterial3FlagEnabled()) {
            mAdditionalShadowView =
                    LayoutInflater.from(context).inflate(R.layout.additional_drag_shadow, null);
            mDragContentRadius =
                    context.getResources().getDimensionPixelSize(R.dimen.drag_content_radius);
            mAdditionalLayerOffset =
                    context.getResources()
                            .getDimensionPixelSize(R.dimen.drag_additional_layer_offset);
            mDragFileCounterOffset =
                    context.getResources().getDimensionPixelSize(R.dimen.drag_file_counter_offset);
            mShadow2Radius =
                    context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_2_radius);
            mShadowYOffset =
                    context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_y_offset);
        } else {
            mAdditionalShadowView = null;
            mDragContentRadius = 0;
            mAdditionalLayerOffset = 0;
            mDragFileCounterOffset = 0;
            mShadow2Radius = 0;
            mShadowYOffset = 0;
        }

        // Important for certain APIs
        mShadowView.setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    @Override
    public void onProvideShadowMetrics(
            Point shadowSize, Point shadowTouchPoint) {
        shadowSize.set(mWidth, mHeight);
        shadowTouchPoint.set(mWidth, mHeight);
    }

    @Override
    public void onDrawShadow(Canvas canvas) {
        Rect r = canvas.getClipBounds();
        // Calling measure is necessary in order for all child views to get correctly laid out.
        mShadowView.measure(
                View.MeasureSpec.makeMeasureSpec(r.right - r.left, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(r.bottom - r.top , View.MeasureSpec.EXACTLY));
        mShadowView.layout(r.left, r.top, r.right, r.bottom);

        // Since DragShadow is not an actual view drawn in hardware-accelerated window,
        // android:elevation does not work; we need to draw the shadow ourselves manually.
        paint.setColor(Color.TRANSPARENT);

        // Layers on the canvas (from bottom to top):
        // 1. Two shadows for the additional drag layer (if drag file count > 1)
        // 2. The additional layer view itself (if drag file count > 1)
        // 3. Two shadows for the drag content layer (icon, title)
        // 4. The drag content layer itself
        final int shadowOneOpacity = (int) (255 * 0.15);
        final int shadowTwoOpacity = (int) (255 * 0.30);
        if (mAdditionalShadowView != null && mDragFileCount > 1) {
            mAdditionalShadowView.measure(
                    View.MeasureSpec.makeMeasureSpec(r.right - r.left, View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(r.bottom - r.top , View.MeasureSpec.EXACTLY));
            mAdditionalShadowView.layout(r.left, r.top, r.right, r.bottom);
            // Shadow 1
            paint.setShadowLayer(
                    mShadowRadius, 0, mShadowYOffset, Color.argb(shadowOneOpacity, 0, 0, 0));
            canvas.drawRoundRect(
                    r.left + mShadowRadius,
                    r.top + mDragFileCounterOffset + mAdditionalLayerOffset,
                    r.right - mDragFileCounterOffset - mAdditionalLayerOffset,
                    r.bottom - mShadowRadius,
                    mDragContentRadius,
                    mDragContentRadius,
                    paint);
            // Shadow 2
            paint.setShadowLayer(
                    mShadow2Radius, 0, mShadowYOffset, Color.argb(shadowTwoOpacity, 0, 0, 0));
            canvas.drawRoundRect(
                    r.left + mShadowRadius,
                    r.top + mDragFileCounterOffset + mAdditionalLayerOffset,
                    r.right - mDragFileCounterOffset - mAdditionalLayerOffset,
                    r.bottom - mShadowRadius,
                    mDragContentRadius,
                    mDragContentRadius,
                    paint);
            mAdditionalShadowView.draw(canvas);
        }

        if (isUseMaterial3FlagEnabled()) {
            // Shadow 1
            paint.setShadowLayer(
                    mShadowRadius, 0, mShadowYOffset, Color.argb(shadowOneOpacity, 0, 0, 0));
            canvas.drawRoundRect(
                    r.left + mShadowRadius + mAdditionalLayerOffset,
                    r.top + mDragFileCounterOffset,
                    r.right - mDragFileCounterOffset,
                    r.bottom - mShadowRadius - mAdditionalLayerOffset,
                    mDragContentRadius,
                    mDragContentRadius,
                    paint);
            // Shadow 2
            paint.setShadowLayer(
                    mShadow2Radius, 0, mShadowYOffset, Color.argb(shadowTwoOpacity, 0, 0, 0));
            canvas.drawRoundRect(
                    r.left + mShadowRadius + mAdditionalLayerOffset,
                    r.top + mDragFileCounterOffset,
                    r.right - mDragFileCounterOffset,
                    r.bottom - mShadowRadius - mAdditionalLayerOffset,
                    mDragContentRadius,
                    mDragContentRadius,
                    paint);
        } else {
            // Shadow 1
            int opacity = (int) (255 * 0.1);
            paint.setShadowLayer(mShadowRadius, 0, 0, Color.argb(opacity, 0, 0, 0));
            canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding,
                    r.bottom - mPadding, paint);
            // Shadow 2
            opacity = (int) (255 * 0.24);
            paint.setShadowLayer(mShadowRadius, 0, mShadowRadius, Color.argb(opacity, 0, 0, 0));
            canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding,
                    r.bottom - mPadding, paint);
        }
        mShadowView.draw(canvas);
    }

    void updateTitle(String title) {
        mTitle.setText(title);
    }

    void updateIcon(Drawable icon) {
        mIcon.updateIcon(icon);
    }

    void onStateUpdated(@State int state) {
        mIcon.updateState(state);
    }

    void updateDragFileCount(int count) {
        if (!isUseMaterial3FlagEnabled()) {
            return;
        }
        mDragFileCount = count;
        TextView dragFileCountView = mShadowView.findViewById(R.id.drag_file_counter);
        if (dragFileCountView != null) {
            dragFileCountView.setVisibility(count > 1 ? View.VISIBLE : View.GONE);
            if (count > 1) {
                NumberFormat numberFormat = NumberFormat.getInstance();
                dragFileCountView.setText(numberFormat.format(count));
            }
        }
    }
}
