package org.jcon.ba.tree;

import org.jcon.ba.system.*;
import org.jcon.param.ParamDriven;
import org.jcon.ui.ImageLib;
import org.jcon.util.GenLib;
import org.jcon.util.TNode;

import java.awt.*;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;

/**
* Renders tree nodes using the node userObject, which is
* an Item. This class's main responsiblity is to allow the
* user to conceptually grasp the node's state, and hence
* the tree's state.
* <p>
* Started from SampleTreeCellRenderer in Swing 0.5.1
*
* @author Jack Harich
*/
public class TreeViewCellRenderer
    extends JLabel implements TreeCellRenderer {

//---------- Protected Fields ----------------------------
/** Font used if the string to be displayed isn't a font. */
static protected Font defaultFont;

/** Icon to use when the item is collapsed. */
static protected ImageIcon collapsedIcon;

/** Icon to use when the item is expanded. */
static protected ImageIcon expandedIcon;

/** Whether or not the item that was last configured is selected. */
protected boolean selected;

protected Item item;

//---------- Initialization ------------------------------
static {
try {
    defaultFont = new Font("SansSerif", 0, 12);
} catch (Exception ex) { }

try {
    // We use the defaultClassName for image resource
    Image collapsedImage = ImageLib.loadClassResourceImage(
        null, "Folder.gif"); // Was Collapsed
    collapsedIcon = new ImageIcon(collapsedImage);

    Image expandedImage = ImageLib.loadClassResourceImage(
        null, "Folder.gif"); // Was Expanded
    expandedIcon = new ImageIcon(expandedImage);

} catch (Exception ex) { // Not triggered if image is null
    print(" - Couldn't load images: " + ex);
}
} // End method

//---------- TreeCellRenderer Implementation -------------
/**
 * This is messaged from JTree whenever it needs to get the
 * size of the component or it wants to draw it.
 * This attempts to set the font based on value, which will
 * be a TreeNode.
 */
public Component getTreeCellRendererComponent(JTree tree,
            Object value, boolean selected,
            boolean expanded, boolean leaf, int row,
            boolean hasFocus) {

    // Set the text. Used by tree to determine row length,
    // so we add extra characters to allow for our extra
    // hand drawn icon, the box. (extra not really needed)
    item = (Item) ((TNode)value).getUserObject();
    String suffix = calcTextSuffix();
    setText(item.getItemName() + suffix + "XXX"); // XXX for extra

    // Set image for node icon
    if(expanded) {
        setIcon(expandedIcon);
    } else if(item.isContainer()) {
        setIcon(collapsedIcon);
    } else {
        setIcon(null);
    }
    // Update the selected flag for the next paint
    this.selected = selected;

    return this;
}
//---------- Superclass Overrides ------------------------
/**
 * paint() is subclassed to draw the background correctly.
 * JLabel currently does not allow backgrounds other than
 * white, and it will also fill behind the icon,
 * something that isn't desirable.
 */
public void paint(Graphics g) {
    // Set background color to selected or normal
    if (selected) {
        g.setColor(Color.cyan);  // Could be a constant
    } else {
        g.setColor(Color.white); // Could be a constant
    }
    // Various properties
    int gap = 3; // Icon, gap, nodeState, gap, text
    FontMetrics metrics = g.getFontMetrics();
    String text = item.getItemName();
        // Calculate iconWidth including gap
    int   iconWidth = 0; // Icon, gap
    Icon  currentIcon = getIcon();
    if(currentIcon != null && getText() != null) {
        iconWidth = currentIcon.getIconWidth() + gap;
    }
    // nodeState dimensions
    int diameter = getHeight() / 2;
    int xNode = iconWidth + gap;
    int yNode = ((getHeight() - diameter) / 2);
    int xText = xNode + diameter + gap + 1;

    // Draw cell background color rectangle
    // This is bkg or selected color
    int textWidth = metrics.stringWidth(text);
    g.fillRect(xText + 1, 1,
        textWidth, getHeight() - 1);

    // Draw icon
    if (currentIcon != null) {
        // Should center vertically ???
      currentIcon.paintIcon(this, g, 2, 2); // 2 by coincidence
    }
    // Draw nodeState, a color filled box
    g.setColor(calcNodeColor()); // Calculate per nodeState
    g.fillRect(xNode, yNode, diameter + 1, diameter + 1);

    String suffix = calcTextSuffix();
    if (item.isBeanWrapper()) {
        g.setColor(Color.darkGray);
        g.drawRect(xNode, yNode, diameter, diameter);
        if (item.getBeanInstance() instanceof BeanPriv) {
            g.drawRect(xNode - 1, yNode - 1, diameter + 2, diameter + 2);
        }
        // Draw X if param driven bean
        if (item.getBeanInstance() instanceof ParamDriven) {
            // Lower left to top right
            g.drawLine(xNode, yNode + diameter,
                xNode + diameter, yNode);
            // Top left to lower right
            g.drawLine(xNode, yNode,
                xNode + diameter, yNode + diameter);
        }
    }
    // Draw text
    int yText = metrics.getAscent() + 1;
    g.setColor(Color.black); // Foreground
    g.drawString(text + suffix, xText, yText);

    //super.paint(g); // Per demo
}
//---------- Private Methods -----------------------------
private String calcTextSuffix() {
    if (item.isBeanWrapper()) {
        return calcBeanSuffix(item.getBeanInstance());
    } else {
        return "";
    }
}
// Returns "" if no BeanAction* or (S, C) style
private String calcBeanSuffix(Object bean) {

    String text = null;
    if (bean instanceof BeanActionInit) text = "I";

    if (bean instanceof BeanActionStart) {
        text = (text == null ? "S" : text + ", S");
    }
    if (bean instanceof BeanActionPause) {
        text = (text == null ? "P" : text + ", P");
    }
    if (bean instanceof BeanActionClose) {
        text = (text == null ? "C" : text + ", C");
    }
    return (text == null ? "" : " (" + text + ")");
}
private Color calcNodeColor() {
    // Note background is cyan or white, squares have black border

    // Cyan   - minimal capability (was white)
    // Yellow - caution, only initialized
    // Green  - running
    // Red    - paused
    // Black  - error

    switch(item.getTrueItemState() ) {
        case Item.CREATED:     return Color.cyan;
        case Item.INITIALIZED: return Color.yellow;
        case Item.RUNNING:     return Color.green;
        case Item.PAUSED:      return Color.red;
        default: return Color.black;
    }
}
//--- Std
private static void print(String text) {
    System.out.println("TreeViewCellRenderer" + text);
}


} // End class
