/*
 * Copyright (C) 2014 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.tencent.tws.assistant.widget;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;

import com.tencent.tws.assistant.drawable.TwsAnimatedStateListDrawable;
import com.tencent.tws.assistant.drawable.TwsRippleDrawable;
import com.tencent.tws.assistant.support.v4.widget.TintableCompoundButton;
import com.tencent.tws.assistant.utils.ThemeUtils;
import com.tencent.tws.sharelib.R;

/**
 * A {@link RadioButton} which supports compatible features on older version of the platform, including:
 * <ul>
 * <li>Allows dynamic tint of it background via the background tint methods in
 * {@link android.support.v4.widget.CompoundButtonCompat}.</li>
 * <li>Allows setting of the background tint using {@link R.attr#buttonTint} and {@link R.attr#buttonTintMode}
 * .</li>
 * </ul>
 * 
 * <p>
 * This will automatically be used when you use {@link RadioButton} in your layouts. You should only need to
 * manually use this class when writing custom views.
 * </p>
 */
public class RadioButton extends android.widget.RadioButton implements TintableCompoundButton {

    private TintManager mTintManager;
    private CompoundButtonHelper mCompoundButtonHelper;
    private boolean mIsAnimationButton = true;

    final int[] radioOnDisableState = {android.R.attr.state_checked, -android.R.attr.state_enabled};
    final int radioOnDisableResId = R.drawable.btn_radio_on_disabled_holo_light;
    final int[] radioOffDisableState = {-android.R.attr.state_checked, -android.R.attr.state_enabled};
    final int radioOffDisableResId = R.drawable.btn_radio_off_disabled_holo_light;
    final int[] radioOnState = {android.R.attr.state_checked, android.R.attr.state_enabled};
    final int radioOnResId = R.drawable.btn_radio_to_on_mtrl_010;
    final int[] radioOffState = {-android.R.attr.state_checked, android.R.attr.state_enabled};
    final int radioOffResId = R.drawable.btn_radio_to_on_mtrl_000;
    final int radioOnkeyframeId = R.id.on;
    final int radioOffKeyframeId = R.id.off;
    final int radioToOnResId = R.drawable.btn_radio_to_on_material_anim;
    final int radioToOffResId = R.drawable.btn_radio_to_off_material_anim;
    private Drawable mAnimationButtonDrawable = null;
    private boolean mIsSupportTintDrawable = false;
    private int mColorControlActivated = 0;

    public RadioButton(Context context) {
        this(context, null);
    }

    public RadioButton(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.radioButtonStyle);
    }

    public RadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTintManager = TintManager.get(context);
        mCompoundButtonHelper = new CompoundButtonHelper(this, mTintManager);
        if (mIsAnimationButton) {
            setAnimationButtonDrawable(mIsAnimationButton);
        } else {
            mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
        }
    }

    @Override
    public void setButtonDrawable(Drawable buttonDrawable) {
        super.setButtonDrawable(buttonDrawable);
        if (mCompoundButtonHelper != null && !mIsAnimationButton) {
            mCompoundButtonHelper.onSetButtonDrawable();
        }
    }

    @Override
    public void setButtonDrawable(@DrawableRes int resId) {
        setButtonDrawable((mTintManager != null && !mIsAnimationButton) ? mTintManager.getDrawable(resId)
                : getContext().getResources().getDrawable(resId));
    }

    @Override
    public int getCompoundPaddingLeft() {
        final int value = super.getCompoundPaddingLeft();
        return mCompoundButtonHelper != null ? mCompoundButtonHelper.getCompoundPaddingLeft(value) : value;
    }

    /**
     * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
     * 
     * @hide
     */
    @Override
    public void setSupportButtonTintList(@Nullable ColorStateList tint) {
        if (mCompoundButtonHelper != null) {
            mCompoundButtonHelper.setSupportButtonTintList(tint);
        }
    }

    /**
     * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
     * 
     * @hide
     */
    @Nullable
    @Override
    public ColorStateList getSupportButtonTintList() {
        return mCompoundButtonHelper != null ? mCompoundButtonHelper.getSupportButtonTintList() : null;
    }

    /**
     * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
     * 
     * @hide
     */
    @Override
    public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
        if (mCompoundButtonHelper != null) {
            mCompoundButtonHelper.setSupportButtonTintMode(tintMode);
        }
    }

    /**
     * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
     * 
     * @hide
     */
    @Nullable
    @Override
    public PorterDuff.Mode getSupportButtonTintMode() {
        return mCompoundButtonHelper != null ? mCompoundButtonHelper.getSupportButtonTintMode() : null;
    }

    private void setAnimationButtonDrawable(boolean isAnimation) {
        mIsAnimationButton = isAnimation;
        if (isAnimation) {
            final boolean isSupportTintDrawable = ThemeUtils.isSupportTintDrawable(getContext());
            int colorControlNormal = ThemeUtils.getThemeAttrColor(getContext(), R.attr.colorControlNormal);
            int colorControlActivated = ThemeUtils.getThemeAttrColor(getContext(),
                    R.attr.colorControlActivated);
            int colorControlDisabled = ThemeUtils.getDisabledThemeAttrColor(getContext(),
                    R.attr.colorControlNormal);
            int colorControlActivateDisabled = ThemeUtils.getDisabledThemeAttrColor(getContext(),
                    R.attr.colorControlActivated);
            final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN;

            if (colorControlNormal == 0) {
                colorControlNormal = getContext().getResources().getColor(R.color.control_normal_color);
            }
            if (colorControlActivated == 0) {
                colorControlActivated = getContext().getResources().getColor(R.color.control_activated_color);
            }
            if (colorControlDisabled == 0) {
                colorControlDisabled = getContext().getResources().getColor(R.color.control_disabled_color);
            }
            if (colorControlActivateDisabled == 0) {
                colorControlActivateDisabled = getContext().getResources().getColor(R.color.control_activate_disabled_color);
            }

            TwsAnimatedStateListDrawable drawable = new TwsAnimatedStateListDrawable();
            Drawable radioOffDisableDrawable = getResources().getDrawable(radioOffDisableResId);
            Drawable radioOnDisableDrawable = getResources().getDrawable(radioOnDisableResId);
            Drawable radioOffDrawable = getResources().getDrawable(radioOffResId);
            Drawable radioOnDrawable = getResources().getDrawable(radioOnResId);

            if (isSupportTintDrawable) {
                radioOffDisableDrawable.setColorFilter(colorControlDisabled, DEFAULT_MODE);
                radioOnDisableDrawable.setColorFilter(colorControlActivateDisabled, DEFAULT_MODE);
                radioOffDrawable.setColorFilter(colorControlNormal, DEFAULT_MODE);
                radioOnDrawable.setColorFilter(colorControlActivated, DEFAULT_MODE);
            }

            drawable.addState(radioOffDisableState, radioOffDisableDrawable, 0);
            drawable.addState(radioOnDisableState, radioOnDisableDrawable, 0);
            drawable.addState(radioOffState, radioOffDrawable, radioOffKeyframeId);
            drawable.addState(radioOnState, radioOnDrawable, radioOnkeyframeId);
            AnimationDrawable toOnDrawable = (AnimationDrawable) getResources().getDrawable(radioToOnResId);
            AnimationDrawable toOffDrawable = (AnimationDrawable) getResources().getDrawable(radioToOffResId);

            if (isSupportTintDrawable) {
                toOnDrawable.setColorFilter(colorControlActivated, DEFAULT_MODE);
                toOffDrawable.setColorFilter(colorControlNormal, DEFAULT_MODE);
            }

            drawable.addTransition(radioOffKeyframeId, radioOnkeyframeId, toOnDrawable, false);
            drawable.addTransition(radioOnkeyframeId, radioOffKeyframeId, toOffDrawable, false);
            setButtonDrawable(drawable);
            mIsSupportTintDrawable = isSupportTintDrawable;
            mColorControlActivated = colorControlActivated;
            mAnimationButtonDrawable = drawable;
        }
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);
        setAnimationButtonDrawable(View.VISIBLE == visibility);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setRippleBackground(mIsSupportTintDrawable, mAnimationButtonDrawable, mColorControlActivated);
    }

    private void setRippleBackground(boolean isSupportTintDrawable, Drawable orgDrawable, int rippleColor) {
        if (orgDrawable != null && isSupportTintDrawable) {
            ColorStateList csl = createNormalStateList(rippleColor);
            final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
            final int drawableHeight = orgDrawable.getIntrinsicHeight();
            final int drawableWidth = orgDrawable.getIntrinsicWidth();
            final float scale = 0.3f;
            final float drawableScaleHeight = drawableHeight * scale;
            final float drawableScaleWidth = drawableWidth * scale;

            final int top;
            switch (verticalGravity) {
                case Gravity.BOTTOM:
                    top = (int) (getHeight() - drawableHeight - drawableScaleHeight);
                    break;
                case Gravity.CENTER_VERTICAL:
                    top = (int) (((getHeight() - drawableHeight) / 2) - drawableScaleHeight);
                    break;
                default:
                    top = (int) (-drawableScaleHeight);
            }
            final int bottom = (int) (top + drawableHeight + drawableScaleHeight * 2);
            final int left = (int) (isLayoutRtl() ? getWidth() - drawableWidth - drawableScaleWidth : -drawableScaleWidth);
            final int right = (int) (isLayoutRtl() ? getWidth() + drawableScaleWidth : drawableWidth + drawableScaleWidth);

            TwsRippleDrawable rippleDrawable = new TwsRippleDrawable(csl, null, null,
                    TwsRippleDrawable.RIPPLE_STYLE_RING);
            rippleDrawable.twsSetHotspotBounds(left, top, right, bottom);
            setBackgroundDrawable(rippleDrawable);
        }
    }

    private ColorStateList createNormalStateList(int textColor) {
        // Now create a new ColorStateList with the default color
        final int[][] states = new int[1][];
        final int[] colors = new int[1];
        // Default state
        states[0] = EMPTY_STATE_SET;
        colors[0] = textColor;
        return new ColorStateList(states, colors);
    }
}
