package org.javafxdata.control.cell;

import java.text.Format;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.text.TextAlignment;
import javafx.util.Callback;

/**
 * <p>A class containing a {@link TableCell} implementation that draws a {@link Label}
 * node inside the cell. This Label is exposed to the developer to allow for easy customisation,
 * either via code or using the APIs exposed in the {@link CSSTableCell} class, from which this
 * class extends.
 * 
 * @param <T> The type of the elements contained within the TableColumn.
 * @author <a href="http://www.jonathangiles.net">Jonathan Giles</a>
 */
public class LabelTableCell<S,T> extends CSSTableCell<S,T> {
    
    private Format format;
    
    /**
     * Creates a default {@link LabelTableCell} instance with the label position set
     * to {@link TextAlignment#LEFT}.
     */
    public LabelTableCell() {
        this(TextAlignment.LEFT);
    }
    
    public LabelTableCell(Format format) {
        this(TextAlignment.LEFT, format);
    }
    
    /**
     * Creates a {@link LabelTableCell} instance with the label position set
     * to the provided {@link TextAlignment} value.
     */
    public LabelTableCell(TextAlignment align) {
        this(align, null);
    }
    
    public LabelTableCell(TextAlignment align, Format format) {
        this.getStyleClass().add("label-cell");
        setTextAlignment(align);
        setFormat(format);
    }
    
    // --- Format
    public Format getFormat() { 
        return format; 
    }
    public void setFormat(Format format) { 
        this.format = format;
        doUpdate();
    }
    
    /**
     * A method that can be overridden by the developer to specify an alternate
     * formatting of the given item argument. By default, this just calls toString()
     * on the item, or returns an empty string if the item is null.
     * 
     * @param item The item for which a String representation is required.
     * @return An empty string if item is null, or a string representation if it is not.
     */
    public String toString(T item) {
        return item == null ? "" : item.toString();
    }
    
    /** {@inheritDoc} */
    @Override public void updateItem(T item, boolean empty) {
        if (item == getItem()) return;

        super.updateItem(item, empty);

        doUpdate(item, empty);
    }
    
    private void doUpdate() {
        doUpdate(getItem(), isEmpty());
    }
    
    private void doUpdate(T item, boolean empty) {
        if (item == null || empty) {
            super.setText(null);
            super.setGraphic(null);
        } else if (format != null) {
            super.setText(format.format(item));
        } else if (item instanceof Node) {
            super.setText(null);
            super.setGraphic((Node)item);
        } else {
            super.setText(toString(item));
            super.setGraphic(null);
        }
    }
}