package net.christophermerrill.FancyFxTree.example;

import javafx.collections.*;
import javafx.scene.control.*;
import javafx.scene.input.*;
import net.christophermerrill.FancyFxTree.*;

import java.util.*;

/**
 * @author Christopher L Merrill (see LICENSE.txt for license details)
 */
public class ExampleOperationHandler extends FancyTreeOperationHandler<ExampleTreeNodeFacade>
    {
    public ExampleOperationHandler(ExampleDataNode root)
        {
        _root = root;
        }

    @Override
    public boolean handleDelete(ObservableList<TreeItem<ExampleTreeNodeFacade>> selected_items)
        {
        for (TreeItem<ExampleTreeNodeFacade> item : selected_items)
            {
            ExampleDataNode node_to_remove = item.getValue().getModelNode();
            ExampleDataNode parent = _root.findParentFor(node_to_remove);
            if (parent != null)
                parent.removeChild(node_to_remove);
            }
        return true;
        }

    @Override
    public boolean handleCut(ObservableList<TreeItem<ExampleTreeNodeFacade>> selected_items)
        {
        _cut = true;
        _copy = false;
        rememberSelection(selected_items);
        return true;
        }

    @Override
    public boolean handleCopy(ObservableList<TreeItem<ExampleTreeNodeFacade>> selected_items)
        {
        _copy = true;
        _cut = false;
        rememberSelection(selected_items);
        return true;
        }

    private void rememberSelection(ObservableList<TreeItem<ExampleTreeNodeFacade>> selected_items)
        {
        _selected_nodes = new ArrayList<>();
        for (TreeItem<ExampleTreeNodeFacade> item : selected_items)
            _selected_nodes.add(item.getValue().getModelNode());
        }

    @Override
    public boolean handlePaste(ObservableList<TreeItem<ExampleTreeNodeFacade>> selected_items)
        {
        ExampleDataNode target = selected_items.get(0).getValue().getModelNode();
        ExampleDataNode parent = _root.findParentFor(target);

        for (ExampleDataNode selected_node : _selected_nodes)
            {
            ExampleDataNode node_to_paste;
            if (_copy)
                node_to_paste = ExampleDataNode.deepCopy(selected_node, true);
            else if (_cut)
                {
                ExampleDataNode parent_to_cut_from = _root.findParentFor(selected_node);
                parent_to_cut_from.removeChild(selected_node);
                node_to_paste = selected_node;
                }
            else
                {
                System.out.println("Expected either copy or paste. Neither...fail!");
                continue;
                }
            parent.addAfter(node_to_paste, target);
            }

        _copy = false;
        _cut = false;
        _selected_nodes = null;
        return true;
        }

    @Override
    public StartDragInfo startDrag(List<List<Integer>> selection_paths, ObservableList<TreeItem<ExampleTreeNodeFacade>> selected_items)
        {
        StartDragInfo info = new StartDragInfo();
        _dragged_items = selected_items;
        List<ExampleDataNode> selections = new ArrayList<>();
        for (TreeItem<ExampleTreeNodeFacade> item : selected_items)
            selections.add(item.getValue().getModelNode());
        info.addContent(LIST_OF_NODES, selections);
        _drag_count = selected_items.size();
        return info;
        }

    @Override
    public DragOverInfo dragOver(Dragboard dragboard)
        {
        DragOverInfo info = new DragOverInfo();
        info.addAllModesAndLocations();
        return info;
        }

    @Override
    public boolean finishDrag(TransferMode transfer_mode, Dragboard dragboard, FancyTreeNodeFacade item, DropLocation location)
        {
        if (dragboard.getContent(LIST_OF_NODES) != null)
            {
            _dropped_nodes = (List<ExampleDataNode>) dragboard.getContent(LIST_OF_NODES);
            ExampleDataNode parent;
            int add_index;
            switch (location)
                {
                case BEFORE:
                    parent = _root.findParentFor((ExampleDataNode) item.getModelNode());
                    add_index = parent.getChildren().indexOf(item.getModelNode());
                    break;
                case ON:
                    parent = (ExampleDataNode) item.getModelNode();
                    add_index = ((ExampleDataNode) item.getModelNode()).getChildren().size();
                    break;
                case AFTER:
                    parent = _root.findParentFor((ExampleDataNode) item.getModelNode());
                    add_index = parent.getChildren().indexOf(item.getModelNode()) + 1;
                    break;
                default:
                    return false;
                }

            for (ExampleDataNode node : _dropped_nodes)
                {
                ExampleDataNode node_to_drop;
                if (transfer_mode.equals(TransferMode.COPY))
                    node_to_drop = ExampleDataNode.deepCopy(node, true);
                else
                    {
                    node_to_drop = node;
                    _root.findParentFor(node).removeChild(node_to_drop);
                    }

                parent.addChild(add_index, node_to_drop);
                add_index++;
                }
            return true;
            }

        return false;
        }

    private List<ExampleDataNode> _selected_nodes;
    private boolean _cut = false;
    private boolean _copy = false;

    public int _drag_count;
    public ObservableList<TreeItem<ExampleTreeNodeFacade>> _dragged_items;
    public List<ExampleDataNode> _dropped_nodes;
    public Object _dropped_content;

    private ExampleDataNode _root;

    private final static DataFormat LIST_OF_NODES = new DataFormat("application/x-ListOfExampleDataNodes");
    }



@@ -46,16 +46,45 @@
 ample;%0A%0A
+import javafx.application.*;%0A
 import j
@@ -5236,32 +5236,111 @@
 %0A               
+ final int index_to_add_at = add_index;%0A                Platform.runLater(() -%3E
  parent.addChild
@@ -5340,25 +5340,31 @@
 ddChild(
-add_
 index
+_to_add_at
 , node_t
@@ -5362,33 +5362,100 @@
 t, node_to_drop)
-;
+); // updates to tree should be done on the UI thread when possible?
 %0A               

fix unreliable implementation that made unit test unstable