/*
 * 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 android.support.wearable.view;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.widget.Button;

/**
 * Helper to add icons to AlertDialog buttons.AlertDialog buttons.
 */
public class WearableDialogHelper {
    private static final String TAG = "WearableDialogHelper";

    private int mPositiveIconId;
    private Drawable mPositiveIcon;

    private int mNeutralIconId;
    private Drawable mNeutralIcon;

    private int mNegativeIconId;
    private Drawable mNegativeIcon;

    @VisibleForTesting /* package */ Resources mResources;
    @VisibleForTesting /* package */ Resources.Theme mTheme;

    /**
     * Convenience constructor, equivalent to {@code new WearableDialogHelper(context.getResources(),
     * context.getTheme())}.
     */
    public WearableDialogHelper(@NonNull Context context) {
        this(context.getResources(), context.getTheme());
    }

    /**
     * @param resources the Resources used to obtain Drawables from resource IDs.
     * @param theme the Theme used to properly obtain Drawables from resource IDs.
     */
    public WearableDialogHelper(@NonNull Resources resources, @NonNull Resources.Theme theme) {
        mResources = resources;
        mTheme = theme;
    }

    @Nullable
    public Drawable getPositiveIcon() {
        return resolveDrawable(mPositiveIcon, mPositiveIconId);
    }

    @Nullable
    public Drawable getNegativeIcon() {
        return resolveDrawable(mNegativeIcon, mNegativeIconId);
    }

    @Nullable
    public Drawable getNeutralIcon() {
        return resolveDrawable(mNeutralIcon, mNeutralIconId);
    }

    @NonNull
    public WearableDialogHelper setPositiveIcon(@DrawableRes int resId) {
        mPositiveIconId = resId;
        mPositiveIcon = null;
        return this;
    }

    @NonNull
    public WearableDialogHelper setPositiveIcon(@Nullable Drawable icon) {
        mPositiveIcon = icon;
        mPositiveIconId = 0;
        return this;
    }

    @NonNull
    public WearableDialogHelper setNegativeIcon(@DrawableRes int resId) {
        mNegativeIconId = resId;
        mNegativeIcon = null;
        return this;
    }

    @NonNull
    public WearableDialogHelper setNegativeIcon(@Nullable Drawable icon) {
        mNegativeIcon = icon;
        mNegativeIconId = 0;
        return this;
    }

    @NonNull
    public WearableDialogHelper setNeutralIcon(@DrawableRes int resId) {
        mNeutralIconId = resId;
        mNeutralIcon = null;
        return this;
    }

    @NonNull
    public WearableDialogHelper setNeutralIcon(@Nullable Drawable icon) {
        mNeutralIcon = icon;
        mNeutralIconId = 0;
        return this;
    }

    /**
     * Applies the button icons setup in the helper to the buttons in the dialog.
     *
     * <p>Note that this should be called after {@code AlertDialog.create()}, NOT {@code
     * AlertDialog.Builder.create()}. Calling {@code AlertDialog.Builder.show()} would also accomplish
     * the same thing.
     *
     * @param dialog the AlertDialog to style with the helper.
     */
    public void apply(@NonNull AlertDialog dialog) {
        applyButton(dialog.getButton(DialogInterface.BUTTON_POSITIVE), getPositiveIcon());
        applyButton(dialog.getButton(DialogInterface.BUTTON_NEGATIVE), getNegativeIcon());
        applyButton(dialog.getButton(DialogInterface.BUTTON_NEUTRAL), getNeutralIcon());
    }

    /** Applies the specified drawable to the button. */
    @VisibleForTesting
    /* package */ void applyButton(@Nullable Button button, @Nullable Drawable drawable) {
        if (button != null) {
            button.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
            button.setAllCaps(false);
        } else if (drawable != null) {
            Log.w(TAG, "non-null drawable used with missing button, did you call AlertDialog.create()?");
        }
    }

    /** Obtain a drawable between a drawable and a resource ID. */
    @VisibleForTesting
    /* package */ Drawable resolveDrawable(@Nullable Drawable drawable, @DrawableRes int resId) {
        return drawable == null && resId != 0 ? mResources.getDrawable(resId, mTheme) : drawable;
    }

    /** Convenience builder to generate an AlertDialog with icons in buttons. */
    public static class DialogBuilder extends AlertDialog.Builder {
        private final WearableDialogHelper mHelper;

        public DialogBuilder(Context context) {
            super(context);
            mHelper = new WearableDialogHelper(context.getResources(), context.getTheme());
        }

        public DialogBuilder(Context context, int themeResId) {
            super(context, themeResId);
            mHelper = new WearableDialogHelper(context.getResources(), context.getTheme());
        }

        public WearableDialogHelper getHelper() {
            return mHelper;
        }

        public DialogBuilder setPositiveIcon(@DrawableRes int iconId) {
            mHelper.setPositiveIcon(iconId);
            return this;
        }

        public DialogBuilder setPositiveIcon(@Nullable Drawable icon) {
            mHelper.setPositiveIcon(icon);
            return this;
        }

        public DialogBuilder setNegativeIcon(@DrawableRes int iconId) {
            mHelper.setNegativeIcon(iconId);
            return this;
        }

        public DialogBuilder setNegativeIcon(@Nullable Drawable icon) {
            mHelper.setNegativeIcon(icon);
            return this;
        }

        public DialogBuilder setNeutralIcon(@DrawableRes int iconId) {
            mHelper.setNeutralIcon(iconId);
            return this;
        }

        public DialogBuilder setNeutralIcon(@Nullable Drawable icon) {
            mHelper.setNeutralIcon(icon);
            return this;
        }

        @Override
        public AlertDialog create() {
            final AlertDialog dialog = super.create();
            dialog.create();
            mHelper.apply(dialog);
            return dialog;
        }

        @Override
        public AlertDialog show() {
            final AlertDialog dialog = this.create();
            dialog.show();
            return dialog;
        }
    }
}
