import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ConnectedCircles extends Application {
  @Override // Przesłanianie metody start z klasy Application
  public void start(Stage primaryStage) {
    // Tworzenie sceny i umieszczanie jej w oknie
    Scene scene = new Scene(new CirclePane(), 450, 350);
    primaryStage.setTitle("ConnectedCircles"); // Ustawianie nagłówka okna
    primaryStage.setScene(scene); // Umieszczanie sceny w oknie
    primaryStage.show(); // Wyświetlanie okna
  }

  /** Panel do wyświetlania kół */
  class CirclePane extends Pane {
    public CirclePane() {
      this.setOnMouseClicked(e -> {
        if (!isInsideACircle(new Point2D(e.getX(), e.getY()))) { 
          // Dodawanie nowego koła
          getChildren().add(new Circle(e.getX(), e.getY(), 20));
          colorIfConnected();
        }
      });
    }

    /** Zwraca true, jeśli punkt znajduje się wewnątrz istniejącego koła */
    private boolean isInsideACircle(Point2D p) {
      for (Node circle: this.getChildren())
        if (circle.contains(p))
          return true;

      return false;
    }

    /** Kolorowanie wszystkich kół, jeśli są połączone */
    private void colorIfConnected() {
      if (getChildren().size() == 0)
        return; // Panel nie zawiera kół

      // Tworzenie krawędzi
      java.util.List<Edge> edges = 
          new java.util.ArrayList<>();
      for (int i = 0; i < getChildren().size(); i++)
        for (int j = i + 1; j < getChildren().size(); j++)
          if (overlaps((Circle)(getChildren().get(i)), 
              (Circle)(getChildren().get(j)))) {
            edges.add(new Edge(i, j));
            edges.add(new Edge(j, i));
          }

      // Tworzenie grafu z kołami jako wierzchołkami
      Graph<Node> graph = new UnweightedGraph<>
        ((java.util.List<Node>)getChildren(), edges);
      UnweightedGraph<Node>.SearchTree tree = graph.dfs(0); 
      boolean isAllCirclesConnected = getChildren().size() == tree
          .getNumberOfVerticesFound();

      for (Node circle: getChildren()) {
        if (isAllCirclesConnected) { // Wszystkie koła są połączone
          ((Circle)circle).setFill(Color.RED);
        } 
        else {
          ((Circle)circle).setStroke(Color.BLACK);
          ((Circle)circle).setFill(Color.WHITE);
        }
      }
    }
  }
  
  public static boolean overlaps(Circle circle1, Circle circle2) {
    return new Point2D(circle1.getCenterX(), circle1.getCenterY()).
      distance(circle2.getCenterX(), circle2.getCenterY()) 
      <= circle1.getRadius() + circle2.getRadius();
  }

  /**
   * Metoda main jest potrzebna tylko w środowiskach IDE z ograniczoną obsługą platformy JavaFX.
   * Nie jest potrzebna przy uruchamianiu kodu w wierszu poleceń.
   */
  public static void main(String[] args) {
    launch(args);
  }
}
