<commit_before>package SW9.model_canvas;

import SW9.MouseTracker;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ObservableDoubleValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.util.Pair;

import java.util.ArrayList;
import java.util.List;

public class Edge {

    private final Location sourceLocation;
    private Location targetLocation = null;


    private final List<Nail> nails = new ArrayList<>();
    private Line lineCue = new Line();

    private boolean skipLine = true;

    ObservableList<Line> lines = FXCollections.observableArrayList();
    private BooleanBinding linesIsEmpty = new BooleanBinding() {
        {
            super.bind(lines);
        }

        @Override
        protected boolean computeValue() {
            return lines.isEmpty();
        }
    };


    // Mouse trackers
    private final MouseTracker canvasMouseTracker;

    public Edge(final Location sourceLocation, final MouseTracker canvasMouseTracker) {
        this.sourceLocation = sourceLocation;
        this.canvasMouseTracker = canvasMouseTracker;

        DoubleBinding[] cueBindings = getCueBindings();

        lineCue.startXProperty().bind(cueBindings[0]);
        lineCue.startYProperty().bind(cueBindings[1]);
        lineCue.endXProperty().bind(cueBindings[2]);
        lineCue.endYProperty().bind(cueBindings[3]);
        lineCue.setMouseTransparent(true);
        addChildToParent(lineCue);

        this.canvasMouseTracker.registerOnMousePressedEventHandler(event -> {
            if (skipLine) {
                skipLine = false;
                return;
            } else if (this.targetLocation != null) {
                return;
            }

            // Create nail
            final Nail nail = new Nail(lineCue.getEndX(), lineCue.getEndY());

            // Create a new line
            final Line line = new Line();

            // If it is the first line to be placed on the canvas
            if (linesIsEmpty.get()) {
                Pair<DoubleBinding, DoubleBinding> newLineStartBindings = getStartBindings(
                        sourceLocation.centerXProperty(),
                        sourceLocation.centerYProperty(),
                        nail.centerXProperty(),
                        nail.centerYProperty()
                );
                line.startXProperty().bind(newLineStartBindings.getKey());
                line.startYProperty().bind(newLineStartBindings.getValue());
            } else {
                final Nail previousNail = nails.get(nails.size() - 1);
                line.startXProperty().bind(previousNail.centerXProperty());
                line.startYProperty().bind(previousNail.centerYProperty());
            }

            if (ModelCanvas.mouseIsHoveringLocation()) {
                final Nail previousNail = nails.get(nails.size() - 1);
                this.targetLocation = ModelCanvas.getHoveredLocation();
                Pair<DoubleBinding, DoubleBinding> newLineEndBindings = getEndBindings(
                        previousNail.centerXProperty(),
                        previousNail.centerYProperty(),
                        targetLocation.centerXProperty(),
                        targetLocation.centerYProperty()
                );

                line.startXProperty().bind(previousNail.centerXProperty());
                line.startYProperty().bind(previousNail.centerYProperty());

                line.endXProperty().bind(newLineEndBindings.getKey());
                line.endYProperty().bind(newLineEndBindings.getValue());

            } else {
                line.endXProperty().bind(nail.centerXProperty());
                line.endYProperty().bind(nail.centerYProperty());
            }

            // TODO ensure you cannot link an edge to the sourcelocaton directly, you muhst have at least one nail


            if (this.targetLocation == null) {
                // Add the nail to the collection
                nail.setMouseTransparent(true);
                addChildToParent(nail);
                nails.add(nail);
            } else {<commit_msg>Allow for two locations to be connected directly<commit_after>package SW9.model_canvas;

import SW9.MouseTracker;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ObservableDoubleValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.util.Pair;

import java.util.ArrayList;
import java.util.List;

public class Edge {

    private final Location sourceLocation;
    private Location targetLocation = null;


    private final List<Nail> nails = new ArrayList<>();
    private Line lineCue = new Line();

    private boolean skipLine = true;

    ObservableList<Line> lines = FXCollections.observableArrayList();
    private BooleanBinding linesIsEmpty = new BooleanBinding() {
        {
            super.bind(lines);
        }

        @Override
        protected boolean computeValue() {
            return lines.isEmpty();
        }
    };


    // Mouse trackers
    private final MouseTracker canvasMouseTracker;

    public Edge(final Location sourceLocation, final MouseTracker canvasMouseTracker) {
        this.sourceLocation = sourceLocation;
        this.canvasMouseTracker = canvasMouseTracker;

        DoubleBinding[] cueBindings = getCueBindings();

        lineCue.startXProperty().bind(cueBindings[0]);
        lineCue.startYProperty().bind(cueBindings[1]);
        lineCue.endXProperty().bind(cueBindings[2]);
        lineCue.endYProperty().bind(cueBindings[3]);
        lineCue.setMouseTransparent(true);
        addChildToParent(lineCue);

        this.canvasMouseTracker.registerOnMousePressedEventHandler(event -> {
            if (skipLine) {
                skipLine = false;
                return;
            } else if (this.targetLocation != null) {
                return;
            }

            // Create nail
            final Nail nail = new Nail(lineCue.getEndX(), lineCue.getEndY());

            // Create a new line
            final Line line = new Line();

            // If it is the first line to be placed on the canvas
            if (linesIsEmpty.get()) {
                Pair<DoubleBinding, DoubleBinding> newLineStartBindings = getStartBindings(
                        sourceLocation.centerXProperty(),
                        sourceLocation.centerYProperty(),
                        nail.centerXProperty(),
                        nail.centerYProperty()
                );
                line.startXProperty().bind(newLineStartBindings.getKey());
                line.startYProperty().bind(newLineStartBindings.getValue());
            } else {
                final Nail previousNail = nails.get(nails.size() - 1);
                line.startXProperty().bind(previousNail.centerXProperty());
                line.startYProperty().bind(previousNail.centerYProperty());
            }

            // If we are hovering a location we want to set the target location and draw the last line
            if (ModelCanvas.mouseIsHoveringLocation()) {

                this.targetLocation = ModelCanvas.getHoveredLocation();

                // If the source location should be connected directly to itself
                if(this.targetLocation.equals(this.sourceLocation) && nails.isEmpty()) {
                    // TODO connect them (draw two nails and three lines connecting it)
                } else if(!this.targetLocation.equals(this.sourceLocation) && nails.isEmpty()) {

                    Pair<DoubleBinding, DoubleBinding> newLineStartBindings = getStartBindings(
                            sourceLocation.centerXProperty(),
                            sourceLocation.centerYProperty(),
                            targetLocation.centerXProperty(),
                            targetLocation.centerYProperty()
                    );

                    Pair<DoubleBinding, DoubleBinding> newLineEndBindings = getEndBindings(
                            sourceLocation.centerXProperty(),
                            sourceLocation.centerYProperty(),
                            targetLocation.centerXProperty(),
                            targetLocation.centerYProperty()
                    );

                    line.startXProperty().bind(newLineStartBindings.getKey());
                    line.startYProperty().bind(newLineStartBindings.getValue());

                    line.endXProperty().bind(newLineEndBindings.getKey());
                    line.endYProperty().bind(newLineEndBindings.getValue());
                } else {

                    final Nail previousNail = nails.get(nails.size() - 1);

                    Pair<DoubleBinding, DoubleBinding> newLineEndBindings = getEndBindings(
                            previousNail.centerXProperty(),
                            previousNail.centerYProperty(),
                            targetLocation.centerXProperty(),
                            targetLocation.centerYProperty()
                    );

                    line.startXProperty().bind(previousNail.centerXProperty());
                    line.startYProperty().bind(previousNail.centerYProperty());

                    line.endXProperty().bind(newLineEndBindings.getKey());
                    line.endYProperty().bind(newLineEndBindings.getValue());
                }

            } else {
                line.endXProperty().bind(nail.centerXProperty());
                line.endYProperty().bind(nail.centerYProperty());
            }

            if (this.targetLocation == null) {
                // Add the nail to the collection
                nail.setMouseTransparent(true);
                addChildToParent(nail);
                nails.add(nail);
            } else {
{'fraction_non_alphanumeric': 0.09288048321616002, 'fraction_numerical': 0.0015843152787404693, 'mean_word_length': 1.9908202546639029, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3856989', 'n_tokens_mistral': 2528, 'n_tokens_neox': 2390, 'n_words': 475}