/*
 * Copyright 2000-2015 JetBrains s.r.o.
 *
 * 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.intellij.openapi.wm.impl.status;

import com.intellij.icons.AllIcons;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.*;
import java.awt.*;

public class TextPanel extends JComponent implements Accessible {
  @Nullable private String  myText;
  @Nullable private Color myCustomColor;

  private Integer   myPrefHeight;
  private Dimension myExplicitSize;

  private float myAlignment;
  private int myRightPadding = JBUI.scale(14);

  protected TextPanel() {
    setOpaque(false);
  }

  @Override
  public Font getFont() {
    return SystemInfo.isMac ? JBUI.Fonts.label(11) : JBUI.Fonts.label();
  }

  public void recomputeSize() {
    final JLabel label = new JLabel("XXX");
    label.setFont(getFont());
    myPrefHeight = label.getPreferredSize().height;
  }

  public void resetColor() {
    myCustomColor = null;
  }

  public void setCustomColor(@Nullable Color customColor) {
    myCustomColor = customColor;
  }

  @Override
  protected void paintComponent(final Graphics g) {
    String s = getText();
    final Rectangle bounds = getBounds();
    if (UIUtil.isUnderDarcula()) {
      g.setColor(UIUtil.getPanelBackground());
      g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
    }
    if (s == null) return;
    final Insets insets = getInsets();

    final Graphics2D g2 = (Graphics2D)g;
    g2.setFont(getFont());

    UISettings.setupAntialiasing(g);

    final FontMetrics fm = g2.getFontMetrics();
    final int sWidth = fm.stringWidth(s);

    int x = insets.left;
    if (myAlignment == Component.CENTER_ALIGNMENT || myAlignment == Component.RIGHT_ALIGNMENT) {
      x = myAlignment == Component.CENTER_ALIGNMENT ? (bounds.width - sWidth) / 2 : bounds.width - insets.right - sWidth;
    }

    final Rectangle textR = new Rectangle();
    final Rectangle iconR = new Rectangle();
    final Rectangle viewR = new Rectangle(bounds);
    textR.x = textR.y = textR.width = textR.height = 0;

    viewR.width -= insets.left;
    viewR.width -= insets.right;

    final int maxWidth = bounds.width - insets.left - insets.right;
    if (sWidth > maxWidth) {
      s = truncateText(s, bounds, fm, textR, iconR, maxWidth);
    }

    final int y = UIUtil.getStringY(s, bounds, g2);

    g2.setColor(myCustomColor == null ? getForeground() : myCustomColor);
    g2.drawString(s, x, y);
  }

  protected String truncateText(String text, Rectangle bounds, FontMetrics fm, Rectangle textR, Rectangle iconR, int maxWidth) {
    return SwingUtilities.layoutCompoundLabel(fm, text, null, SwingConstants.CENTER, SwingConstants.CENTER, SwingConstants.CENTER,
                                               SwingConstants.TRAILING,
                                               bounds, iconR, textR, 0);
  }

  public void setTextAlignment(final float alignment) {
    myAlignment = alignment;
  }

  private static String splitText(final JLabel label, final String text, final int widthLimit) {
    final FontMetrics fontMetrics = label.getFontMetrics(label.getFont());

    final String[] lines = UIUtil.splitText(text, fontMetrics, widthLimit, ' ');

    final StringBuilder result = new StringBuilder();
    for (int i = 0; i < lines.length; i++) {
      final String line = lines[i];
      if (i > 0) {
        result.append('\n');
      }
      result.append(line);
    }
    return result.toString();
  }

  public final void setText(@Nullable String text) {
    text = StringUtil.notNullize(text);
    if (text.equals(myText)) {
      return;
    }

    String oldAccessibleName = null;
    if (accessibleContext != null) {
      oldAccessibleName = accessibleContext.getAccessibleName();
    }

    myText = text;

    if ((accessibleContext != null) && !StringUtil.equals(accessibleContext.getAccessibleName(), oldAccessibleName)) {
      accessibleContext.firePropertyChange(
        AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
        oldAccessibleName,
        accessibleContext.getAccessibleName());
    }

    setPreferredSize(getPanelDimensionFromFontMetrics(myText));
    revalidate();
    repaint();
  }

  public String getText() {
    return myText;
  }

  public Dimension getPreferredSize() {
    if (myExplicitSize != null) {
      return myExplicitSize;
    }

    String text = getTextForPreferredSize();
    return getPanelDimensionFromFontMetrics(text);
  }

  public void setRightPadding(int rightPadding) {
    myRightPadding = rightPadding;
  }

  private Dimension getPanelDimensionFromFontMetrics (String text) {
    int width = (text == null) ? 0 : myRightPadding + getFontMetrics(getFont()).stringWidth(text);
    int height = (myPrefHeight == null) ? getMinimumSize().height : myPrefHeight;

    return new Dimension(width, height);
  }

  /**
   * @return the text that is used to calculate the preferred size
   */
  @Nullable
  protected String getTextForPreferredSize() {
    return myText;
  }

  public void setExplicitSize(@Nullable Dimension explicitSize) {
    myExplicitSize = explicitSize;
  }

  public static class WithIconAndArrows extends TextPanel {
    private final static int GAP = 2;
    @Nullable private Icon myIcon;

    @Override
    protected void paintComponent(@NotNull final Graphics g) {
      super.paintComponent(g);
      if (getText() != null) {
        Rectangle r = getBounds();
        Insets insets = getInsets();
        Icon arrows = AllIcons.Ide.Statusbar_arrows;
        arrows.paintIcon(this, g, r.width - insets.right - arrows.getIconWidth() - 1,
                         r.height / 2 - arrows.getIconHeight() / 2);
        if (myIcon != null) {
          myIcon.paintIcon(this, g, insets.left - GAP - myIcon.getIconWidth(), r.height / 2 - myIcon.getIconHeight() / 2);
        }
      }
    }

    @NotNull
    @Override
    public Insets getInsets() {
      Insets insets = super.getInsets();
      if (myIcon != null) {
        insets.left += myIcon.getIconWidth() + GAP * 2;
      }
      return insets;
    }

    @Override
    public Dimension getPreferredSize() {
      final Dimension preferredSize = super.getPreferredSize();
      int deltaWidth = AllIcons.Ide.Statusbar_arrows.getIconWidth();
      if (myIcon != null) {
        deltaWidth += myIcon.getIconWidth();
      }
      return new Dimension(preferredSize.width + deltaWidth, preferredSize.height);
    }

    public void setIcon(@Nullable Icon icon) {
      myIcon = icon;
    }
  }

  public static class ExtraSize extends TextPanel {
    public Dimension getPreferredSize() {
      Dimension size = super.getPreferredSize();
      return new Dimension(size.width + 3, size.height);
    }
  }

  @Override
  public AccessibleContext getAccessibleContext() {
    if (accessibleContext == null) {
      accessibleContext = new AccessibleTextPanel();
    }
    return accessibleContext;
  }

  protected class AccessibleTextPanel extends AccessibleJComponent {
    @Override
    public AccessibleRole getAccessibleRole() {
      return AccessibleRole.LABEL;
    }

    @Override
    public String getAccessibleName() {
      return myText;
    }
  }
}
