package org.example;

import org.graphstream.algorithm.Toolkit;
import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.DefaultGraph;
import org.graphstream.graph.implementations.SingleGraph;
import org.graphstream.stream.file.FileSource;
import org.graphstream.stream.file.FileSourceEdge;
import org.graphstream.stream.file.FileSourceFactory;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

public class GraphManipulation {
    public static Graph getTheFileEdge(String path) {
        Graph graph = new SingleGraph("g");

        try {
            FileSourceEdge fs = new FileSourceEdge();
            fs.addSink(graph);
            fs.readAll(path);
        } catch (Exception e) {
            System.err.println("Erreur lors du chargement du graphe : " + e.getMessage());
            return null;
        }

        return graph;
    }

    public static int getNodeCount(Graph g) {return g.getNodeCount();}

    public static int getEdgeCount(Graph g) { return g.getEdgeCount();}


    public static double getAverageDegree(Graph g) {return Toolkit.averageDegree(g);}

    public static double getAverageClusteringCoefficient(Graph g) {return Toolkit.averageClusteringCoefficient(g);}

    public static double getRandomGraphClustering(double averageDegree , int NodeCount) {
        return averageDegree / (NodeCount - 1);
    }
    public static Boolean isOrientedGraph(Graph graph) {
        for (Edge edge : graph.edges().toList()) {
            if (edge.isDirected()) {
                return true;
            }
        }
        return false;
    }


    /**
     * Vérifie si un graphe non orienté est connexe
     * @param g le graphe GraphStream
     * @return true si tous les nœuds sont connectés entre eux, false sinon
     */
    public static boolean isConnexe(Graph g) {
        if (g.getNodeCount() == 0) return true;

        Set<Node> visited = new HashSet<>();
        Queue<Node> queue = new LinkedList<>();

        Node start = g.getNode(0);
        queue.add(start);
        visited.add(start);

        while (!queue.isEmpty()) {
            Node current = queue.poll();
            current.edges().forEach(edge -> {
                Node neighbor = edge.getSourceNode().equals(current) ? edge.getTargetNode() : edge.getSourceNode();
                if (!visited.contains(neighbor)) {
                    visited.add(neighbor);
                    queue.add(neighbor);
                }
            });
        }

        return visited.size() == g.getNodeCount();
    }

    public static void getDegreeDistribution(Graph graph ) {
        int[] dd = Toolkit.degreeDistribution(graph);
        String filePath = "src/main/gnuplot/dd_dblp.dat";
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
            for (int k = 0; k < dd.length; k++) {
                if (dd[k] != 0) {
                    double fraction = (double) dd[k] / graph.getNodeCount();
                    writer.write(String.format(Locale.US, "%d\t%.8f%n", k, fraction));
                    //System.out.printf(Locale.US, "%6d%20.8f%n", k, fraction);
                }
            }
            System.out.println("Distribution des degrés sauvegardée dans : " + filePath);
        } catch (IOException e) {
            System.err.println("Erreur lors de l'écriture du fichier : " + e.getMessage());
        }
    }


}
