/*
 * Copyright (c) 2020 Hemanth Savarala.
 *
 * Licensed under the GNU General Public License v3
 *
 * This is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by
 *  the Free Software Foundation either version 3 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */

package code.name.monkey.appthemehelper.view;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.DrawableCompat;

public class PopupBackground extends Drawable {

  private final int mPaddingEnd;

  private final int mPaddingStart;

  @NonNull private final Paint mPaint;

  @NonNull private final Path mPath = new Path();

  @NonNull private final Matrix mTempMatrix = new Matrix();

  public PopupBackground(@NonNull Context context, int color) {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setColor(color);
    mPaint.setStyle(Paint.Style.FILL);
    Resources resources = context.getResources();
    mPaddingStart = resources.getDimensionPixelOffset(me.zhanghai.android.fastscroll.R.dimen.afs_md2_popup_padding_start);
    mPaddingEnd = resources.getDimensionPixelOffset(me.zhanghai.android.fastscroll.R.dimen.afs_md2_popup_padding_end);
  }

  private static void pathArcTo(
      @NonNull Path path,
      float centerX,
      float centerY,
      float radius,
      float startAngle,
      float sweepAngle) {
    path.arcTo(
        centerX - radius,
        centerY - radius,
        centerX + radius,
        centerY + radius,
        startAngle,
        sweepAngle,
        false);
  }

  @Override
  public void draw(@NonNull Canvas canvas) {
    canvas.drawPath(mPath, mPaint);
  }

  @Override
  public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
  }

  @Override
  public void getOutline(@NonNull Outline outline) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && !mPath.isConvex()) {
      // The outline path must be convex before Q, but we may run into floating point error
      // caused by calculation involving sqrt(2) or OEM implementation difference, so in this
      // case we just omit the shadow instead of crashing.
      super.getOutline(outline);
      return;
    }
    outline.setConvexPath(mPath);
  }

  @Override
  public void setAlpha(int alpha) {}

  @Override
  public void setColorFilter(@Nullable ColorFilter colorFilter) {}

  @Override
  public boolean getPadding(@NonNull Rect padding) {
    if (needMirroring()) {
      padding.set(mPaddingEnd, 0, mPaddingStart, 0);
    } else {
      padding.set(mPaddingStart, 0, mPaddingEnd, 0);
    }
    return true;
  }

  @Override
  public boolean isAutoMirrored() {
    return true;
  }

  @Override
  public boolean onLayoutDirectionChanged(int layoutDirection) {
    updatePath();
    return true;
  }

  @Override
  protected void onBoundsChange(@NonNull Rect bounds) {
    updatePath();
  }

  private boolean needMirroring() {
    return DrawableCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL;
  }

  private void updatePath() {

    mPath.reset();

    Rect bounds = getBounds();
    float width = bounds.width();
    float height = bounds.height();
    float r = height / 2;
    float sqrt2 = (float) Math.sqrt(2);
    // Ensure we are convex.
    width = Math.max(r + sqrt2 * r, width);
    pathArcTo(mPath, r, r, r, 90, 180);
    float o1X = width - sqrt2 * r;
    pathArcTo(mPath, o1X, r, r, -90, 45f);
    float r2 = r / 5;
    float o2X = width - sqrt2 * r2;
    pathArcTo(mPath, o2X, r, r2, -45, 90);
    pathArcTo(mPath, o1X, r, r, 45f, 45f);
    mPath.close();

    if (needMirroring()) {
      mTempMatrix.setScale(-1, 1, width / 2, 0);
    } else {
      mTempMatrix.reset();
    }
    mTempMatrix.postTranslate(bounds.left, bounds.top);
    mPath.transform(mTempMatrix);
  }
}
