/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.react.views.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.util.TypedValue;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ViewProps;

/**
 * Utility class that helps with converting android drawable description used in JS to an actual
 * instance of {@link Drawable}.
 */
public class ReactDrawableHelper {

  private static final TypedValue sResolveOutValue = new TypedValue();

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public static Drawable createDrawableFromJSDescription(
      Context context, ReadableMap drawableDescriptionDict) {
    String type = drawableDescriptionDict.getString("type");
    if ("ThemeAttrAndroid".equals(type)) {
      String attr = drawableDescriptionDict.getString("attribute");
      SoftAssertions.assertNotNull(attr);
      int attrID = context.getResources().getIdentifier(attr, "attr", "android");
      if (attrID == 0) {
        throw new JSApplicationIllegalArgumentException(
            "Attribute " + attr + " couldn't be found in the resource list");
      }
      if (!context.getTheme().resolveAttribute(attrID, sResolveOutValue, true)) {
        throw new JSApplicationIllegalArgumentException(
            "Attribute " + attr + " couldn't be resolved into a drawable");
      }
      Drawable drawable = getDefaultThemeDrawable(context);
      return setRadius(drawableDescriptionDict, drawable);
    } else if ("RippleAndroid".equals(type)) {
      RippleDrawable rd = getRippleDrawable(context, drawableDescriptionDict);
      return setRadius(drawableDescriptionDict, rd);
    } else {
      throw new JSApplicationIllegalArgumentException("Invalid type for android drawable: " + type);
    }
  }

  private static Drawable getDefaultThemeDrawable(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      return context.getResources().getDrawable(sResolveOutValue.resourceId, context.getTheme());
    } else {
      return context.getResources().getDrawable(sResolveOutValue.resourceId);
    }
  }

  private static RippleDrawable getRippleDrawable(
      Context context, ReadableMap drawableDescriptionDict) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
      throw new JSApplicationIllegalArgumentException(
          "Ripple drawable is not available on android API <21");
    }
    int color = getColor(context, drawableDescriptionDict);
    Drawable mask = getMask(drawableDescriptionDict);
    ColorStateList colorStateList =
        new ColorStateList(new int[][] {new int[] {}}, new int[] {color});

    return new RippleDrawable(colorStateList, null, mask);
  }

  private static Drawable setRadius(ReadableMap drawableDescriptionDict, Drawable drawable) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
        && drawableDescriptionDict.hasKey("rippleRadius")
        && drawable instanceof RippleDrawable) {
      RippleDrawable rippleDrawable = (RippleDrawable) drawable;
      double rippleRadius = drawableDescriptionDict.getDouble("rippleRadius");
      rippleDrawable.setRadius((int) PixelUtil.toPixelFromDIP(rippleRadius));
    }
    return drawable;
  }

  private static int getColor(Context context, ReadableMap drawableDescriptionDict) {
    if (drawableDescriptionDict.hasKey(ViewProps.COLOR)
        && !drawableDescriptionDict.isNull(ViewProps.COLOR)) {
      return drawableDescriptionDict.getInt(ViewProps.COLOR);
    } else {
      if (context
          .getTheme()
          .resolveAttribute(android.R.attr.colorControlHighlight, sResolveOutValue, true)) {
        return context.getResources().getColor(sResolveOutValue.resourceId);
      } else {
        throw new JSApplicationIllegalArgumentException(
            "Attribute colorControlHighlight couldn't be resolved into a drawable");
      }
    }
  }

  private static @Nullable Drawable getMask(ReadableMap drawableDescriptionDict) {
    if (!drawableDescriptionDict.hasKey("borderless")
        || drawableDescriptionDict.isNull("borderless")
        || !drawableDescriptionDict.getBoolean("borderless")) {
      return new ColorDrawable(Color.WHITE);
    }
    return null;
  }
}

@@ -595,24 +595,25 @@
 n.Nullable;%0A
+%0A
 import com.f
@@ -1447,50 +1447,8 @@
 %22);%0A
-      SoftAssertions.assertNotNull(attr);%0A
     
@@ -1462,242 +1462,37 @@
 ttrI
-D = context.getResources().getIdentifier(attr, %22attr%22, %22android%22);%0A      if (attrID == 0) %7B%0A        throw new JSApplicationIllegalArgumentException(%0A            %22Attribute %22 + attr + %22 couldn't be found in the resource list%22);%0A      %7D
+d = getAttrId(context, attr);
 %0A   
@@ -1540,17 +1540,17 @@
 te(attrI
-D
+d
 , sResol
@@ -1662,16 +1662,39 @@
 attr + %22
+ with id %22 + attrId + %22
  couldn'
@@ -2149,32 +2149,515 @@
 pe);%0A    %7D%0A  %7D%0A%0A
+  @TargetApi(Build.VERSION_CODES.LOLLIPOP)%0A  private static int getAttrId(Context context, String attr) %7B%0A    SoftAssertions.assertNotNull(attr);%0A    if (%22selectableItemBackground%22.equals(attr)) %7B%0A      return android.R.attr.selectableItemBackground;%0A    %7D else if (%22selectableItemBackgroundBorderless%22.equals(attr)) %7B%0A      return android.R.attr.selectableItemBackgroundBorderless;%0A    %7D else %7B%0A      return context.getResources().getIdentifier(attr, %22attr%22, %22android%22);%0A    %7D%0A  %7D%0A%0A
   private static

get ripple drawables by id (#28600)