content: /*
   * Copyright (C) 2015 AChep@xda <artemchep@gmail.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   * MA  02110-1301, USA.
   */
  package com.achep.acdisplay.ui.widgets.notification;
  
  import android.content.Context;
  import android.content.res.TypedArray;
  import androidx.annotation.LayoutRes;
  import androidx.annotation.Nullable;
  import android.text.SpannableString;
  import android.text.Spanned;
  import android.text.style.UnderlineSpan;
  import android.util.AttributeSet;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.widget.LinearLayout;
  import android.widget.TextView;
  
  import com.achep.acdisplay.R;
  import com.achep.base.tests.Check;
  
  import java.util.Arrays;
  
  /**
   * @author Artem Chepurnoy
   * @since 3.1
   */
  public class NotificationMessages extends LinearLayout {
  
      private CharSequence[] mMessages;
      private boolean mHighlightMessages;
      private int mMaxLines;
  
      public NotificationMessages(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
      }
  
      public NotificationMessages(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
  
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationMessages);
          setMaxLines(a.getInt(R.styleable.NotificationMessages_maxLines, 6));
          setHighlightMessagesEnabled(a.getBoolean(R.styleable.NotificationMessages_highlightMessages, true));
          a.recycle();
      }
  
      public void setMaxLines(int maxLines) {
          mMaxLines = maxLines;
          updateMessages();
      }
  
      public void setHighlightMessagesEnabled(boolean enabled) {
          mHighlightMessages = enabled;
          updateMessages();
      }
  
      protected void updateMessages() {
          if (mMessages != null) setMessages(mMessages);
      }
  
      /**
       * @param messages an array of non-empty messages.
       */
      public void setMessages(final @Nullable CharSequence[] messages) {
          mMessages = messages;
  
          if (messages == null) {
              // Free messages' container.
              removeAllViews();
              return;
          }
  
          int freeLines = mMaxLines;
          final int length = messages.length;
          final int viewCount = Math.min(length, freeLines);
          final int[] viewMaxLines = new int[length];
          if (freeLines > length) { // We can reserve more than one line per message
  
              // Initial setup.
              Arrays.fill(viewMaxLines, 1);
              freeLines -= length;
  
              // Build list of lengths, so we don't have
              // to recalculate it every time.
              int[] msgLengths = new int[length];
              for (int i = 0; i < length; i++) {
                  assert messages[i] != null;
                  msgLengths[i] = messages[i].length();
              }
  
              while (freeLines > 0) {
                  int pos = 0;
                  float a = 0;
                  for (int i = 0; i < length; i++) {
                      final float k = (float) msgLengths[i] / viewMaxLines[i];
                      if (k > a) {
                          a = k;
                          pos = i;
                      }
                  }
                  viewMaxLines[pos]++;
                  freeLines--;
              }
          } else {
              // Show first messages.
              for (int i = 0; freeLines > 0; freeLines--, i++) {
                  viewMaxLines[i] = 1;
              }
          }
  
          View[] views = new View[viewCount];
  
          // Find available views.
          int childCount = getChildCount();
          for (int i = Math.min(childCount, viewCount) - 1; i >= 0; i--) {
              views[i] = getChildAt(i);
          }
  
          // Remove redundant views.
          for (int i = childCount - 1; i >= viewCount; i--) {
              removeViewAt(i);
          }
  
          boolean highlightFirstLetter = mHighlightMessages && viewCount > 1;
  
          LayoutInflater inflater = null;
          for (int i = 0; i < viewCount; i++) {
              View root = views[i];
  
              if (root == null) {
                  // Initialize layout inflater only when we really need it.
                  if (inflater == null) {
                      inflater = (LayoutInflater) getContext()
                              .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                      assert inflater != null;
                  }
  
                  root = inflater.inflate(
                          getMessageLayoutResource(),
                          this, false);
                  // FIXME: ?
                  // We need to keep all IDs unique to make
                  // TransitionManager#beginDelayedTransition(ViewGroup)
                  // work correctly!
                  root.setId(getChildCount() + 1);
                  addView(root);
              }
  
              Check.getInstance().isTrue(messages[i].length() != 0);
  
              final CharSequence text;
              final char char_ = messages[i].charAt(0);
              if (highlightFirstLetter && (Character.isLetter(char_) || Character.isDigit(char_))) {
                  SpannableString spannable = new SpannableString(messages[i]);
                  spannable.setSpan(new UnderlineSpan(), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                  text = spannable;
              } else {
                  text = messages[i];
              }
  
              // Get message view and apply the content.
              TextView textView = root instanceof TextView
                      ? (TextView) root
                      : (TextView) root.findViewById(android.R.id.message);
              textView.setMaxLines(viewMaxLines[i]);
              textView.setText(text);
          }
      }
  
      @LayoutRes
      protected int getMessageLayoutResource() {
          return R.layout.notification_message;
      }
  
  }
  