package be.iminds.ilabt.jfed.ui.javafx.probe_gui.command_arguments;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.util.StringConverter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * StringArgumentChooser
 */
public class MultiStringArgumentProvidedOptionsChooser extends CommandArgumentChooser<List<String>> {
    @FXML
    protected ListView<SelectableImmutableString> valueField;
    @FXML
    protected TextField addTextField;

    //
    //
    // Important note: There are multiple *options* shown, *valueProperty* contains only the SELECTED options.
    //
    //

    protected final ObservableList<SelectableImmutableString> selectableOptions = FXCollections.observableArrayList();
    private final ObservableList<SelectableImmutableString> selectedOptionsList = FXCollections.observableArrayList();
    private final ObjectProperty<List<String>> valueProperty = new SimpleObjectProperty<>();

    private class SelectableImmutableString {
        private final BooleanProperty selected;
        private final String text;

        private SelectableImmutableString(String text, boolean selected) {
            this.text = text;
            this.selected = new SimpleBooleanProperty(selected);
            this.selected.addListener((observableValue, oldValue, newValue) -> {
                if (selectedOptionsList != null) {
                    if (!newValue)
                        selectedOptionsList.removeAll(SelectableImmutableString.this);
                    else {
                        assert !selectedOptionsList.contains(SelectableImmutableString.this);
                        selectedOptionsList.add(SelectableImmutableString.this);
                    }
                }
            });
            if (selected)
                selectedOptionsList.add(this);
        }

        public boolean getSelected() {
            return selected.get();
        }

        public BooleanProperty selectedProperty() {
            return selected;
        }

        public String getText() {
            return text;
        }
    }

    public MultiStringArgumentProvidedOptionsChooser(List<String> options) {
        FXMLLoader fxmlLoader =
                new FXMLLoader(getClass().getResource("MultiStringArgumentProvidedOptionsChooser.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();

            assert valueField != null;

            valueField.setCellFactory(list -> {
                CheckBoxListCell<SelectableImmutableString> cb =
                        new CheckBoxListCell<>();
                cb.setConverter(new StringConverter<SelectableImmutableString>() {
                    @Override
                    public String toString(SelectableImmutableString selectableImmutableString) {
                        return selectableImmutableString.getText();
                    }

                    @Override
                    public SelectableImmutableString fromString(String s) {
                        throw new RuntimeException("This direction doesn't work and is not needed");
                    }
                });
                cb.setSelectedStateCallback(SelectableImmutableString::selectedProperty);
                return cb;
//                    return new SelectableItemCell();
            }
            );

            setAllOptions(options);

            valueField.setItems(this.selectableOptions);
//            valueField.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

            if (!valueField.getItems().isEmpty())
                valueField.getSelectionModel().selectLast();


            selectedOptionsList.addListener((ListChangeListener<SelectableImmutableString>) change -> valueProperty.set(new ArrayList<>(getSelectedStrings())));
            //init
            valueProperty.set(new ArrayList<>(getSelectedStrings()));
            value = valueProperty;
            assert value != null;
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    private List<String> getSelectedStrings() {
        List<String> selectedItemsStr = new ArrayList<>();
        for (SelectableImmutableString sms : selectedOptionsList) {
            selectedItemsStr.add(sms.getText());
        }
        return selectedItemsStr;
    }

    protected void setAllOptions(List<String> options) {
        selectableOptions.clear();
        selectedOptionsList.clear();
        for (String option : options) {
            SelectableImmutableString selMutStr = new SelectableImmutableString(option, false);
            selectableOptions.add(selMutStr);
        }
        selectedOptionsList.clear();
    }


    public void add() {
        SelectableImmutableString toAdd = new SelectableImmutableString(addTextField.getText(), true);
        selectableOptions.add(toAdd);
    }


//    static class SelectableItemCell extends ListCell<Pair<Boolean, String>> {
//        private CheckBox checkbox;
//
//        public SelectableItemCell() {
//            checkbox = new CheckBox();
//            checkbox.setOnAction(new EventHandler<ActionEvent>() {
//                @Override
//                public void handle(ActionEvent actionEvent) {
//                    SelectableItemCell.this.commitEdit(new Pair<Boolean, String>(checkbox.isSelected(), checkbox.getText()));
//                }
//            });
//        }
//
//        @Override
//        public void updateItem(Pair<Boolean, String> item, boolean empty) {
//            super.updateItem(item, empty);
//            if (item != null) {
//                checkbox.setSelected(item.getKey());
//                checkbox.setText(item.getValue());
//                setGraphic(checkbox);
//            } else {
//                checkbox.setText("");
//                checkbox.setSelected(false);
//            }
//        }
//    }
}
