package org.jcon.ui;

import java.awt.*;
import java.util.*;
import javax.swing.JComponent;

/*
* This class is a multi-line label. It's based on the example
* in Java in a Nutshell Examples, with improvements.
*/

// *** BUG - Fails to show paint if extends JComponent
public class MultiLineLabel extends Canvas {

//---------- Public Fields -------------------------------
public static final int LEFT   = 0; // Alignment constants
public static final int CENTER = 1;
public static final int RIGHT  = 2;

//---------- Protected Fields ----------------------------
protected String[] lines;         // The lines of text to display
protected int num_lines;          // The number of lines
protected int margin_width;       // Left and right margins
protected int margin_height;      // Top and bottom margins
protected int line_height;        // Total height of the font
protected int line_ascent;        // Font height above baseline
protected int[] line_widths;      // How wide each line is
protected int max_width;          // The width of the widest line
protected int alignment = LEFT;   // The alignment of the text.
protected String text;            // The original label text

protected static final int DEFAULT_MARGIN = 2;

//---------- Initialization ------------------------------
public MultiLineLabel() {
    this("", DEFAULT_MARGIN, DEFAULT_MARGIN, LEFT);
}
public MultiLineLabel(String label, int margin_width, int margin_height) {
    this(label, margin_width, margin_height, LEFT);
}
public MultiLineLabel(String label, int alignment) {
    this(label, DEFAULT_MARGIN, DEFAULT_MARGIN, alignment);
}
public MultiLineLabel(String label) {
    this(label, DEFAULT_MARGIN, DEFAULT_MARGIN, LEFT);
}
public MultiLineLabel(String label, int margin_width, int margin_height,
              int alignment) {
    newLabel(label);
    this.margin_width = margin_width;
    this.margin_height = margin_height;
    this.alignment = alignment;
}
//---------- Properties ----------------------------------
/*
* Sets the text to be used in the label. Lines should be
* separated by a newline character.
*/
public void setText(String text) {
    newLabel(text);
    measure();
    repaint();
}
public String getText() {
    return text;
}
public void setFont(Font f) {
    super.setFont(f);
    measure();
    repaint();
}
public void setForeground(Color c) { 
    super.setForeground(c); 
    repaint(); 
}
public void setAlignment(int a) { alignment = a; repaint(); }
public void setMarginWidth(int mw) { margin_width = mw; repaint(); }
public void setMarginHeight(int mh) { margin_height = mh; repaint(); }
public int getAlignment() { return alignment; }
public int getMarginWidth() { return margin_width; }
public int getMarginHeight() { return margin_height; }

// This method is invoked after our Canvas is first created
// but before it can actually be displayed.  After we've
// invoked our superclass's addNotify() method, we have font
// metrics and can successfully call measure() to figure out
// how big the label is.
public void addNotify() { super.addNotify(); measure(); }

// This method is called by a layout manager when it wants to
// know how big we'd like to be.  
public Dimension getPreferredSize() {
    return new Dimension(max_width + 2*margin_width, 
                 num_lines * line_height + 2*margin_height);
}

// This method is called when the layout manager wants to know
// the bare minimum amount of space we need to get by.
public Dimension getMinimumSize() {
    return new Dimension(max_width, num_lines * line_height);
}

// This method draws the label (applets use the same method).
// Note that it handles the margins and the alignment, but that
// it doesn't have to worry about the color or font--the superclass
// takes care of setting those in the Graphics object we're passed.
public void paint(Graphics g) {
    int x, y;
    Dimension d = this.getSize();
    y = line_ascent + (d.height - num_lines * line_height)/2;
    for(int i = 0; i < num_lines; i++, y += line_height) {
        switch(alignment) {
        case LEFT:
            x = margin_width; break;
        case CENTER:
        default:
            x = (d.width - line_widths[i])/2; break;
        case RIGHT:
            x = d.width - margin_width - line_widths[i]; break;
        }
        g.drawString(lines[i], x, y);
        //print(".paint() - " + lines[i] + " x = " + x + ", y = " + y);
    }
}
//---------- Protected Methods ---------------------------
// This method breaks a specified label up into an array of lines.
// It uses the StringTokenizer utility class.
protected void newLabel(String label) {
    if (label == null) label = "";

    this.text = label;
    StringTokenizer t = new StringTokenizer(label, "\n");
    num_lines = t.countTokens();
    lines = new String[num_lines];
    line_widths = new int[num_lines];
    for(int i = 0; i < num_lines; i++) {
        lines[i] = t.nextToken();
    }
}

// This method figures out how the font is, and how wide each
// line of the label is, and how wide the widest line is.
protected void measure() {
    FontMetrics fm = this.getFontMetrics(this.getFont());
    // If we don't have font metrics yet, just return.
    if (fm == null) return;
    
    line_height = fm.getHeight();
    line_ascent = fm.getAscent();
    max_width = 0;
    for(int i = 0; i < num_lines; i++) {
        line_widths[i] = fm.stringWidth(lines[i]);
        if (line_widths[i] > max_width) max_width = line_widths[i];
    }
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("MultiLineLabel" + text);
}

} // End Class
