package org.mbari.m3.vars.annotation.ui.concepttree;

import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import org.mbari.m3.vars.annotation.model.Concept;
import org.mbari.m3.vars.annotation.services.ConceptService;
import org.mbari.m3.vars.annotation.ui.shared.FilterableTreeItem;
import org.mbari.m3.vars.annotation.ui.shared.TreeItemPredicate;

import java.util.stream.Collectors;

/**
 * @author Brian Schlining
 * @since 2017-05-16T12:06:00
 */
public class SearchTreePaneFactory {

    // TODO Need an indicator to show that concepts are still loading. Otherwise
    // searches results will be incomplete but the user won't know that the load
    // process is ongoing.

    // TODO often Kyra will search for a known term, say malacostrea, then browse
    // to see what's underneath it. Maybe add "show this node" item to the
    // context menu that clears the search, , scrolls to the selected node and
    // expands all children.

    private ConceptService conceptService;

    public SearchTreePaneFactory(ConceptService conceptService) {
        this.conceptService = conceptService;
    }

    protected BorderPane build() {
        final TreeView<Concept> treeView = new TreeViewFactory(conceptService).build();


        TextField textField = new TextField();
        textField.setPromptText("Filter ...");
        textField.textProperty().addListener((obs, oldValue, newValue) -> {
            TreeItem<Concept> root = treeView.getRoot();
            if (newValue.length() > oldValue.length()) {
                if (root != null) {
                    expand(root);
                }
            }
            if (newValue.isEmpty()) {
                if (root != null) {
                    collapse(root);
                }
            }
        });

        ContextMenu contextMenu = treeView.getContextMenu();
        MenuItem showChildren = new MenuItem("Show All Children");
        contextMenu.getItems().addAll(showChildren);
        showChildren.setOnAction(event -> {
            // Get node
            final TreeItem<Concept> selectedItem = treeView.getSelectionModel().getSelectedItem();
            textField.setText("");
            treeView.getSelectionModel().select(selectedItem);
            expand(selectedItem);
        });


        /*
          The KB tree is lazy loaded. So we have to listen for when the root is added before
          we can
         */
        ChangeListener<TreeItem<Concept>> rootListener = new ChangeListener<TreeItem<Concept>>() {

            private boolean completed = false;

            @Override
            public void changed(ObservableValue<? extends TreeItem<Concept>> observable, TreeItem<Concept> oldValue, TreeItem<Concept> newValue) {
                if (!completed) {
                    FilterableTreeItem<Concept> root = (FilterableTreeItem<Concept>) newValue;
                    root.predicateProperty().bind(Bindings.createObjectBinding(() -> {
                        if (textField.getText() == null || textField.getText().isEmpty()) {
                            return null;
                        }
                        else {
                            return TreeItemPredicate.create(c -> {
                                String t = c.getName();
                                if (c.getConceptDetails() != null) {
                                    t = t + c.getConceptDetails()
                                            .getAlternateNames()
                                            .stream()
                                            .collect(Collectors.joining());
                                }
                                return t.toLowerCase().contains(textField.getText().toLowerCase());
                            });
                        }
                    }, textField.textProperty()));
                    completed = true;
                }
            }
        };
        treeView.rootProperty().addListener(rootListener);

        HBox.setHgrow(textField, Priority.ALWAYS);
        BorderPane pane = new BorderPane();
        pane.setCenter(treeView);
        pane.setTop(textField);

        return pane;
    }

    private static void expand(TreeItem<?> item) {
        if(item != null && !item.isLeaf()){
            item.setExpanded(true);
            for(TreeItem<?> child :item.getChildren()){
                expand(child);
            }
        }
    }

    private static void collapse(TreeItem<?> item) {
        if(item != null && !item.isLeaf()){
            item.setExpanded(false);
            for(TreeItem<?> child :item.getChildren()){
                collapse(child);
            }
        }
    }




}

@@ -888,273 +888,9 @@
 g.%0A%0A
-    // TODO often Kyra will search for a known term, say malacostrea, then browse%0A    // to see what's underneath it. Maybe add %22show this node%22 item to the%0A    // context menu that clears the search, , scrolls to the selected node and%0A    // expands all children.
 %0A
+
 %0A   
@@ -1711,24 +1711,314 @@
        %7D);%0A%0A
+        /*%0A         Often Kyra will search for a known term, say malacostrea, then browse%0A         to see what's underneath it. Maybe add %22show this node%22 item to the%0A         context menu that clears the search, , scrolls to the selected node and%0A         expands all children.%0A        */%0A
         Cont
@@ -2603,16 +2603,16 @@
  before%0A
-
         
@@ -2619,16 +2619,28 @@
   we can
+ bind to it.
 %0A       

check point