package com.limegroup.gnutella.gui;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Toolkit;

import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JTextArea;
import javax.swing.plaf.basic.BasicToolTipUI;

/**
 * A new class to allow mulitple lines to be displayed in a tool tip
 * @author Sumeet Thadani
 */


public class MultilineToolTipUI extends BasicToolTipUI {

    /**
     * The default width of a tooltip.
     */
    private static final int MAX_WIDTH = 400;
    
    /**
     * The blank space between a border & text of a tooltip.
     */
    private static final int BLANK_SPACE = 4;

    /**
     * The shared instance.
     */
    private static final MultilineToolTipUI instance =
        new MultilineToolTipUI();
        
    /**
     * Whether or not the current tip extends beyond the default width
     */
    private boolean extendedWidth = false;
    
    /**
     * The JTextArea with the texts.
     */
    private final JTextArea TEXT = new JTextArea();
    
    /**
     * The cell renderer pane used to draw the text over the component.
     */
    private final CellRendererPane PANE = new CellRendererPane();
    
    public static MultilineToolTipUI instance(){
        return instance;
    }
    
    //private constructor
    private MultilineToolTipUI() {
        TEXT.setLineWrap(true);
        TEXT.setWrapStyleWord(true);
        TEXT.setEditable(false);
        TEXT.setOpaque(false);
    }

    /**
     * Determines the size of this tooltip.
     */
    public Dimension getPreferredSize(JComponent c) {
        extendedWidth = false;
        Font font = c.getFont();
        FontMetrics fontMetrics = c.getFontMetrics(font);
        int fontHeight = fontMetrics.getHeight();
        String[] lines = ((JMultilineToolTip)c).getTipArray();
        if(lines == null)
            return new Dimension(0,0);
        int num_lines = lines.length;
        int height = num_lines * fontHeight;
        if (height==0)
            return new Dimension(0,0);
        int width = 0;
        for (int i = 0; i < num_lines; i++) {
            int line_width = fontMetrics.stringWidth(lines[i]);
            width = Math.max(line_width, width);
            if(width > MAX_WIDTH) {
                extendedWidth = true;
                break;
            }
        }
        Dimension preferredSize;
        
        if(extendedWidth) {
            TEXT.setFont(font);
            TEXT.setText(lines[0]);
            for(int i = 1; i < num_lines; i++)
                TEXT.append("\n" + lines[i]);
            Dimension pref = preferredSize(fontMetrics, TEXT);
            width = pref.width;
            height = pref.height;
        }
        
        return new Dimension(width + BLANK_SPACE * 2,
                             height + BLANK_SPACE * 2);
    }
    
    public Dimension getMinimumSize(JComponent c) {
        return getPreferredSize(c);
    }
    
    public Dimension getMaximumSize(JComponent c) {
        return getPreferredSize(c);
    }
    
    /**
     * Gets the preferred size of a JTextArea.
     */
    private Dimension preferredSize(final FontMetrics fm, JTextArea area) {
        // Iterate through the text, determining how large we want it to be.
        int fullWidth = 0;
        int rows = 1;
        int carriage = -1;
        int nextCarriage = -1;
        int width = 0;
        final String text = area.getText();
        String current;
        nextCarriage = text.indexOf("\n");
        while(nextCarriage != -1) {
            current = text.substring(carriage+1, nextCarriage);
            width = fm.stringWidth(current);
            if(width > MAX_WIDTH) {
              rows += (int)Math.ceil((double)width / (double)MAX_WIDTH);
              fullWidth = MAX_WIDTH;
            } else {
                fullWidth = Math.max(width, fullWidth);
                rows++;
            }
            carriage = nextCarriage;
            nextCarriage = text.indexOf("\n", carriage+1);
        }
        // last run...
        current = text.substring(carriage + 1);
        width = fm.stringWidth(current);
        if(width > MAX_WIDTH) {
          rows += (int)Math.ceil((double)width / (double)MAX_WIDTH);
          fullWidth = MAX_WIDTH;
        } else {
            fullWidth = Math.max(width, fullWidth);
            rows++;
        }
        return new Dimension(fullWidth, rows * fm.getHeight());
    }
    
    /**
     * Paints this tooltip.  If 'extendedWidth' is true, uses a JTextArea
     * in order to paint the tooltip.
     */
    public void paint(Graphics g, JComponent c) {
        Dimension dimension = c.getSize();
        Font font = c.getFont();
        
        if(extendedWidth) {
            g.setColor(c.getBackground());
            g.fillRect(0, 0, dimension.width, dimension.height);            
            TEXT.setForeground(c.getForeground());
    		PANE.paintComponent(g, TEXT, c,
    		    BLANK_SPACE, BLANK_SPACE,
    		    dimension.width - BLANK_SPACE*2,
    		    dimension.height - BLANK_SPACE*2,
    		    true);
            return;
        }

        FontMetrics fontMetrics =
        Toolkit.getDefaultToolkit().getFontMetrics(font);
        int fontHeight = fontMetrics.getHeight();
        int fontAscent = fontMetrics.getAscent();
        String[] lines = ((JMultilineToolTip)c).getTipArray();
        // possible NPE
        if (lines == null) return;
        int num_lines = lines.length;
        int height;
        int i;
        
        g.setColor(c.getBackground());
        g.fillRect(0, 0, dimension.width, dimension.height);
        g.setColor(c.getForeground());
        for(i=0, height = BLANK_SPACE + fontAscent;
          i < num_lines; i++, height += fontHeight)
            g.drawString(lines[i], BLANK_SPACE, height);
    }
}
    
