package org.javafxdata.control.cell;

import java.text.Format;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.scene.text.TextAlignment;
import javafx.util.Callback;

/**
 * A class containing cell factories that make it easy to manipulate the String representation of 
 * items contained within ListView, TreeView and TableView controls.
 * 
 * @author <a href="http://www.jonathangiles.net">Jonathan Giles</a>
 */
public class LabelCellFactory {
    
    private LabelCellFactory() { }
    
    /**
     * Returns a cell factory that creates a default {@link LabelListCell}.
     */
    public static <T> Callback<ListView<T>, ListCell<T>> forListView() {
        return forListView(TextAlignment.LEFT);
    }
    
    public static <T> Callback<ListView<T>, ListCell<T>> forListView(TextAlignment align) {
        return forListView(align, null);
    }
    
    public static <T> Callback<ListView<T>, ListCell<T>> forListView(Format format) {
        return forListView(TextAlignment.LEFT, format);
    }
    
    public static <T> Callback<ListView<T>, ListCell<T>> forListView(final TextAlignment align, final Format format) {
        return new Callback<ListView<T>, ListCell<T>>() {
            @Override public ListCell<T> call(ListView<T> list) {
                return new LabelListCell<T>(align, format);
            }
        };
    }
    
    /**
     * Returns a cell factory that creates a {@link LabelListCell} that uses the provided {@link Callback}
     * to convert from the generic T type to a String, such that it is rendered appropriately.
     * 
     * @param toString A {@link Callback} that converts an instance of type T to a String, for rendering
     *      in the {@link LabelCellFactory}.
     */
    public static <T> Callback<ListView<T>, ListCell<T>> forListView(final Callback<T, String> toString) {
        return new Callback<ListView<T>, ListCell<T>>() {
            @Override public ListCell<T> call(ListView<T> list) {
                return new LabelListCell<T>() {
                    @Override public String toString(T item) {
                        return toString == null ? super.toString(item) : toString.call(item);
                    };
                };
            }
        };
    }
    
    /**
     * Returns a cell factory that creates a default {@link LabelTreeCell}.
     */
    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView() {
        return forTreeView(TextAlignment.LEFT);
    }
    
    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView(TextAlignment align) {
        return forTreeView(align, null);
    }
    
    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView(Format format) {
        return forTreeView(TextAlignment.LEFT, format);
    }
    
    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView(final TextAlignment align, final Format format) {
        return new Callback<TreeView<T>, TreeCell<T>>() {
            @Override public TreeCell<T> call(TreeView<T> list) {
                return new LabelTreeCell<T>(align, format);
            }
        };
    }
    
    /**
     * Returns a cell factory that creates a {@link LabelTableCell} that uses the provided {@link Callback}
     * to convert from the generic T type to a String, such that it is rendered appropriately.
     * 
     * @param toString A {@link Callback} that converts an instance of type T to a String, for rendering
     *      in the {@link TableCell}.
     */
    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView(final Callback<T, String> toString) {
        return new Callback<TreeView<T>, TreeCell<T>>() {
            @Override public TreeCell<T> call(TreeView<T> list) {
                return new LabelTreeCell<T>() {
                    @Override public String toString(T item) {
                        return toString == null ? super.toString(item) : toString.call(item);
                    };
                };
            }
        };
    }
    
    /**
     * Returns a cell factory that creates a default {@link LabelTableCell}.
     */
    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn() {
        return forTableColumn(TextAlignment.LEFT);
    }
    
    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(TextAlignment align) {
        return forTableColumn(align, null);
    }
    
    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(Format format) {
        return forTableColumn(TextAlignment.LEFT, format);
    }
    
    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(final TextAlignment align, final Format format) {
        return new Callback<TableColumn<S,T>, TableCell<S,T>>() {
            @Override public TableCell<S,T> call(TableColumn<S,T> list) {
                return new LabelTableCell<S,T>(align, format);
            }
        };
    }
    
    /**
     * Returns a cell factory that creates a {@link LabelTreeCell} that uses the provided {@link Callback}
     * to convert from the generic T type to a String, such that it is rendered appropriately.
     * 
     * @param toString A {@link Callback} that converts an instance of type T to a String, for rendering
     *      in the {@link TreeCell}.
     */
    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(final Callback<T, String> toString) {
        return new Callback<TableColumn<S,T>, TableCell<S,T>>() {
            @Override public TableCell<S,T> call(TableColumn<S,T> list) {
                return new LabelTableCell<S,T>() {
                    @Override public String toString(T item) {
                        return toString == null ? super.toString(item) : toString.call(item);
                    };
                };
            }
        };
    }
}