/*
 * 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 com.android.internal.widget;

import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.view.RemotableViewMethod;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RemoteViews;
import android.widget.TextView;

import com.android.internal.R;

import java.util.Locale;

/**
 * An expand button in a notification
 */
@RemoteViews.RemoteView
public class NotificationExpandButton extends FrameLayout {

    private Drawable mPillDrawable;
    private TextView mNumberView;
    private ImageView mIconView;
    private boolean mExpanded;
    private int mNumber;
    private int mDefaultPillColor;
    private int mDefaultTextColor;
    private int mHighlightPillColor;
    private int mHighlightTextColor;

    public NotificationExpandButton(Context context) {
        this(context, null, 0, 0);
    }

    public NotificationExpandButton(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0, 0);
    }

    public NotificationExpandButton(Context context, @Nullable AttributeSet attrs,
            int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public NotificationExpandButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        final View pillView = findViewById(R.id.expand_button_pill);
        final LayerDrawable layeredPill = (LayerDrawable) pillView.getBackground();
        mPillDrawable = layeredPill.findDrawableByLayerId(R.id.expand_button_pill_colorized_layer);
        mNumberView = findViewById(R.id.expand_button_number);
        mIconView = findViewById(R.id.expand_button_icon);
    }

    /**
     * Show the touchable area of the view for a11y.
     * If the parent is the touch container, then that view's bounds are the touchable area.
     */
    @Override
    public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
        ViewGroup parent = (ViewGroup) getParent();
        if (parent != null && parent.getId() == R.id.expand_button_touch_container) {
            parent.getBoundsOnScreen(outRect, clipToParent);
        } else {
            super.getBoundsOnScreen(outRect, clipToParent);
        }
    }

    /**
     * Determined if the given point should be touchable.
     * If the parent is the touch container, then any point in that view should be touchable.
     */
    @Override
    public boolean pointInView(float localX, float localY, float slop) {
        ViewGroup parent = (ViewGroup) getParent();
        if (parent != null && parent.getId() == R.id.expand_button_touch_container) {
            // If our parent is checking with us, then the point must be within its bounds.
            return true;
        }
        return super.pointInView(localX, localY, slop);
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(Button.class.getName());
    }

    /**
     * Update the button's drawable, content description, and color for the given expanded state.
     */
    @RemotableViewMethod
    public void setExpanded(boolean expanded) {
        mExpanded = expanded;
        updateExpandedState();
    }

    private void updateExpandedState() {
        int drawableId;
        int contentDescriptionId;
        if (mExpanded) {
            drawableId = R.drawable.ic_collapse_notification;
            contentDescriptionId = R.string.expand_button_content_description_expanded;
        } else {
            drawableId = R.drawable.ic_expand_notification;
            contentDescriptionId = R.string.expand_button_content_description_collapsed;
        }
        setContentDescription(mContext.getText(contentDescriptionId));
        mIconView.setImageDrawable(getContext().getDrawable(drawableId));

        // changing the expanded state can affect the number display
        updateNumber();
    }

    private void updateNumber() {
        if (shouldShowNumber()) {
            CharSequence text = mNumber >= 100
                    ? getResources().getString(R.string.unread_convo_overflow, 99)
                    : String.format(Locale.getDefault(), "%d", mNumber);
            mNumberView.setText(text);
            mNumberView.setVisibility(VISIBLE);
        } else {
            mNumberView.setVisibility(GONE);
        }

        // changing number can affect the color
        updateColors();
    }

    private void updateColors() {
        if (shouldShowNumber()) {
            if (mHighlightPillColor != 0) {
                mPillDrawable.setTintList(ColorStateList.valueOf(mHighlightPillColor));
            }
            mIconView.setColorFilter(mHighlightTextColor);
            if (mHighlightTextColor != 0) {
                mNumberView.setTextColor(mHighlightTextColor);
            }
        } else {
            if (mDefaultPillColor != 0) {
                mPillDrawable.setTintList(ColorStateList.valueOf(mDefaultPillColor));
            }
            mIconView.setColorFilter(mDefaultTextColor);
            if (mDefaultTextColor != 0) {
                mNumberView.setTextColor(mDefaultTextColor);
            }
        }
    }

    private boolean shouldShowNumber() {
        return !mExpanded && mNumber > 1;
    }

    /**
     * Set the color used for the expand chevron and the text
     */
    @RemotableViewMethod
    public void setDefaultTextColor(int color) {
        mDefaultTextColor = color;
        updateColors();
    }

    /**
     * Sets the color used to for the expander when there is no number shown
     */
    @RemotableViewMethod
    public void setDefaultPillColor(@ColorInt int color) {
        mDefaultPillColor = color;
        updateColors();
    }

    /**
     * Set the color used for the expand chevron and the text
     */
    @RemotableViewMethod
    public void setHighlightTextColor(int color) {
        mHighlightTextColor = color;
        updateColors();
    }

    /**
     * Sets the color used to highlight the expander when there is a number shown
     */
    @RemotableViewMethod
    public void setHighlightPillColor(@ColorInt int color) {
        mHighlightPillColor = color;
        updateColors();
    }

    /**
     * Sets the number shown inside the expand button.
     * This only appears when the expand button is collapsed, and when greater than 1.
     */
    @RemotableViewMethod
    public void setNumber(int number) {
        if (mNumber != number) {
            mNumber = number;
            updateNumber();
        }
    }
}
