package org.javafxdata.control.cell;

import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.util.Callback;

/**
 * A class containing cell factories that use {@link TextField TextFields}. 
 * Be sure to read the API documentation for each static method before using it!
 * 
 * @author <a href="http://www.jonathangiles.net">Jonathan Giles</a>
 */
public class TextFieldCellFactory {
    
    private TextFieldCellFactory() { }
    
    /**
     * Provides a {@link TextField} that allows editing of the cell content when the cell is double-clicked,
     * or when {@link ListView#edit(int)} is called. This method will only work on {@link ListView} instances
     * which are of type String.
     * 
     * @return A {@link Callback} that can be inserted into the {@link ListView#cellFactoryProperty() cell
     *      factory property} of a ListView, that enables textual editing of the content.
     */
    public static Callback<ListView<String>, ListCell<String>> forListView() {
        return forListView(DEFAULT_STRING_ON_COMMIT);
    }
    
    /**
     * Provides a {@link TextField} that allows editing of the cell content when the cell is double-clicked,
     * or when {@link ListView#edit(int)} is called. This method will work on any ListView instance, 
     * regardless of its generic type. However, to enable this, a {@link Callback} must be provided that
     * will convert the given String (from what the user typed in) into an instance of type T. This
     * item will then be passed along to the {@link ListView#onEditCommitProperty()} callback.
     * 
     * @param onCommit A {@link Callback} that can convert the given String (from what the user typed in) 
     *      into an instance of type T.
     * @return A {@link Callback} that can be inserted into the {@link ListView#cellFactoryProperty() cell
     *      factory property} of a ListView, that enables textual editing of the content.
     */
    public static <T> Callback<ListView<T>, ListCell<T>> forListView(final Callback<String, T> onCommit) {
        return new Callback<ListView<T>, ListCell<T>>() {
            @Override public ListCell<T> call(ListView<T> list) {
                return new TextFieldListCell<T>(onCommit);
            }
        };
    }
    
    /**
     * Provides a {@link TextField} that allows editing of the cell content when the cell is double-clicked,
     * or when {@link ListView#edit(int)} is called. This method will only work on {@link TreeView} instances
     * which are of type String.
     * 
     * @return A {@link Callback} that can be inserted into the {@link TreeView#cellFactoryProperty() cell
     *      factory property} of a TreeView, that enables textual editing of the content.
     */
    public static Callback<TreeView<String>, TreeCell<String>> forTreeView() {
        return forTreeView(DEFAULT_STRING_ON_COMMIT);
    }
    
    /**
     * Provides a {@link TextField} that allows editing of the cell content when the cell is double-clicked,
     * or when {@link TreeView#edit(javafx.scene.control.TreeItem)} is called. This method will work on 
     * any {@link TreeView} instance, 
     * regardless of its generic type. However, to enable this, a {@link Callback} must be provided that
     * will convert the given String (from what the user typed in) into an instance of type T. This
     * item will then be passed along to the {@link TreeView#onEditCommitProperty()} callback.
     * 
     * @param onCommit A {@link Callback} that can convert the given String (from what the user typed in) 
     *      into an instance of type T.
     * @return A {@link Callback} that can be inserted into the {@link TreeView#cellFactoryProperty() cell
     *      factory property} of a TreeView, that enables textual editing of the content.
     */
    public static <T> Callback<TreeView<T>, TreeCell<T>> forTreeView(final Callback<String, T> onCommit) {
        return new Callback<TreeView<T>, TreeCell<T>>() {
            @Override public TreeCell<T> call(TreeView<T> list) {
                return new TextFieldTreeCell<T>(onCommit);
            }
        };
    }
    
    /**
     * Provides a {@link TextField} that allows editing of the cell content when the cell is double-clicked,
     * or when {@link TableView#edit(int, TableColumn)} is called. This method will only work on {@link TableColumn} instances
     * which are of type String.
     * 
     * @return A {@link Callback} that can be inserted into the {@link TableColumn#cellFactoryProperty() cell
     *      factory property} of a TableColumn, that enables textual editing of the content.
     */
    public static <S> Callback<TableColumn<S,String>, TableCell<S,String>> forTableColumn() {
        return forTableColumn(DEFAULT_STRING_ON_COMMIT);
    }
    
    /**
     * Provides a {@link TextField} that allows editing of the cell content when the cell is double-clicked,
     * or when {@link TableView#edit(int, TableColumn)} is called. This method will work on any {@link TableColumn} instance, 
     * regardless of its generic type. However, to enable this, a {@link Callback} must be provided that
     * will convert the given String (from what the user typed in) into an instance of type T. This
     * item will then be passed along to the {@link TableColumn#onEditCommitProperty()} callback.
     * 
     * @param onCommit A {@link Callback} that can convert the given String (from what the user typed in) 
     *      into an instance of type T.
     * @return A {@link Callback} that can be inserted into the {@link TableColumn#cellFactoryProperty() cell
     *      factory property} of a TableColumn, that enables textual editing of the content.
     */
    public static <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> forTableColumn(final Callback<String, T> onCommit) {
        return new Callback<TableColumn<S,T>, TableCell<S,T>>() {
            @Override public TableCell<S,T> call(TableColumn<S,T> list) {
                return new TextFieldTableCell<S,T>(onCommit);
            }
        };
    }
    
    private static final Callback<String, String> DEFAULT_STRING_ON_COMMIT = new Callback<String, String>() {
        @Override public String call(String value) {
            return value;
        };
    };
}
