package com.ecep.contract.controller.table.cell;

import org.controlsfx.control.textfield.AutoCompletionBinding;
import org.controlsfx.control.textfield.TextFields;
import org.springframework.util.StringUtils;

import com.ecep.contract.SpringApp;
import com.ecep.contract.converter.EntityStringConverter;
import com.ecep.contract.service.InventoryService;
import com.ecep.contract.vo.InventoryVo;

import javafx.scene.Node;
import javafx.scene.control.Cell;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
import javafx.scene.control.TableColumn;
import javafx.scene.input.KeyCode;
import lombok.Setter;

public class InventoryAutoCompletionTableCell<V> extends TableCell<V, Integer> {
    /**
     * 创建一个InventoryAutoCompletionTableCell的单元格工厂
     * 
     * @param inventoryService 库存服务
     * @param <V>              表格行数据类型
     * @return 表格列的单元格工厂
     */
    public static <V> javafx.util.Callback<TableColumn<V, Integer>, TableCell<V, Integer>> forTableColumn(
            InventoryService inventoryService) {
        return param -> new InventoryAutoCompletionTableCell<>(inventoryService);
    }

    private TextField textField;

    private InventoryService inventoryService;

    public InventoryAutoCompletionTableCell() {
    }

    public InventoryAutoCompletionTableCell(InventoryService service) {
        this();
        this.inventoryService = service;
    }

    InventoryService getInventoryService() {
        if (inventoryService == null) {
            inventoryService = SpringApp.getBean(InventoryService.class);
        }
        return inventoryService;
    }

    @Override
    public void startEdit() {
        super.startEdit();
        if (!isEditing()) {
            return;
        }

        if (textField == null) {
            textField = createTextField(this);
            AutoCompletionBinding<InventoryVo> binding = TextFields.bindAutoCompletion(textField,
                    suggest -> getInventoryService().search(suggest.getUserText()),
                    getInventoryService().getStringConverter());
            binding.setOnAutoCompleted(event -> {
                commitEdit(event.getCompletion().getId());
            });
        }

        startEdit(this, textField);
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        cancelEdit(this, null);
    }

    @Override
    public void updateItem(Integer item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText("");
            setGraphic(null);
            return;
        }
        if (isEditing()) {
            if (textField != null) {
                textField.setText(getItemText(this));
            }
            setText(null);
            setGraphic(textField);
        } else {
            setText(getItemText(this));
            setGraphic(null);
        }
    }

    private String getItemText(Cell<Integer> cell) {
        Integer inventoryId = cell.getItem();
        if (inventoryId == null) {
            return "-";
        }
        InventoryVo inventory = getInventoryService().findById(inventoryId);
        return inventory == null ? "-"
                : StringUtils.hasText(inventory.getCode()) ? inventory.getCode() : ("#" + inventory.getId());
    }

    TextField createTextField(final Cell<Integer> cell) {
        final TextField textField = new TextField(getItemText(cell));
        textField.setOnKeyReleased(t -> {
            if (t.getCode() == KeyCode.ESCAPE) {
                cell.cancelEdit();
                t.consume();
                return;
            }
            if (t.getCode() == KeyCode.ENTER) {
                InventoryVo fromString = getInventoryService().findByName(textField.getText());
                if (fromString != null) {
                    cell.commitEdit(fromString.getId());
                    t.consume();
                }
            }
        });

        return textField;
    }

    void startEdit(final Cell<Integer> cell,
            final TextField textField) {
        if (textField != null) {
            textField.setText(getItemText(cell));
        }
        cell.setText(null);
        cell.setGraphic(textField);
        textField.selectAll();
        // requesting focus so that key input can immediately go into the
        // TextField (see RT-28132)
        textField.requestFocus();
    }

    void cancelEdit(Cell<Integer> cell,
            Node graphic) {
        cell.setText(getItemText(cell));
        cell.setGraphic(graphic);
    }
}