/*
 * Copyright (C) 2019 Andrew Gegg
 *
 *	This file is part of the Gardeners Notebook application
 *
 * The Gardeners Notebook application is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl.html>.
 */
package uk.co.gardennotebook;

import java.time.format.DateTimeParseException;
import javafx.event.ActionEvent;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;

/**
	*	Support updatable text fields in in-line tables, e.g. PlantVarieties in the PlantSpecies editor
	*
    *   @param <S>  the Class of the items in the table
    *   @param <T>  the type of the item in the cell
    * 
	*	@author Andy Gegg
	*	@version	2.4.0
	*	@since	2.4.0
 */
public class TextFieldTableCellTabOut <S, T> extends TableCell<S, T>
{
    private final static StringConverter<?> defaultStringConverter = new StringConverter<Object>() {
        @Override public String toString(Object t) {
            return t == null ? null : t.toString();
        }

        @Override public Object fromString(String string) {
            return (Object) string;
        }
    };

private final StringConverter<T> converter;

/**
 * Convenience constructor - THE TYPE OF THE CELL ITEM MUST BE String
 */    
    public TextFieldTableCellTabOut()
    {
        this(null);
    }

/**
 * Construct a general purpose Cell editor.
 * 
 * @param converter a converter to convert the cell item of type T to/from a String for display.
 *                  May only be null if the cell type T is String
 */    
    public TextFieldTableCellTabOut(StringConverter<T> converter)
    {
        if (converter == null)
        {
            this.converter = (StringConverter<T>) defaultStringConverter;
        }
        else
        {
            this.converter = converter;
        }
    }
    
    @Override
    protected void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
    	if (item == null || empty)
		{
			setText(null);
			setGraphic(null);
			return;
		}
        updateViewMode();
    }

    @Override
    public void startEdit() {
        if (!isEditable()
            || !getTableView().isEditable()
            || !getTableColumn().isEditable())
        {
            return;
        }
        super.startEdit();
        updateViewMode();
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        updateViewMode();
    }

    private void updateViewMode() {
        // protect against empty rows at end of displayed table
        if (getItem() == null) {
            return;
        }

        setGraphic(null);
        setText(null);
        if (isEditing())
        {
            VBox vBox = new VBox();
            TextField dp = new TextField();
            T oldValue = getItem();
            
            String itemText = "";
            if (getItem() != null)
            {
                if (converter == null)
                {
                    itemText = getItem().toString();
                }
                else
                {
                    itemText = converter.toString(getItem());
                }
            }
            dp.setText(itemText);
            
                dp.setOnAction(ev -> {
                        try {
                            commitEdit(converter.fromString(dp.getText()));
                        }
                        catch (DateTimeParseException | NumberFormatException e)
                        {
                            commitEdit(oldValue);
                        }
                    });
            //  if user tabs out after editting, make sure the TextField updates
            dp.focusedProperty().addListener((obj, wasFocused, isFocused) -> {
                if (wasFocused && !isFocused) {
                    dp.fireEvent(new ActionEvent());
                }
            });
            vBox.getChildren().add(dp);
            setGraphic(vBox);
            dp.selectAll();
            dp.requestFocus();
        } 
        else if (getItem() != null)
        {
            String itemText = "";
            if (converter == null)
            {
                itemText = getItem().toString();
            }
            else
            {
                itemText = converter.toString(getItem());
            }
            setText(itemText);
        }
    }
    
}
