/*
 * 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.android.systemui.qs;

import android.content.Context;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.systemui.R;

import java.util.Objects;

/**
 * Text displayed over one or two lines, centered horizontally.  A caret is always drawn at the end
 * of the first line, and considered part of the content for centering purposes.
 *
 * Text overflow rules:
 *   First line: break on a word, unless a single word takes up the entire line - in which case
 *               truncate.
 *   Second line: ellipsis if necessary
 */
public class QSDualTileLabel extends LinearLayout {

    private final Context mContext;
    private final TextView mFirstLine;
    private final ImageView mFirstLineCaret;
    private final TextView mSecondLine;
    private final int mHorizontalPaddingPx;

    private String mText;

    public QSDualTileLabel(Context context) {
        super(context);
        mContext = context;
        setOrientation(LinearLayout.VERTICAL);

        mHorizontalPaddingPx = mContext.getResources()
                .getDimensionPixelSize(R.dimen.qs_dual_tile_padding_horizontal);

        mFirstLine = initTextView();
        mFirstLine.setPadding(mHorizontalPaddingPx, 0, mHorizontalPaddingPx, 0);
        final LinearLayout firstLineLayout = new LinearLayout(mContext);
        firstLineLayout.setPadding(0, 0, 0, 0);
        firstLineLayout.setOrientation(LinearLayout.HORIZONTAL);
        firstLineLayout.setClickable(false);
        firstLineLayout.setBackground(null);
        firstLineLayout.addView(mFirstLine);
        mFirstLineCaret = new ImageView(mContext);
        mFirstLineCaret.setScaleType(ImageView.ScaleType.MATRIX);
        mFirstLineCaret.setClickable(false);
        firstLineLayout.addView(mFirstLineCaret);
        addView(firstLineLayout, newLinearLayoutParams());

        mSecondLine = initTextView();
        mSecondLine.setPadding(mHorizontalPaddingPx, 0, mHorizontalPaddingPx, 0);
        mSecondLine.setEllipsize(TruncateAt.END);
        mSecondLine.setVisibility(GONE);
        addView(mSecondLine, newLinearLayoutParams());

        addOnLayoutChangeListener(new OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right,
                    int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if ((oldRight - oldLeft) != (right - left)) {
                    rescheduleUpdateText();
                }
            }
        });
    }

    private static LayoutParams newLinearLayoutParams() {
        final LayoutParams lp =
                new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        lp.gravity = Gravity.CENTER_HORIZONTAL;
        return lp;
    }

    public void setFirstLineCaret(Drawable d) {
        mFirstLineCaret.setImageDrawable(d);
        if (d != null) {
            final int h = d.getIntrinsicHeight();
            mFirstLine.setMinHeight(h);
            mFirstLine.setPadding(mHorizontalPaddingPx, 0, 0, 0);
        }
    }

    private TextView initTextView() {
        final TextView tv = new TextView(mContext);
        tv.setPadding(0, 0, 0, 0);
        tv.setGravity(Gravity.CENTER_VERTICAL);
        tv.setSingleLine(true);
        tv.setClickable(false);
        tv.setBackground(null);
        return tv;
    }

    public void setText(CharSequence text) {
        final String newText = text == null ? null : text.toString().trim();
        if (Objects.equals(newText, mText)) return;
        mText = newText;
        rescheduleUpdateText();
    }

    public String getText() {
        return mText;
    }

    public void setTextSize(int unit, float size) {
        mFirstLine.setTextSize(unit, size);
        mSecondLine.setTextSize(unit, size);
        rescheduleUpdateText();
    }

    public void setTextColor(int color) {
        mFirstLine.setTextColor(color);
        mSecondLine.setTextColor(color);
        rescheduleUpdateText();
    }

    public void setTypeface(Typeface tf) {
        mFirstLine.setTypeface(tf);
        mSecondLine.setTypeface(tf);
        rescheduleUpdateText();
    }

    private void rescheduleUpdateText() {
        removeCallbacks(mUpdateText);
        post(mUpdateText);
    }

    private void updateText() {
        if (getWidth() == 0) return;
        if (TextUtils.isEmpty(mText)) {
            mFirstLine.setText(null);
            mSecondLine.setText(null);
            mSecondLine.setVisibility(GONE);
            return;
        }
        final float maxWidth = getWidth() - mFirstLineCaret.getWidth() - mHorizontalPaddingPx
                - getPaddingLeft() - getPaddingRight();
        float width = mFirstLine.getPaint().measureText(mText);
        if (width <= maxWidth) {
            mFirstLine.setText(mText);
            mSecondLine.setText(null);
            mSecondLine.setVisibility(GONE);
            return;
        }
        final int n = mText.length();
        int lastWordBoundary = -1;
        boolean inWhitespace = false;
        int i = 0;
        for (i = 1; i < n; i++) {
            width = mFirstLine.getPaint().measureText(mText.substring(0, i));
            final boolean done = width > maxWidth;
            if (Character.isWhitespace(mText.charAt(i))) {
                if (!inWhitespace && !done) {
                    lastWordBoundary = i;
                }
                inWhitespace = true;
            } else {
                inWhitespace = false;
            }
            if (done) {
                break;
            }
        }
        if (lastWordBoundary == -1) {
            lastWordBoundary = i - 1;
        }
        mFirstLine.setText(mText.substring(0, lastWordBoundary));
        mSecondLine.setText(mText.substring(lastWordBoundary).trim());
        mSecondLine.setVisibility(VISIBLE);
    }

    private final Runnable mUpdateText = new Runnable() {
        @Override
        public void run() {
            updateText();
        }
    };
}
