package com.kunminx.architecture.ui.bind;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.StateListDrawable;
import android.view.View;

import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.databinding.BindingAdapter;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

/**
 * Created by linjiang on 2018/9/5.
 */

public class DrawablesBindingAdapter {
    private static final String TAG = "Drawables";

    private static final int INVALID = 0;
    private static final int[] TMP_PADDING = new int[4];

    // normal, checked, checkable, enabled, focused, pressed, selected
    @BindingAdapter(value = {
        "drawable_shapeMode",
        "drawable_solidColor",
        "drawable_strokeColor",
        "drawable_strokeWidth",
        "drawable_strokeDash",
        "drawable_strokeDashGap",
        "drawable_radius",
        "drawable_radiusLT",
        "drawable_radiusLB",
        "drawable_radiusRT",
        "drawable_radiusRB",
        "drawable_startColor",
        "drawable_centerColor",
        "drawable_endColor",
        "drawable_orientation",
        "drawable_gradientType",
        "drawable_radialCenterX",
        "drawable_radialCenterY",
        "drawable_radialRadius",
        "drawable_width",
        "drawable_height",
        "drawable_marginLeft",
        "drawable_marginTop",
        "drawable_marginRight",
        "drawable_marginBottom",
        "drawable_ringThickness",
        "drawable_ringThicknessRatio",
        "drawable_ringInnerRadius",
        "drawable_ringInnerRadiusRatio",

        "drawable_checked_shapeMode",
        "drawable_checked_solidColor",
        "drawable_checked_strokeColor",
        "drawable_checked_strokeWidth",
        "drawable_checked_strokeDash",
        "drawable_checked_strokeDashGap",
        "drawable_checked_radius",
        "drawable_checked_radiusLT",
        "drawable_checked_radiusLB",
        "drawable_checked_radiusRT",
        "drawable_checked_radiusRB",
        "drawable_checked_startColor",
        "drawable_checked_centerColor",
        "drawable_checked_endColor",
        "drawable_checked_orientation",
        "drawable_checked_gradientType",
        "drawable_checked_radialCenterX",
        "drawable_checked_radialCenterY",
        "drawable_checked_radialRadius",
        "drawable_checked_width",
        "drawable_checked_height",
        "drawable_checked_marginLeft",
        "drawable_checked_marginTop",
        "drawable_checked_marginRight",
        "drawable_checked_marginBottom",
        "drawable_checked_ringThickness",
        "drawable_checked_ringThicknessRatio",
        "drawable_checked_ringInnerRadius",
        "drawable_checked_ringInnerRadiusRatio",

        "drawable_checkable_shapeMode",
        "drawable_checkable_solidColor",
        "drawable_checkable_strokeColor",
        "drawable_checkable_strokeWidth",
        "drawable_checkable_strokeDash",
        "drawable_checkable_strokeDashGap",
        "drawable_checkable_radius",
        "drawable_checkable_radiusLT",
        "drawable_checkable_radiusLB",
        "drawable_checkable_radiusRT",
        "drawable_checkable_radiusRB",
        "drawable_checkable_startColor",
        "drawable_checkable_centerColor",
        "drawable_checkable_endColor",
        "drawable_checkable_orientation",
        "drawable_checkable_gradientType",
        "drawable_checkable_radialCenterX",
        "drawable_checkable_radialCenterY",
        "drawable_checkable_radialRadius",
        "drawable_checkable_width",
        "drawable_checkable_height",
        "drawable_checkable_marginLeft",
        "drawable_checkable_marginTop",
        "drawable_checkable_marginRight",
        "drawable_checkable_marginBottom",
        "drawable_checkable_ringThickness",
        "drawable_checkable_ringThicknessRatio",
        "drawable_checkable_ringInnerRadius",
        "drawable_checkable_ringInnerRadiusRatio",

        "drawable_enabled_shapeMode",
        "drawable_enabled_solidColor",
        "drawable_enabled_strokeColor",
        "drawable_enabled_strokeWidth",
        "drawable_enabled_strokeDash",
        "drawable_enabled_strokeDashGap",
        "drawable_enabled_radius",
        "drawable_enabled_radiusLT",
        "drawable_enabled_radiusLB",
        "drawable_enabled_radiusRT",
        "drawable_enabled_radiusRB",
        "drawable_enabled_startColor",
        "drawable_enabled_centerColor",
        "drawable_enabled_endColor",
        "drawable_enabled_orientation",
        "drawable_enabled_gradientType",
        "drawable_enabled_radialCenterX",
        "drawable_enabled_radialCenterY",
        "drawable_enabled_radialRadius",
        "drawable_enabled_width",
        "drawable_enabled_height",
        "drawable_enabled_marginLeft",
        "drawable_enabled_marginTop",
        "drawable_enabled_marginRight",
        "drawable_enabled_marginBottom",
        "drawable_enabled_ringThickness",
        "drawable_enabled_ringThicknessRatio",
        "drawable_enabled_ringInnerRadius",
        "drawable_enabled_ringInnerRadiusRatio",

        "drawable_focused_shapeMode",
        "drawable_focused_solidColor",
        "drawable_focused_strokeColor",
        "drawable_focused_strokeWidth",
        "drawable_focused_strokeDash",
        "drawable_focused_strokeDashGap",
        "drawable_focused_radius",
        "drawable_focused_radiusLT",
        "drawable_focused_radiusLB",
        "drawable_focused_radiusRT",
        "drawable_focused_radiusRB",
        "drawable_focused_startColor",
        "drawable_focused_centerColor",
        "drawable_focused_endColor",
        "drawable_focused_orientation",
        "drawable_focused_gradientType",
        "drawable_focused_radialCenterX",
        "drawable_focused_radialCenterY",
        "drawable_focused_radialRadius",
        "drawable_focused_width",
        "drawable_focused_height",
        "drawable_focused_marginLeft",
        "drawable_focused_marginTop",
        "drawable_focused_marginRight",
        "drawable_focused_marginBottom",
        "drawable_focused_ringThickness",
        "drawable_focused_ringThicknessRatio",
        "drawable_focused_ringInnerRadius",
        "drawable_focused_ringInnerRadiusRatio",

        "drawable_pressed_shapeMode",
        "drawable_pressed_solidColor",
        "drawable_pressed_strokeColor",
        "drawable_pressed_strokeWidth",
        "drawable_pressed_strokeDash",
        "drawable_pressed_strokeDashGap",
        "drawable_pressed_radius",
        "drawable_pressed_radiusLT",
        "drawable_pressed_radiusLB",
        "drawable_pressed_radiusRT",
        "drawable_pressed_radiusRB",
        "drawable_pressed_startColor",
        "drawable_pressed_centerColor",
        "drawable_pressed_endColor",
        "drawable_pressed_orientation",
        "drawable_pressed_gradientType",
        "drawable_pressed_radialCenterX",
        "drawable_pressed_radialCenterY",
        "drawable_pressed_radialRadius",
        "drawable_pressed_width",
        "drawable_pressed_height",
        "drawable_pressed_marginLeft",
        "drawable_pressed_marginTop",
        "drawable_pressed_marginRight",
        "drawable_pressed_marginBottom",
        "drawable_pressed_ringThickness",
        "drawable_pressed_ringThicknessRatio",
        "drawable_pressed_ringInnerRadius",
        "drawable_pressed_ringInnerRadiusRatio",

        "drawable_selected_shapeMode",
        "drawable_selected_solidColor",
        "drawable_selected_strokeColor",
        "drawable_selected_strokeWidth",
        "drawable_selected_strokeDash",
        "drawable_selected_strokeDashGap",
        "drawable_selected_radius",
        "drawable_selected_radiusLT",
        "drawable_selected_radiusLB",
        "drawable_selected_radiusRT",
        "drawable_selected_radiusRB",
        "drawable_selected_startColor",
        "drawable_selected_centerColor",
        "drawable_selected_endColor",
        "drawable_selected_orientation",
        "drawable_selected_gradientType",
        "drawable_selected_radialCenterX",
        "drawable_selected_radialCenterY",
        "drawable_selected_radialRadius",
        "drawable_selected_width",
        "drawable_selected_height",
        "drawable_selected_marginLeft",
        "drawable_selected_marginTop",
        "drawable_selected_marginRight",
        "drawable_selected_marginBottom",
        "drawable_selected_ringThickness",
        "drawable_selected_ringThicknessRatio",
        "drawable_selected_ringInnerRadius",
        "drawable_selected_ringInnerRadiusRatio",

        // normal, checked, checkable, enabled, focused, pressed, selected

        "drawable",
        "drawable_checked",
        "drawable_checkable",
        "drawable_enabled",
        "drawable_focused",
        "drawable_pressed",
        "drawable_selected",

    }, requireAll = false)
    public static void setViewBackground(
        View view,

        @ShapeMode int shapeMode,
        @ColorInt Integer solidColor,
        @ColorInt int strokeColor,
        float strokeWidth,
        float strokeDash,
        float strokeDashGap,
        float radius,
        float radiusLT,
        float radiusLB,
        float radiusRT,
        float radiusRB,
        @ColorInt Integer startColor,
        @ColorInt Integer centerColor,
        @ColorInt Integer endColor,
        @Orientation int orientation,
        @GradientType int gradientType,
        Float radialCenterX,
        Float radialCenterY,
        float radialRadius,
        float width,
        float height,
        float marginLeft,
        float marginTop,
        float marginRight,
        float marginBottom,
        float ringThickness,
        float ringThicknessRatio,
        float ringInnerRadius,
        float ringInnerRadiusRatio,

        @ShapeMode int checked_shapeMode,
        @ColorInt Integer checked_solidColor,
        @ColorInt int checked_strokeColor,
        float checked_strokeWidth,
        float checked_strokeDash,
        float checked_strokeDashGap,
        float checked_radius,
        float checked_radiusLT,
        float checked_radiusLB,
        float checked_radiusRT,
        float checked_radiusRB,
        @ColorInt Integer checked_startColor,
        @ColorInt Integer checked_centerColor,
        @ColorInt Integer checked_endColor,
        @Orientation int checked_orientation,
        @GradientType int checked_gradientType,
        Float checked_radialCenterX,
        Float checked_radialCenterY,
        float checked_radialRadius,
        float checked_width,
        float checked_height,
        float checked_marginLeft,
        float checked_marginTop,
        float checked_marginRight,
        float checked_marginBottom,
        float checked_ringThickness,
        float checked_ringThicknessRatio,
        float checked_ringInnerRadius,
        float checked_ringInnerRadiusRatio,

        @ShapeMode int checkable_shapeMode,
        @ColorInt Integer checkable_solidColor,
        @ColorInt int checkable_strokeColor,
        float checkable_strokeWidth,
        float checkable_strokeDash,
        float checkable_strokeDashGap,
        float checkable_radius,
        float checkable_radiusLT,
        float checkable_radiusLB,
        float checkable_radiusRT,
        float checkable_radiusRB,
        @ColorInt Integer checkable_startColor,
        @ColorInt Integer checkable_centerColor,
        @ColorInt Integer checkable_endColor,
        @Orientation int checkable_orientation,
        @GradientType int checkable_gradientType,
        Float checkable_radialCenterX,
        Float checkable_radialCenterY,
        float checkable_radialRadius,
        float checkable_width,
        float checkable_height,
        float checkable_marginLeft,
        float checkable_marginTop,
        float checkable_marginRight,
        float checkable_marginBottom,
        float checkable_ringThickness,
        float checkable_ringThicknessRatio,
        float checkable_ringInnerRadius,
        float checkable_ringInnerRadiusRatio,

        @ShapeMode int enabled_shapeMode,
        @ColorInt Integer enabled_solidColor,
        @ColorInt int enabled_strokeColor,
        float enabled_strokeWidth,
        float enabled_strokeDash,
        float enabled_strokeDashGap,
        float enabled_radius,
        float enabled_radiusLT,
        float enabled_radiusLB,
        float enabled_radiusRT,
        float enabled_radiusRB,
        @ColorInt Integer enabled_startColor,
        @ColorInt Integer enabled_centerColor,
        @ColorInt Integer enabled_endColor,
        @Orientation int enabled_orientation,
        @GradientType int enabled_gradientType,
        Float enabled_radialCenterX,
        Float enabled_radialCenterY,
        float enabled_radialRadius,
        float enabled_width,
        float enabled_height,
        float enabled_marginLeft,
        float enabled_marginTop,
        float enabled_marginRight,
        float enabled_marginBottom,
        float enabled_ringThickness,
        float enabled_ringThicknessRatio,
        float enabled_ringInnerRadius,
        float enabled_ringInnerRadiusRatio,

        @ShapeMode int focused_shapeMode,
        @ColorInt Integer focused_solidColor,
        @ColorInt int focused_strokeColor,
        float focused_strokeWidth,
        float focused_strokeDash,
        float focused_strokeDashGap,
        float focused_radius,
        float focused_radiusLT,
        float focused_radiusLB,
        float focused_radiusRT,
        float focused_radiusRB,
        @ColorInt Integer focused_startColor,
        @ColorInt Integer focused_centerColor,
        @ColorInt Integer focused_endColor,
        @Orientation int focused_orientation,
        @GradientType int focused_gradientType,
        Float focused_radialCenterX,
        Float focused_radialCenterY,
        float focused_radialRadius,
        float focused_width,
        float focused_height,
        float focused_marginLeft,
        float focused_marginTop,
        float focused_marginRight,
        float focused_marginBottom,
        float focused_ringThickness,
        float focused_ringThicknessRatio,
        float focused_ringInnerRadius,
        float focused_ringInnerRadiusRatio,

        @ShapeMode int pressed_shapeMode,
        @ColorInt Integer pressed_solidColor,
        @ColorInt int pressed_strokeColor,
        float pressed_strokeWidth,
        float pressed_strokeDash,
        float pressed_strokeDashGap,
        float pressed_radius,
        float pressed_radiusLT,
        float pressed_radiusLB,
        float pressed_radiusRT,
        float pressed_radiusRB,
        @ColorInt Integer pressed_startColor,
        @ColorInt Integer pressed_centerColor,
        @ColorInt Integer pressed_endColor,
        @Orientation int pressed_orientation,
        @GradientType int pressed_gradientType,
        Float pressed_radialCenterX,
        Float pressed_radialCenterY,
        float pressed_radialRadius,
        float pressed_width,
        float pressed_height,
        float pressed_marginLeft,
        float pressed_marginTop,
        float pressed_marginRight,
        float pressed_marginBottom,
        float pressed_ringThickness,
        float pressed_ringThicknessRatio,
        float pressed_ringInnerRadius,
        float pressed_ringInnerRadiusRatio,

        @ShapeMode int selected_shapeMode,
        @ColorInt Integer selected_solidColor,
        @ColorInt int selected_strokeColor,
        float selected_strokeWidth,
        float selected_strokeDash,
        float selected_strokeDashGap,
        float selected_radius,
        float selected_radiusLT,
        float selected_radiusLB,
        float selected_radiusRT,
        float selected_radiusRB,
        @ColorInt Integer selected_startColor,
        @ColorInt Integer selected_centerColor,
        @ColorInt Integer selected_endColor,
        @Orientation int selected_orientation,
        @GradientType int selected_gradientType,
        Float selected_radialCenterX,
        Float selected_radialCenterY,
        float selected_radialRadius,
        float selected_width,
        float selected_height,
        float selected_marginLeft,
        float selected_marginTop,
        float selected_marginRight,
        float selected_marginBottom,
        float selected_ringThickness,
        float selected_ringThicknessRatio,
        float selected_ringInnerRadius,
        float selected_ringInnerRadiusRatio,

        Drawable drawable,
        Drawable drawable_checked,
        Drawable drawable_checkable,
        Drawable drawable_enabled,
        Drawable drawable_focused,
        Drawable drawable_pressed,
        Drawable drawable_selected
    ) {
        boolean isDefaultNull = false;
        int count = 0;
        Drawable defaultDrawable = drawable != null ? drawable : create(
            shapeMode,
            solidColor,
            strokeColor,
            strokeWidth,
            strokeDash,
            strokeDashGap,
            radius,
            radiusLT,
            radiusLB,
            radiusRT,
            radiusRB,
            startColor,
            centerColor,
            endColor,
            orientation,
            gradientType,
            radialCenterX,
            radialCenterY,
            radialRadius,
            width,
            height,
            marginLeft,
            marginTop,
            marginRight,
            marginBottom,
            ringThickness,
            ringThicknessRatio,
            ringInnerRadius,
            ringInnerRadiusRatio
        );
        if (defaultDrawable != null) {
            count++;
        } else {
            isDefaultNull = true;
        }
        Drawable checkedDrawable = drawable_checked != null ? drawable_checked : create(
            checked_shapeMode,
            checked_solidColor,
            checked_strokeColor,
            checked_strokeWidth,
            checked_strokeDash,
            checked_strokeDashGap,
            checked_radius,
            checked_radiusLT,
            checked_radiusLB,
            checked_radiusRT,
            checked_radiusRB,
            checked_startColor,
            checked_centerColor,
            checked_endColor,
            checked_orientation,
            checked_gradientType,
            checked_radialCenterX,
            checked_radialCenterY,
            checked_radialRadius,
            checked_width,
            checked_height,
            checked_marginLeft,
            checked_marginTop,
            checked_marginRight,
            checked_marginBottom,
            checked_ringThickness,
            checked_ringThicknessRatio,
            checked_ringInnerRadius,
            checked_ringInnerRadiusRatio
        );
        if (checkedDrawable != null) {
            count++;
        }
        Drawable checkableDrawable = drawable_checkable != null ? drawable_checkable : create(
            checkable_shapeMode,
            checkable_solidColor,
            checkable_strokeColor,
            checkable_strokeWidth,
            checkable_strokeDash,
            checkable_strokeDashGap,
            checkable_radius,
            checkable_radiusLT,
            checkable_radiusLB,
            checkable_radiusRT,
            checkable_radiusRB,
            checkable_startColor,
            checkable_centerColor,
            checkable_endColor,
            checkable_orientation,
            checkable_gradientType,
            checkable_radialCenterX,
            checkable_radialCenterY,
            checkable_radialRadius,
            checkable_width,
            checkable_height,
            checkable_marginLeft,
            checkable_marginTop,
            checkable_marginRight,
            checkable_marginBottom,
            checkable_ringThickness,
            checkable_ringThicknessRatio,
            checkable_ringInnerRadius,
            checkable_ringInnerRadiusRatio
        );
        if (checkableDrawable != null) {
            count++;
        }
        Drawable enabledDrawable = drawable_enabled != null ? drawable_enabled : create(
            enabled_shapeMode,
            enabled_solidColor,
            enabled_strokeColor,
            enabled_strokeWidth,
            enabled_strokeDash,
            enabled_strokeDashGap,
            enabled_radius,
            enabled_radiusLT,
            enabled_radiusLB,
            enabled_radiusRT,
            enabled_radiusRB,
            enabled_startColor,
            enabled_centerColor,
            enabled_endColor,
            enabled_orientation,
            enabled_gradientType,
            enabled_radialCenterX,
            enabled_radialCenterY,
            enabled_radialRadius,
            enabled_width,
            enabled_height,
            enabled_marginLeft,
            enabled_marginTop,
            enabled_marginRight,
            enabled_marginBottom,
            enabled_ringThickness,
            enabled_ringThicknessRatio,
            enabled_ringInnerRadius,
            enabled_ringInnerRadiusRatio
        );
        if (enabledDrawable != null) {
            count++;
        }
        Drawable focusedDrawable = drawable_focused != null ? drawable_focused : create(
            focused_shapeMode,
            focused_solidColor,
            focused_strokeColor,
            focused_strokeWidth,
            focused_strokeDash,
            focused_strokeDashGap,
            focused_radius,
            focused_radiusLT,
            focused_radiusLB,
            focused_radiusRT,
            focused_radiusRB,
            focused_startColor,
            focused_centerColor,
            focused_endColor,
            focused_orientation,
            focused_gradientType,
            focused_radialCenterX,
            focused_radialCenterY,
            focused_radialRadius,
            focused_width,
            focused_height,
            focused_marginLeft,
            focused_marginTop,
            focused_marginRight,
            focused_marginBottom,
            focused_ringThickness,
            focused_ringThicknessRatio,
            focused_ringInnerRadius,
            focused_ringInnerRadiusRatio
        );
        if (focusedDrawable != null) {
            count++;
        }
        Drawable pressedDrawable = drawable_pressed != null ? drawable_pressed : create(
            pressed_shapeMode,
            pressed_solidColor,
            pressed_strokeColor,
            pressed_strokeWidth,
            pressed_strokeDash,
            pressed_strokeDashGap,
            pressed_radius,
            pressed_radiusLT,
            pressed_radiusLB,
            pressed_radiusRT,
            pressed_radiusRB,
            pressed_startColor,
            pressed_centerColor,
            pressed_endColor,
            pressed_orientation,
            pressed_gradientType,
            pressed_radialCenterX,
            pressed_radialCenterY,
            pressed_radialRadius,
            pressed_width,
            pressed_height,
            pressed_marginLeft,
            pressed_marginTop,
            pressed_marginRight,
            pressed_marginBottom,
            pressed_ringThickness,
            pressed_ringThicknessRatio,
            pressed_ringInnerRadius,
            pressed_ringInnerRadiusRatio
        );
        if (pressedDrawable != null) {
            count++;
        }
        Drawable selectedDrawable = drawable_selected != null ? drawable_selected : create(
            selected_shapeMode,
            selected_solidColor,
            selected_strokeColor,
            selected_strokeWidth,
            selected_strokeDash,
            selected_strokeDashGap,
            selected_radius,
            selected_radiusLT,
            selected_radiusLB,
            selected_radiusRT,
            selected_radiusRB,
            selected_startColor,
            selected_centerColor,
            selected_endColor,
            selected_orientation,
            selected_gradientType,
            selected_radialCenterX,
            selected_radialCenterY,
            selected_radialRadius,
            selected_width,
            selected_height,
            selected_marginLeft,
            selected_marginTop,
            selected_marginRight,
            selected_marginBottom,
            selected_ringThickness,
            selected_ringThicknessRatio,
            selected_ringInnerRadius,
            selected_ringInnerRadiusRatio
        );
        if (selectedDrawable != null) {
            count++;
        }
        //noinspection StatementWithEmptyBody
        if (count < 1) {
            // impossible，因为该方法被调用说明至少声明了一条属性
        } else {
            boolean needReSetPadding = false;
            if (isDefaultNull || count == 1) {
                // 当设置了margin（非view的margin）时，InsetDrawable会导致view本身的padding失效
                needReSetPadding = true;
                TMP_PADDING[0] = view.getPaddingLeft();
                TMP_PADDING[1] = view.getPaddingTop();
                TMP_PADDING[2] = view.getPaddingRight();
                TMP_PADDING[3] = view.getPaddingBottom();
            }
            if (count == 1 && !isDefaultNull) {
                view.setBackground(defaultDrawable);
            } else {
                ProxyDrawable listDrawable = new ProxyDrawable();
                if (checkedDrawable != null) {
                    listDrawable.addState(new int[]{android.R.attr.state_checked}, checkedDrawable);
                }
                if (checkableDrawable != null) {
                    listDrawable.addState(new int[]{android.R.attr.state_checkable}, checkableDrawable);
                }
                if (enabledDrawable != null) {
                    listDrawable.addState(new int[]{android.R.attr.state_enabled}, enabledDrawable);
                }
                if (focusedDrawable != null) {
                    listDrawable.addState(new int[]{android.R.attr.state_focused}, focusedDrawable);
                }
                if (pressedDrawable != null) {
                    listDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
                }
                if (selectedDrawable != null) {
                    listDrawable.addState(new int[]{android.R.attr.state_selected}, selectedDrawable);
                }
                if (defaultDrawable != null) {
                    listDrawable.addState(new int[]{0}, defaultDrawable);
                } else {
                    Drawable originDrawable = view.getBackground();
                    if (originDrawable != null) {
                        if (originDrawable instanceof ProxyDrawable) {
                            originDrawable = ((ProxyDrawable) originDrawable).getOriginDrawable();
                        }
                        listDrawable.addState(new int[]{0}, originDrawable);
                    }
                }
                view.setBackground(listDrawable);
            }
            if (needReSetPadding) {
                view.setPadding(TMP_PADDING[0], TMP_PADDING[1], TMP_PADDING[2], TMP_PADDING[3]);
            }
        }
    }

    public static Drawable create(
        @ShapeMode int shapeMode, @ColorInt Integer solidColor,
        @ColorInt int strokeColor, @DP float strokeWidth, @DP float strokeDash, @DP float strokeDashGap,
        @DP float radius, @DP float radiusLT, @DP float radiusLB, @DP float radiusRT, @DP float radiusRB,
        @ColorInt Integer startColor, @ColorInt Integer centerColor, @ColorInt Integer endColor,
        @Orientation int orientation, @GradientType int gradientType,
        Float radialCenterX, Float radialCenterY, float radialRadius,
        @DP float width, @DP float height,
        @DP float marginLeft, @DP float marginTop, @DP float marginRight, @DP float marginBottom,
        @DP float ringThickness,
        @DP float ringThicknessRatio,
        @DP float ringInnerRadius,
        @DP float ringInnerRadiusRatio
    ) {
        if (shapeMode == INVALID && solidColor == null && strokeColor == INVALID
            && strokeWidth == INVALID && strokeDash == INVALID && strokeDashGap == INVALID
            && radius == INVALID && radiusLT == INVALID && radiusLB == INVALID
            && radiusRT == INVALID && radiusRB == INVALID && startColor == null
            && centerColor == null && endColor == null && orientation == INVALID
            && gradientType == INVALID && radialCenterX == null && radialCenterY == null
            && radialRadius == INVALID && width == INVALID && height == INVALID
            && marginLeft == INVALID && marginTop == INVALID && marginRight == INVALID && marginBottom == INVALID
        ) {
            // 这里需要判断empty，因为有可能只设置了一个state的drawable，那么其他state的就是empty了
            return null;
        }
        GradientDrawable drawable = new GradientDrawable();
        if (startColor != null && endColor != null) {
            int[] colors;
            if (centerColor != null) {
                colors = new int[3];
                colors[0] = startColor;
                colors[1] = centerColor;
                colors[2] = endColor;
            } else {
                colors = new int[2];
                colors[0] = startColor;
                colors[1] = endColor;
            }
            drawable.setColors(colors);
            drawable.setOrientation(mapOrientation(orientation));
            drawable.setGradientType(gradientType);
            if (gradientType == GradientType.RADIAL) {
                drawable.setGradientCenter(radialCenterX == null ? .5f : radialCenterX,
                    radialCenterY == null ? .5f : radialCenterY);
                drawable.setGradientRadius(dip2px(radialRadius));
            }
        } else {
            if (solidColor != null) {
                drawable.setColor(solidColor);
            }
        }
        drawable.setShape(validShapeMode(shapeMode));
        if (shapeMode == ShapeMode.RING) {
            // 由于GradientDrawable中没有ring相关的公开API，所以使用反射，若对性能有要求，请注意。
            setRingValue(drawable, ringThickness, ringThicknessRatio, ringInnerRadius, ringInnerRadiusRatio);
        }
        if (strokeWidth > 0) {
            drawable.setStroke(dip2px(strokeWidth), strokeColor, dip2px(strokeDash), dip2px(strokeDashGap));
        }
        if (radius <= 0) {
            float[] radiusEach = new float[]{dip2px(radiusLT), dip2px(radiusLT), dip2px(radiusRT), dip2px(radiusRT),
                dip2px(radiusRB), dip2px(radiusRB), dip2px(radiusLB), dip2px(radiusLB)};
            drawable.setCornerRadii(radiusEach);
        } else {
            drawable.setCornerRadius(dip2px(radius));
        }
        if (width > 0 && height > 0) {
            // https://stackoverflow.com/a/29180660/4698946
            drawable.setSize(dip2px(width), dip2px(height));
        }
        if (marginLeft != 0 || marginTop != 0 || marginRight != 0 || marginBottom != 0) {
            return new InsetDrawable(drawable,
                dip2px(marginLeft),
                dip2px(marginTop),
                dip2px(marginRight),
                dip2px(marginBottom));
        } else {
            return drawable;
        }
    }

    private static int validShapeMode(@ShapeMode int shapeMode) {
        return shapeMode > ShapeMode.RING || shapeMode < ShapeMode.RECTANGLE
            ? GradientDrawable.RECTANGLE : shapeMode;
    }

    private static GradientDrawable.Orientation mapOrientation(@Orientation int orientation) {
        switch (orientation) {
            case Orientation.BL_TR:
                return GradientDrawable.Orientation.BL_TR;
            case Orientation.BOTTOM_TOP:
                return GradientDrawable.Orientation.BOTTOM_TOP;
            case Orientation.BR_TL:
                return GradientDrawable.Orientation.BR_TL;
            case Orientation.LEFT_RIGHT:
                return GradientDrawable.Orientation.LEFT_RIGHT;
            case Orientation.RIGHT_LEFT:
                return GradientDrawable.Orientation.RIGHT_LEFT;
            case Orientation.TL_BR:
                return GradientDrawable.Orientation.TL_BR;
            case Orientation.TOP_BOTTOM:
                return GradientDrawable.Orientation.TOP_BOTTOM;
            case Orientation.TR_BL:
                return GradientDrawable.Orientation.TR_BL;
            default:
                break;
        }
        return GradientDrawable.Orientation.TOP_BOTTOM;
    }

    private static void setRingValue(GradientDrawable drawable,
                                     Float thickness, Float thicknessRatio,
                                     Float innerRadius, Float innerRadiusRatio) {
        try {
            Field mGradientState = drawable.getClass().getDeclaredField("mGradientState");
            mGradientState.setAccessible(true);
            Class mGradientStateClass = mGradientState.get(drawable).getClass();
            Field mUseLevelForShape = mGradientStateClass.getDeclaredField("mUseLevelForShape");
            mUseLevelForShape.setAccessible(true);
            mUseLevelForShape.setBoolean(mGradientState.get(drawable), false);
            if (thickness != null) {
                Field mThickness = mGradientStateClass.getDeclaredField("mThickness");
                mThickness.setAccessible(true);
                mThickness.setInt(mGradientState.get(drawable), dip2px(thickness));
            }
            if (thicknessRatio != null) {
                Field mThicknessRatio = mGradientStateClass.getDeclaredField("mThicknessRatio");
                mThicknessRatio.setAccessible(true);
                mThicknessRatio.setFloat(mGradientState.get(drawable), dip2px(thicknessRatio));
            }
            if (innerRadius != null) {
                Field mInnerRadius = mGradientStateClass.getDeclaredField("mInnerRadius");
                mInnerRadius.setAccessible(true);
                mInnerRadius.setInt(mGradientState.get(drawable), dip2px(innerRadius));
            }
            if (innerRadiusRatio != null) {
                Field mInnerRadiusRatio = mGradientStateClass.getDeclaredField("mInnerRadiusRatio");
                mInnerRadiusRatio.setAccessible(true);
                mInnerRadiusRatio.setFloat(mGradientState.get(drawable), dip2px(innerRadiusRatio));
            }
        } catch (NoSuchFieldException | IllegalAccessException t) {
            t.printStackTrace();
        }
    }

    private static int dip2px(float dipValue) {
        final float scale = Resources.getSystem().getDisplayMetrics().density;
        return (int) (dipValue * scale + .5f);
    }

    @IntDef({
        ShapeMode.RECTANGLE,
        ShapeMode.OVAL,
        ShapeMode.LINE,
        ShapeMode.RING,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ShapeMode {
        int RECTANGLE = GradientDrawable.RECTANGLE;
        int OVAL = GradientDrawable.OVAL;
        /**
         * 画线时，有几点特性必须要知道的：
         * 1. 只能画水平线，画不了竖线；
         * 2. 线的高度是通过stroke的android:width属性设置的；
         * 3. size的android:height属性定义的是整个形状区域的高度；
         * 4. size的height必须大于stroke的width，否则，线无法显示；
         * 5. 线在整个形状区域中是居中显示的；
         * 6. 线左右两边会留有空白间距，线越粗，空白越大；
         * 7. 引用虚线的view需要添加属性android:layerType，值设为"software"，否则显示不了虚线。
         */
        int LINE = GradientDrawable.LINE;
        int RING = GradientDrawable.RING;
    }

    @IntDef({
        GradientType.LINEAR,
        GradientType.RADIAL,
        GradientType.SWEEP
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface GradientType {
        int LINEAR = 0;
        int RADIAL = 1;
        int SWEEP = 2;
    }

    @IntDef({
        Orientation.TOP_BOTTOM,
        Orientation.TR_BL,
        Orientation.RIGHT_LEFT,
        Orientation.BR_TL,
        Orientation.BOTTOM_TOP,
        Orientation.BL_TR,
        Orientation.LEFT_RIGHT,
        Orientation.TL_BR
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Orientation {
        int TOP_BOTTOM = 0;
        int TR_BL = 1;
        int RIGHT_LEFT = 2;
        int BR_TL = 3;
        int BOTTOM_TOP = 4;
        int BL_TR = 5;
        int LEFT_RIGHT = 6;
        int TL_BR = 7;
    }

    @Retention(RetentionPolicy.SOURCE)
    @Target({PARAMETER, FIELD})
    @interface DP {
    }

    public static class ProxyDrawable extends StateListDrawable {

        private Drawable originDrawable;

        @Override
        public void addState(int[] stateSet, Drawable drawable) {
            if (stateSet != null && stateSet.length == 1 && stateSet[0] == 0) {
                originDrawable = drawable;
            }
            super.addState(stateSet, drawable);
        }

        Drawable getOriginDrawable() {
            return originDrawable;
        }
    }
}
