package leigh.elements.javafx.type1;

import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import leigh.elements.ElementBase;
import leigh.elements.sdk.type1.NodeGraphElement;
import leigh.eo.EO;
import leigh.eo.EOListener;
import leigh.eo.EOLoop;
import leigh.eo.EditEventGenerator;
import leigh.mecha.javafx.JavaFXConstants;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import leigh.mecha.nodegraph.GraphSerializer;
import leigh.mecha.nodegraph.NodeConfig;
import leigh.mecha.nodegraph.javafx.NodeGraphJFX;

import java.io.Serializable;
import java.util.List;

/**
 * Implementation of the node graph editor for JavaFX.
 *
 * @author Alex Leigh
 */
public class GraphElementJFX extends ElementBase implements ElementJFX {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(GraphElementJFX.class);
    private final VBox base = new VBox();
    private final ScrollPane scrollPane = new ScrollPane();
    private boolean eventArmed = true;

    public GraphElementJFX(EO elementCfg, List<NodeConfig> configs) {
        super(elementCfg);

        Pane root = new Pane();
        scrollPane.setContent(root);
        scrollPane.setPannable(true);

        GraphSerializer gs = new GraphSerializer();
        NodeGraphJFX g = new NodeGraphJFX(root, configs);

        // When the contents of the node change, we update our cfg object.
        g.getListeners().add(() -> {
            EOLoop graphState = gs.save(g);
            eventArmed = false;
            elementCfg.setValue(NodeGraphElement.KEY_GRAPH, graphState);
            eventArmed = true;
            logger.debug("Serialized graph: {}", graphState);
        });

        EditEventGenerator et = (EditEventGenerator) elementCfg.getEditTracker();
        et.addListener(elementCfg, new EOListener() {
            @Override
            public void valueUpdated(EO eo, String key, Serializable oldValue, Serializable newValue) throws Exception {
                // If the value changes in the cfg, and we are armed, we load.
                if (eventArmed) {
                    if (key.equals(NodeGraphElement.KEY_GRAPH)) {
                        g.clear();
                        gs.load(g, (EOLoop) newValue, configs);
                    }
                }
            }
        });

        // If we have an initial state, load it now.
        EOLoop graphState = elementCfg.getValueLoop(NodeGraphElement.KEY_GRAPH);
        if (graphState.size() > 0) {
            gs.load(g, graphState, configs);
        }

        scrollPane.setPrefHeight(JavaFXConstants.REALLY_TALL_HEIGHT);
        base.getChildren().add(scrollPane);
    }

    @Override
    public Node getJavaFXNode() {
        return base;
    }
}
