/*
 * Copyright (C) 2015 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 com.android.setupwizardlib.view;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.widget.Button;

/**
 * Button for navigation bar, which includes tinting of its compound drawables to be used for dark
 * and light themes.
 */
public class NavigationBarButton extends Button {

    public NavigationBarButton(Context context) {
        super(context);
        init();
    }

    public NavigationBarButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        // Unfortunately, drawableStart and drawableEnd set through XML does not call the setter,
        // so manually getting it and wrapping it in the compat drawable.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            Drawable[] drawables = getCompoundDrawablesRelative();
            for (int i = 0; i < drawables.length; i++) {
                if (drawables[i] != null) {
                    drawables[i] = TintedDrawable.wrap(drawables[i]);
                }
            }
            setCompoundDrawablesRelativeWithIntrinsicBounds(drawables[0], drawables[1],
                    drawables[2], drawables[3]);
        }
    }

    @Override
    public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
        if (left != null) left = TintedDrawable.wrap(left);
        if (top != null) top = TintedDrawable.wrap(top);
        if (right != null) right = TintedDrawable.wrap(right);
        if (bottom != null) bottom = TintedDrawable.wrap(bottom);
        super.setCompoundDrawables(left, top, right, bottom);
        tintDrawables();
    }

    @Override
    public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end,
            Drawable bottom) {
        if (start != null) start = TintedDrawable.wrap(start);
        if (top != null) top = TintedDrawable.wrap(top);
        if (end != null) end = TintedDrawable.wrap(end);
        if (bottom != null) bottom = TintedDrawable.wrap(bottom);
        super.setCompoundDrawablesRelative(start, top, end, bottom);
        tintDrawables();
    }

    @Override
    public void setTextColor(ColorStateList colors) {
        super.setTextColor(colors);
        tintDrawables();
    }

    private void tintDrawables() {
        final ColorStateList textColors = getTextColors();
        if (textColors != null) {
            for (Drawable drawable : getAllCompoundDrawables()) {
                if (drawable instanceof TintedDrawable) {
                    ((TintedDrawable) drawable).setTintListCompat(textColors);
                }
            }
            invalidate();
        }
    }

    private Drawable[] getAllCompoundDrawables() {
        Drawable[] drawables = new Drawable[6];
        Drawable[] compoundDrawables = getCompoundDrawables();
        drawables[0] = compoundDrawables[0];  // left
        drawables[1] = compoundDrawables[1];  // top
        drawables[2] = compoundDrawables[2];  // right
        drawables[3] = compoundDrawables[3];  // bottom
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            Drawable[] compoundDrawablesRelative = getCompoundDrawablesRelative();
            drawables[4] = compoundDrawablesRelative[0];  // start
            drawables[5] = compoundDrawablesRelative[2];  // end
        }
        return drawables;
    }

    // TODO: Remove this class and use DrawableCompat.wrap() once we can use support library 22.1.0
    // or above
    private static class TintedDrawable extends LayerDrawable {

        public static TintedDrawable wrap(Drawable drawable) {
            if (drawable instanceof TintedDrawable) {
                return (TintedDrawable) drawable;
            }
            return new TintedDrawable(drawable.mutate());
        }

        private ColorStateList mTintList = null;

        TintedDrawable(Drawable wrapped) {
            super(new Drawable[] { wrapped });
        }

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

        @Override
        public boolean setState(@NonNull int[] stateSet) {
            boolean needsInvalidate = super.setState(stateSet);
            boolean needsInvalidateForState = updateState();
            return needsInvalidate || needsInvalidateForState;
        }

        public void setTintListCompat(ColorStateList colors) {
            mTintList = colors;
            if (updateState()) {
                invalidateSelf();
            }
        }

        private boolean updateState() {
            if (mTintList != null) {
                final int color = mTintList.getColorForState(getState(), 0);
                setColorFilter(color, PorterDuff.Mode.SRC_IN);
                return true;  // Needs invalidate
            }
            return false;
        }
    }
}
