package at.irian.ankor.todosample.fxclient.task;

import at.irian.ankor.action.Action;
import at.irian.ankor.fx.binding.BindingContext;
import at.irian.ankor.ref.Ref;
import at.irian.ankor.ref.listener.RefChangeListener;
import at.irian.ankor.ref.listener.RefListeners;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.util.Callback;

import java.net.URL;
import java.util.LinkedHashMap;
import java.util.ResourceBundle;

import static at.irian.ankor.fx.binding.ValueBindingsBuilder.bind;
import static at.irian.ankor.todosample.fxclient.App.refFactory;

public class TaskListController implements Initializable {
    //private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(TaskListController.class);

    private BindingContext bindingContext = new BindingContext();
    private Ref modelRef;

    @FXML public ListView tasksList;
    @FXML public ToggleButton toggleAll;
    @FXML public TextField newTodo;
    @FXML public Label todoCountNum;
    @FXML public Button clearButton;

    @FXML public ToggleButton filterAll;
    @FXML public ToggleButton filterActive;
    @FXML public ToggleButton filterCompleted;
    @FXML public ToggleGroup filterTG;

    @FXML public Node footerTop;
    @FXML public Node footerBottom;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        modelRef = refFactory().rootRef().append("model");

        // TODO: @ActionListener syntax
        RefListeners.addPropChangeListener(modelRef, new RefChangeListener() {
            @Override
            public void processChange(Ref changedProperty) {
                initialize();
            }
        });

        refFactory().rootRef().fire(new Action("init"));

    }

    public void initialize() {
        bind(modelRef.append("tasks"))
                .toProperty(tasksList.itemsProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("toggleAll"))
                .toProperty(toggleAll.selectedProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("itemsLeft"))
                .toProperty(todoCountNum.textProperty())
                .forIntegerValue()
                .createWithin(bindingContext);

        bind(modelRef.append("itemsCompleteText"))
                .toProperty(clearButton.textProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("clearButtonVisibility"))
                .toProperty(clearButton.visibleProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("footerVisibility"))
                .toProperty(footerTop.visibleProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("footerVisibility"))
                .toProperty(footerBottom.visibleProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("footerVisibility"))
                .toProperty(toggleAll.visibleProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("filterAllSelected"))
                .toProperty(filterAll.selectedProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("filterActiveSelected"))
                .toProperty(filterActive.selectedProperty())
                .createWithin(bindingContext);

        bind(modelRef.append("filterCompletedSelected"))
                .toProperty(filterCompleted.selectedProperty())
                .createWithin(bindingContext);

        tasksList.setCellFactory(new Callback<ListView, ListCell>() {
            @Override
            public ListCell call(ListView listView) {
                return new TaskComponentListCell();
            }
        });
    }

    @FXML
    public void newTodo(ActionEvent actionEvent) {
        if (!newTodo.getText().equals("")) {

            LinkedHashMap<String, Object> params = new LinkedHashMap<>();
            params.put("title", newTodo.getText());

            modelRef.fire(new Action("newTask", params));
            newTodo.clear();
        }
    }

    @FXML
    public void clearTasks(ActionEvent actionEvent) {
        modelRef.fire(new Action("clearTasks"));
    }

    @FXML
    public void toggleAll(ActionEvent actionEvent) {
        modelRef.fire(new Action("toggleAll"));
    }

    private class TaskComponentListCell extends ListCell<LinkedHashMap<String, Object>> {
        @Override
        public void updateItem(LinkedHashMap<String, Object> item, boolean empty) {
            super.updateItem(item, empty);
            if (item != null) {
                Object id = item.get("id");
                String title = (String)item.get("title");
                boolean completed = (boolean)item.get("completed");

                if (getGraphic() == null) {
                    setGraphic(new TaskPane(modelRef));
                }

                TaskPane node = (TaskPane) this.getGraphic();
                node.setIndex(getIndex());
                node.setText(title);
                node.getCompleted().setSelected(completed);

                setGraphic(node);
            }
        }
    }
}

@@ -321,16 +321,47 @@
 l.FXML;%0A
+import javafx.fxml.FXMLLoader;%0A
 import j
@@ -494,16 +494,42 @@
 et.URL;%0A
+import java.util.HashMap;%0A
 import j
@@ -4463,24 +4463,164 @@
 %22));%0A    %7D%0A%0A
+    // XXX: Tune performance using a cache but produces glitches%0A    // HashMap%3CObject, TaskPane%3E cache = new HashMap%3CObject, TaskPane%3E();%0A%0A
     private 
@@ -4697,16 +4697,17 @@
 ect%3E%3E %7B%0A
+%0A
         
@@ -4875,55 +4875,21 @@
 null
-) %7B%0A                Object id = item.get(%22id%22);
+ && !empty) %7B
 %0A   
@@ -5126,25 +5126,24 @@
           %7D%0A
-%0A
             
@@ -5177,13 +5177,8 @@
 ne) 
-this.
 getG
@@ -5186,16 +5186,283 @@
 aphic();
+%0A%0A                /*%0A                if (cache.get(getIndex()) == null) %7B%0A                    cache.put(getIndex(), new TaskPane(modelRef));%0A                %7D%0A                TaskPane node = cache.get(getIndex());%0A                setGraphic(node);%0A                */%0A
 %0A       
@@ -5597,43 +5597,8 @@
 ed);
-%0A%0A                setGraphic(node);
 %0A   

add support for caching task nodes