package com.kongzue.dialogx.dialogs;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Outline;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;

import com.kongzue.dialogx.DialogX;
import com.kongzue.dialogx.R;
import com.kongzue.dialogx.interfaces.BaseDialog;
import com.kongzue.dialogx.interfaces.BaseOnDialogClickCallback;
import com.kongzue.dialogx.interfaces.BlurViewType;
import com.kongzue.dialogx.interfaces.BottomDialogSlideEventLifecycleCallback;
import com.kongzue.dialogx.interfaces.DialogConvertViewInterface;
import com.kongzue.dialogx.interfaces.DialogLifecycleCallback;
import com.kongzue.dialogx.interfaces.DialogXAnimInterface;
import com.kongzue.dialogx.interfaces.DialogXBaseBottomDialog;
import com.kongzue.dialogx.interfaces.DialogXRunnable;
import com.kongzue.dialogx.interfaces.DialogXStyle;
import com.kongzue.dialogx.interfaces.OnBackPressedListener;
import com.kongzue.dialogx.interfaces.OnBackgroundMaskClickListener;
import com.kongzue.dialogx.interfaces.OnBindView;
import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialogx.interfaces.OnMenuButtonClickListener;
import com.kongzue.dialogx.interfaces.ScrollController;
import com.kongzue.dialogx.util.BottomDialogTouchEventInterceptor;
import com.kongzue.dialogx.util.TextInfo;
import com.kongzue.dialogx.util.views.DialogScrollView;
import com.kongzue.dialogx.util.views.DialogXBaseRelativeLayout;
import com.kongzue.dialogx.util.views.MaxRelativeLayout;

import java.util.HashMap;
import java.util.List;

/**
 * @author: Kongzue
 * @github: https://github.com/kongzue/
 * @homepage: http://kongzue.com/
 * @mail: myzcxhh@live.cn
 * @createTime: 2020/10/6 15:17
 */
public class BottomDialog extends BaseDialog implements DialogXBaseBottomDialog {

    public static int overrideEnterDuration = -1;
    public static int overrideExitDuration = -1;
    public static BOOLEAN overrideCancelable;
    protected OnBindView<BottomDialog> onBindView;
    protected CharSequence title;
    protected CharSequence message;
    protected CharSequence cancelText;
    protected CharSequence okText;
    protected CharSequence otherText;
    protected boolean allowInterceptTouch = true;
    protected boolean bottomNonSafetyAreaBySelf = false;
    protected Integer maskColor = null;
    protected BaseOnDialogClickCallback cancelButtonClickListener;
    protected BaseOnDialogClickCallback okButtonClickListener;
    protected BaseOnDialogClickCallback otherButtonClickListener;
    protected OnBackgroundMaskClickListener<BottomDialog> onBackgroundMaskClickListener;
    protected OnBackPressedListener<BottomDialog> onBackPressedListener;
    protected BOOLEAN privateCancelable;
    protected boolean bkgInterceptTouch = true;
    protected float backgroundRadius = DialogX.defaultBottomDialogBackgroundRadius;
    protected Drawable titleIcon;
    protected DialogXAnimInterface<BottomDialog> dialogXAnimImpl;
    protected BUTTON_SELECT_RESULT buttonSelectResult = BUTTON_SELECT_RESULT.NONE;
    protected boolean scrollableWhenContentLargeThanVisibleRange = true;

    protected TextInfo titleTextInfo;
    protected TextInfo messageTextInfo;
    protected TextInfo menuTextInfo;
    protected TextInfo cancelTextInfo = new TextInfo().setBold(true);
    protected TextInfo okTextInfo = new TextInfo().setBold(true);
    protected TextInfo otherTextInfo = new TextInfo().setBold(true);

    /**
     * 此值用于，当禁用滑动时（style.overrideBottomDialogRes.touchSlide = false时）的最大显示高度。
     * 0：不限制，最大显示到屏幕可用高度。
     */
    protected float bottomDialogMaxHeight = 0f;

    protected DialogLifecycleCallback<BottomDialog> dialogLifecycleCallback;

    protected BottomDialog me = this;

    protected BottomDialog() {
        super();
    }

    @Override
    public String dialogKey() {
        return getClass().getSimpleName() + "(" + Integer.toHexString(hashCode()) + ")";
    }

    public static BottomDialog build() {
        return new BottomDialog();
    }

    public static BottomDialog build(DialogXStyle style) {
        return new BottomDialog().setStyle(style);
    }

    public static BottomDialog build(OnBindView<BottomDialog> onBindView) {
        return new BottomDialog().setCustomView(onBindView);
    }

    public static BottomDialog show(CharSequence title, CharSequence message) {
        BottomDialog bottomDialog = new BottomDialog(title, message);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, int messageResId) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(CharSequence title, CharSequence message, OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(title, message, onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, int messageResId, OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(CharSequence title, OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(title, onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, int messageResId, int okTextResId) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, okTextResId);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, okTextResId, cancelTextResId);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, int messageResId, int okTextResId, OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, okTextResId, onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public static BottomDialog show(int titleResId, int messageResId, int okTextResId, int cancelTextResId, OnBindView<BottomDialog> onBindView) {
        BottomDialog bottomDialog = new BottomDialog(titleResId, messageResId, okTextResId, cancelTextResId, onBindView);
        bottomDialog.show();
        return bottomDialog;
    }

    public BottomDialog(OnBindView<BottomDialog> onBindView) {
        this.onBindView = onBindView;
    }

    public BottomDialog(CharSequence title, OnBindView<BottomDialog> onBindView) {
        this.title = title;
        this.onBindView = onBindView;
    }

    public BottomDialog(int titleResId, OnBindView<BottomDialog> onBindView) {
        this.title = getString(titleResId);
        this.onBindView = onBindView;
    }

    public BottomDialog(CharSequence title, CharSequence message) {
        this.title = title;
        this.message = message;
    }

    public BottomDialog(int titleResId, int messageResId) {
        this.title = getString(titleResId);
        this.message = getString(messageResId);
    }

    public BottomDialog(CharSequence title, CharSequence message, OnBindView<BottomDialog> onBindView) {
        this.title = title;
        this.message = message;
        this.onBindView = onBindView;
    }

    public BottomDialog(int titleResId, int messageResId, OnBindView<BottomDialog> onBindView) {
        this.title = getString(titleResId);
        this.message = getString(messageResId);
        this.onBindView = onBindView;
    }

    public BottomDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId) {
        this.title = getString(titleResId);
        this.message = getString(messageResId);
        this.okText = getString(okTextResId);
        this.cancelText = getString(cancelTextResId);
    }

    public BottomDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText) {
        this.title = title;
        this.message = message;
        this.okText = okText;
        this.cancelText = cancelText;
    }

    public BottomDialog(int titleResId, int messageResId, int okTextResId) {
        this.title = getString(titleResId);
        this.message = getString(messageResId);
        this.okText = getString(okTextResId);
    }

    public BottomDialog(CharSequence title, CharSequence message, CharSequence okText) {
        this.title = title;
        this.message = message;
        this.okText = okText;
    }

    public BottomDialog(int titleResId, int messageResId, int okTextResId, OnBindView<BottomDialog> onBindView) {
        this.title = getString(titleResId);
        this.message = getString(messageResId);
        this.okText = getString(okTextResId);
        this.onBindView = onBindView;
    }

    public BottomDialog(CharSequence title, CharSequence message, CharSequence okText, OnBindView<BottomDialog> onBindView) {
        this.title = title;
        this.message = message;
        this.okText = okText;
        this.onBindView = onBindView;
    }

    public BottomDialog(int titleResId, int messageResId, int okTextResId, int cancelTextResId, OnBindView<BottomDialog> onBindView) {
        this.title = getString(titleResId);
        this.message = getString(messageResId);
        this.okText = getString(okTextResId);
        this.cancelText = getString(cancelTextResId);
        this.onBindView = onBindView;
    }

    public BottomDialog(CharSequence title, CharSequence message, CharSequence okText, CharSequence cancelText, OnBindView<BottomDialog> onBindView) {
        this.title = title;
        this.message = message;
        this.okText = okText;
        this.cancelText = cancelText;
        this.onBindView = onBindView;
    }

    public BottomDialog show() {
        if (isHide && getDialogView() != null && isShow) {
            if (hideWithExitAnim && getDialogImpl() != null) {
                getDialogView().setVisibility(View.VISIBLE);
                getDialogImpl().getDialogXAnimImpl().doShowAnim(me, getDialogImpl().bkg);
            } else {
                getDialogView().setVisibility(View.VISIBLE);
            }
            return this;
        }
        super.beforeShow();
        if (getDialogView() == null) {
            int layoutId = isLightTheme() ? R.layout.layout_dialogx_bottom_material : R.layout.layout_dialogx_bottom_material_dark;
            if (style.overrideBottomDialogRes() != null) {
                layoutId = style.overrideBottomDialogRes().overrideDialogLayout(isLightTheme());
            }
            layoutId = getCustomDialogLayoutResId(isLightTheme()) != 0 ? getCustomDialogLayoutResId(isLightTheme()) : layoutId;

            View dialogView = createView(layoutId);
            dialogImpl = new DialogImpl(dialogView);
            if (dialogView != null) dialogView.setTag(me);
            show(dialogView);
        } else {
            show(getDialogView());
        }
        return this;
    }

    public void show(Activity activity) {
        super.beforeShow();
        if (getDialogView() == null) {
            int layoutId = isLightTheme() ? R.layout.layout_dialogx_bottom_material : R.layout.layout_dialogx_bottom_material_dark;
            if (style.overrideBottomDialogRes() != null) {
                layoutId = style.overrideBottomDialogRes().overrideDialogLayout(isLightTheme());
            }
            layoutId = getCustomDialogLayoutResId(isLightTheme()) != 0 ? getCustomDialogLayoutResId(isLightTheme()) : layoutId;

            View dialogView = createView(layoutId);
            dialogImpl = new DialogImpl(dialogView);
            if (dialogView != null) dialogView.setTag(me);
            show(activity, dialogView);
        } else {
            show(activity, getDialogView());
        }
    }

    protected DialogImpl dialogImpl;

    public class DialogImpl implements DialogConvertViewInterface {

        private BottomDialogTouchEventInterceptor bottomDialogTouchEventInterceptor;

        public DialogXBaseRelativeLayout boxRoot;
        public RelativeLayout boxBkg;
        public MaxRelativeLayout bkg;
        public ImageView imgTab;
        public ViewGroup boxBody;
        public TextView txtDialogTitle;
        public ScrollController scrollView;
        public LinearLayout boxContent;
        public TextView txtDialogTip;
        public View imgSplit;
        public ViewGroup boxList;
        public RelativeLayout boxCustom;
        public ViewGroup boxCancel;
        public ImageView splitSelectPositive;
        public ImageView splitSelectOther;

        public LinearLayout boxButton;
        public TextView btnSelectNegative;
        public TextView btnSelectOther;
        public TextView btnSelectPositive;

        private List<View> blurViews;

        public DialogImpl(View convertView) {
            if (convertView == null) return;
            setDialogView(convertView);
            boxRoot = convertView.findViewById(R.id.box_root);
            boxBkg = convertView.findViewById(R.id.box_bkg);
            bkg = convertView.findViewById(R.id.bkg);
            imgTab = convertView.findViewById(R.id.img_tab);
            boxBody = convertView.findViewById(R.id.box_body);
            txtDialogTitle = convertView.findViewById(R.id.txt_dialog_title);
            scrollView = convertView.findViewById(R.id.scrollView);
            boxContent = convertView.findViewById(R.id.box_content);
            txtDialogTip = convertView.findViewById(R.id.txt_dialog_tip);
            imgSplit = convertView.findViewWithTag("split");
            boxList = convertView.findViewById(R.id.box_list);
            boxCustom = convertView.findViewById(R.id.box_custom);

            if (!scrollableWhenContentLargeThanVisibleRange) {
                ViewGroup bodyContent = (ViewGroup) txtDialogTitle.getParent();
                ((ViewGroup) boxContent.getParent()).removeView(boxContent);
                bodyContent.addView(boxContent, 1, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            }
            boxCancel = convertView.findViewWithTag("cancelBox");

            boxButton = convertView.findViewById(R.id.box_button);
            btnSelectNegative = convertView.findViewById(R.id.btn_selectNegative);
            btnSelectOther = convertView.findViewById(R.id.btn_selectOther);
            btnSelectPositive = convertView.findViewById(R.id.btn_selectPositive);
            splitSelectPositive = convertView.findViewWithTag("imgPositiveButtonSplit");
            splitSelectOther = convertView.findViewWithTag("imgOtherButtonSplit");

            blurViews = findAllBlurView(convertView);

            init();
            dialogImpl = this;
            refreshView();
        }

        public void reBuild() {
            init();
            dialogImpl = this;
            refreshView();
        }

        /**
         * 此值记录了BottomDialog启动后的位置
         * ·当内容高度大于屏幕安全区高度时，BottomDialog会以全屏方式启动，但一开始只会展开到 0.8×屏幕高度，
         * 此时可以再次上划查看全部内容。
         * ·当内容高度小于屏幕安全区高度时，BottomDialog会以内容高度启动。
         * <p>
         * 记录这个值的目的是，当用户向下滑动时，判断情况该回到这个位置还是关闭对话框，
         * 并阻止当内容高度已经完全显示时的继续向上滑动操作。
         */
        public float bkgEnterAimY = -1;

        @Override
        public void init() {
            buttonSelectResult = BUTTON_SELECT_RESULT.NONE;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                getDialogView().setTranslationZ(getThisOrderIndex());
            }

            if (titleTextInfo == null) titleTextInfo = DialogX.titleTextInfo;
            if (messageTextInfo == null) messageTextInfo = DialogX.messageTextInfo;
            if (okTextInfo == null) okTextInfo = DialogX.okButtonTextInfo;
            if (okTextInfo == null) okTextInfo = DialogX.buttonTextInfo;
            if (cancelTextInfo == null) cancelTextInfo = DialogX.buttonTextInfo;
            if (otherTextInfo == null) otherTextInfo = DialogX.buttonTextInfo;
            if (backgroundColor == null) backgroundColor = DialogX.backgroundColor;
            if (cancelText == null) cancelText = DialogX.cancelButtonText;

            if (txtDialogTitle != null) txtDialogTitle.getPaint().setFakeBoldText(true);
            if (btnSelectNegative != null) btnSelectNegative.getPaint().setFakeBoldText(true);
            if (btnSelectPositive != null) btnSelectPositive.getPaint().setFakeBoldText(true);
            if (btnSelectOther != null) btnSelectOther.getPaint().setFakeBoldText(true);

            boxBkg.setY(getRootFrameLayout() == null ? Resources.getSystem().getDisplayMetrics().heightPixels : getRootFrameLayout().getMeasuredHeight());

            boxRoot.setParentDialog(me);
            boxRoot.setOnLifecycleCallBack(new DialogXBaseRelativeLayout.OnLifecycleCallBack() {
                @Override
                public void onShow() {

                    isShow = true;
                    preShow = false;

                    setLifecycleState(Lifecycle.State.CREATED);
                    getDialogLifecycleCallback().onShow(me);
                    BottomDialog.this.onShow(me);

                    onDialogShow();

                    refreshUI();
                }

                @Override
                public void onDismiss() {
                    isShow = false;
                    getDialogLifecycleCallback().onDismiss(me);
                    BottomDialog.this.onDismiss(me);
                    setLifecycleState(Lifecycle.State.DESTROYED);
                    dialogImpl = null;
                    bottomDialogTouchEventInterceptor = null;
                    dialogLifecycleCallback = null;
                    BaseDialog.gc();
                }
            });

            if (btnSelectNegative != null) {
                btnSelectNegative.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        haptic(v);
                        buttonSelectResult = BUTTON_SELECT_RESULT.BUTTON_CANCEL;
                        if (cancelButtonClickListener != null) {
                            if (cancelButtonClickListener instanceof OnDialogButtonClickListener) {
                                if (!((OnDialogButtonClickListener) cancelButtonClickListener).onClick(me, v)) {
                                    dismiss();
                                }
                            } else if (cancelButtonClickListener instanceof OnMenuButtonClickListener) {
                                if (!((OnMenuButtonClickListener) cancelButtonClickListener).onClick(me, v)) {
                                    dismiss();
                                }
                            }
                        } else {
                            dismiss();
                        }
                    }
                });
            }
            if (btnSelectOther != null) {
                btnSelectOther.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        haptic(v);
                        buttonSelectResult = BUTTON_SELECT_RESULT.BUTTON_OTHER;
                        if (otherButtonClickListener != null) {
                            if (otherButtonClickListener instanceof OnDialogButtonClickListener) {
                                if (!((OnDialogButtonClickListener) otherButtonClickListener).onClick(me, v)) {
                                    dismiss();
                                }
                            } else if (otherButtonClickListener instanceof OnMenuButtonClickListener) {
                                if (!((OnMenuButtonClickListener) otherButtonClickListener).onClick(me, v)) {
                                    dismiss();
                                }
                            }
                        } else {
                            dismiss();
                        }
                    }
                });
            }
            if (btnSelectPositive != null) {
                btnSelectPositive.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        haptic(v);
                        buttonSelectResult = BUTTON_SELECT_RESULT.BUTTON_OK;
                        if (okButtonClickListener != null) {
                            if (okButtonClickListener instanceof OnDialogButtonClickListener) {
                                if (!((OnDialogButtonClickListener) okButtonClickListener).onClick(me, v)) {
                                    dismiss();
                                }
                            } else if (okButtonClickListener instanceof OnMenuButtonClickListener) {
                                if (!((OnMenuButtonClickListener) okButtonClickListener).onClick(me, v)) {
                                    dismiss();
                                }
                            }
                        } else {
                            dismiss();
                        }
                    }
                });
            }

            if (imgSplit != null) {
                int dividerRes = style.overrideBottomDialogRes().overrideMenuDividerDrawableRes(isLightTheme());
                int dividerHeight = style.overrideBottomDialogRes().overrideMenuDividerHeight(isLightTheme());
                if (dividerRes != 0) imgSplit.setBackgroundResource(dividerRes);
                if (dividerHeight != 0) {
                    ViewGroup.LayoutParams lp = imgSplit.getLayoutParams();
                    lp.height = dividerHeight;
                    imgSplit.setLayoutParams(lp);
                }
            }

            boxRoot.setOnBackPressedListener(new DialogXBaseRelativeLayout.PrivateBackPressedListener() {
                @Override
                public boolean onBackPressed() {
                    if (onBackPressedListener != null) {
                        if (onBackPressedListener.onBackPressed(me)) {
                            dismiss();
                        }
                    } else {
                        if (isCancelable()) {
                            dismiss();
                        }
                    }
                    return true;
                }
            });

            boxBkg.post(new Runnable() {
                @Override
                public void run() {
                    getDialogXAnimImpl().doShowAnim(BottomDialog.this, bkg);

                    Integer blurFrontColor = null;
                    Float dialogXRadius = null;
                    if (style.messageDialogBlurSettings() != null) {
                        blurFrontColor = getColorNullable(getIntStyleAttr(style.messageDialogBlurSettings().blurForwardColorRes(isLightTheme())));
                        dialogXRadius = getFloatStyleAttr((float) style.messageDialogBlurSettings().blurBackgroundRoundRadiusPx());
                    }

                    if (blurViews != null) {
                        for (View blurView : blurViews) {
                            ((BlurViewType) blurView).setOverlayColor(backgroundColor == null ? blurFrontColor : backgroundColor);
                            ((BlurViewType) blurView).setRadiusPx(dialogXRadius);
                        }
                    }
                }
            });

            runOnMainDelay(new Runnable() {
                @Override
                public void run() {
                    bottomDialogTouchEventInterceptor = new BottomDialogTouchEventInterceptor(me, dialogImpl);
                }
            }, getEnterAnimationDuration());

            onDialogInit();
        }

        @Override
        public void refreshView() {
            if (boxRoot == null || getOwnActivity() == null) {
                return;
            }

            bkg.setMaxWidth(getMaxWidth());
            bkg.setMaxHeight(getMaxHeight());
            bkg.setMinimumWidth(getMinWidth());
            bkg.setMinimumHeight(getMinHeight());

            boxRoot.setAutoUnsafePlacePadding(isEnableImmersiveMode());
            boxRoot.setRootPadding(screenPaddings[0], screenPaddings[1], screenPaddings[2], screenPaddings[3]);
            if (backgroundColor != null) {
                tintColor(bkg, backgroundColor);
                if (style.tintButtonBackground()) {
                    tintColor(btnSelectOther, backgroundColor);
                    tintColor(btnSelectNegative, backgroundColor);
                    tintColor(btnSelectPositive, backgroundColor);
                }

                if (blurViews != null) {
                    for (View blurView : blurViews) {
                        ((BlurViewType) blurView).setOverlayColor(backgroundColor);
                    }
                }
            }

            showText(txtDialogTitle, title);
            showText(txtDialogTip, message);

            useTextInfo(txtDialogTitle, titleTextInfo);
            useTextInfo(txtDialogTip, messageTextInfo);
            useTextInfo(btnSelectNegative, cancelTextInfo);
            useTextInfo(btnSelectOther, otherTextInfo);
            useTextInfo(btnSelectPositive, okTextInfo);

            if (boxButton != null) {
                boxButton.setVisibility((btnSelectNegative != null && btnSelectNegative.getVisibility() == View.VISIBLE) ||
                        (btnSelectOther != null && btnSelectOther.getVisibility() == View.VISIBLE) ||
                        (btnSelectPositive != null && btnSelectPositive.getVisibility() == View.VISIBLE) ?
                        View.VISIBLE : View.GONE);
            }
            if (titleIcon != null) {
                int size = (int) txtDialogTitle.getTextSize();
                titleIcon.setBounds(0, 0, size, size);
                txtDialogTitle.setCompoundDrawablePadding(dip2px(10));
                txtDialogTitle.setCompoundDrawables(titleIcon, null, null, null);
            }

            if (bkgInterceptTouch) {
                if (isCancelable()) {
                    boxRoot.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (onBackgroundMaskClickListener == null || !onBackgroundMaskClickListener.onClick(me, v)) {
                                doDismiss(v);
                            }
                        }
                    });
                } else {
                    boxRoot.setOnClickListener(null);
                }
            } else {
                boxRoot.setClickable(false);
            }
            boxBkg.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    boxRoot.callOnClick();
                }
            });
            if (backgroundRadius > -1) {
                if (bkg.getBackground() instanceof GradientDrawable) {
                    GradientDrawable gradientDrawable = (GradientDrawable) bkg.getBackground();
                    if (gradientDrawable != null)
                        gradientDrawable.setCornerRadii(new float[]{backgroundRadius, backgroundRadius, backgroundRadius, backgroundRadius, 0, 0, 0, 0});
                }
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                    bkg.setOutlineProvider(new ViewOutlineProvider() {
                        @Override
                        public void getOutline(View view, Outline outline) {
                            outline.setRoundRect(0, 0, view.getWidth(), (int) (view.getHeight() + backgroundRadius), backgroundRadius);
                        }
                    });
                    bkg.setClipToOutline(true);
                }

                if (blurViews != null) {
                    for (View blurView : blurViews) {
                        ((BlurViewType) blurView).setRadiusPx(backgroundRadius);
                    }
                }
            }

            if (maskColor != null) {
                boxRoot.setBackground(new ColorDrawable(maskColor));
            }

            if (onBindView != null && onBindView.getCustomView() != null) {
                onBindView.bindParent(boxCustom, me);
                if (onBindView.getCustomView() instanceof ScrollController) {
                    if (scrollView instanceof DialogScrollView) {
                        ((DialogScrollView) scrollView).setVerticalScrollBarEnabled(false);
                    }
                    scrollView = (ScrollController) onBindView.getCustomView();
                } else {
                    View scrollController = onBindView.getCustomView().findViewWithTag("ScrollController");
                    if (scrollController instanceof ScrollController) {
                        if (scrollView instanceof DialogScrollView) {
                            ((DialogScrollView) scrollView).setVerticalScrollBarEnabled(false);
                        }
                        scrollView = (ScrollController) scrollController;
                    }
                }
            }

            if (isAllowInterceptTouch() && isCancelable()) {
                if (imgTab != null) imgTab.setVisibility(View.VISIBLE);
            } else {
                if (imgTab != null) imgTab.setVisibility(View.GONE);
            }

            if (bottomDialogTouchEventInterceptor != null) {
                bottomDialogTouchEventInterceptor.refresh(me, this);
            }

            if (imgSplit != null) {
                if (txtDialogTitle.getVisibility() == View.VISIBLE || txtDialogTip.getVisibility() == View.VISIBLE) {
                    imgSplit.setVisibility(View.VISIBLE);
                } else {
                    imgSplit.setVisibility(View.GONE);
                }
            }

            if (boxCancel != null) {
                if (isNull(cancelText)) {
                    boxCancel.setVisibility(View.GONE);
                } else {
                    boxCancel.setVisibility(View.VISIBLE);
                }
            }

            showText(btnSelectPositive, okText);
            showText(btnSelectNegative, cancelText);
            showText(btnSelectOther, otherText);
            if (splitSelectPositive != null) {
                splitSelectPositive.setVisibility(btnSelectPositive.getVisibility());
            }
            if (splitSelectOther != null) {
                splitSelectOther.setVisibility(btnSelectOther.getVisibility());
            }

            onDialogRefreshUI();
        }

        @Override
        public void doDismiss(View v) {
            if (BottomDialog.this.preDismiss(BottomDialog.this)) {
                return;
            }
            if (v != null) v.setEnabled(false);
            if (getOwnActivity() == null) return;
