import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.DefaultGraph;
import org.graphstream.stream.file.FileSource;
import org.graphstream.stream.file.FileSourceDGS;
import org.graphstream.ui.graphicGraph.GraphPosLengthUtils;
import java.io.IOException;
import java.util.Arrays;
import java.util.Hashtable;

/**
 * The goal of this class is to compute the correlation Dimension of the graph store in a dgs file
 *
 */
public class CorrelationDimension {

	/**
	 * The goal of the function is to add to the input argument graph g all the nodes present in the dgs file at the
	 * argument path.
	 *
	 * @param g graph to which we want to add the nodes
	 * @param path the path to the dgs file where the graph data is store
	 */
	public void add_node_to_graph_from_dgs_file(Graph g, String path, int nb_noeuds) throws IOException {
		FileSource fs = new FileSourceDGS();

		fs.addSink(g);
		int i = 0;
		try {
			fs.begin(path);
			while (fs.nextEvents() && i <= nb_noeuds) {
				i = i + 1;
			}
		} catch( IOException e) {
			throw  new IOException(e);
		}
	}

	/**
	 * The goal of this function is to find the max and the value of all the x coordinates and the same for the y
	 * coordinates of the graph g
	 * @param g the graph in which we are searching the min and max coordinates
	 * @return a Hashtable to associate the values to understandable key :
	 * x_min = the minimal x coordinate
	 * x_max = the maximal x coordinate
	 * y_min = the y min coordinate
	 * y_max = the y max coordinate
	 */
	public Hashtable<String, Float> get_min_max_coord(Graph g) {
		Hashtable<String, Float> extreme_coord = new Hashtable<>();
		extreme_coord.put("x_min", Float.MAX_VALUE);
		extreme_coord.put("x_max", Float.MIN_VALUE);
		extreme_coord.put("y_min", Float.MAX_VALUE);
		extreme_coord.put("y_max", Float.MIN_VALUE);
		g.nodes().forEachOrdered((n) -> {
			double[] coords = GraphPosLengthUtils.nodePosition(n);
			if (coords[0] > extreme_coord.get("x_max")) {
				extreme_coord.put("x_max", (float) coords[0]);
			}
			if (coords[0] > extreme_coord.get("x_min")) {
				extreme_coord.put("x_max", (float) coords[0]);
			}
			if (coords[1] > extreme_coord.get("y_max")) {
				extreme_coord.put("y_max", (float) coords[0]);
			}
			if (coords[1] > extreme_coord.get("y_min")) {
				extreme_coord.put("y_max", (float) coords[0]);
			}
		});
		return extreme_coord;
	}

	/**
	 * The goal of this function is to move the graph to the origine with the min values. We are also going to rescale
	 * the nodes of the graph wit the attribut scale
	 *
	 * @param extreme_coord the extrem_values of the graph
	 * @param scale the scale value to use to rescale the graph
	 * @param g the graph in which we are going to move the nodes
	 */
	public void move_graph(Hashtable <String, Float>extreme_coord, double scale, Graph g) {
		g.nodes().forEach((n) -> {
			double[] coords = GraphPosLengthUtils.nodePosition(n);
			coords[0] = (coords[0] - extreme_coord.get("x_min")) * scale;
			coords[1] = (coords[1] - extreme_coord.get("y_min")) * scale;
			n.setAttribute("xy", coords[0], coords[1]);
		});
	}

	public static void main(String... args) {
		String path = args[0];
		int nb_noeuds = Integer.parseInt(args[1]);
		System.out.println("path : " + path);
		if (path.endsWith("dgs")) {
			Graph g = new DefaultGraph("graph_test");
			CorrelationDimension correlationDimension = new CorrelationDimension();
			try {
				correlationDimension.add_node_to_graph_from_dgs_file(g, path, nb_noeuds);
			} catch (IOException e) {
				e.printStackTrace();
				return;
			}
			System.out.println("nombre de noeud : " + g.getNodeCount());
			Hashtable<String, Float> extreme_coord = correlationDimension.get_min_max_coord(g);
			System.out.println("xmin : " + extreme_coord.get("x_min") + " x_max : " + extreme_coord.get("x_max")
					+ "  y_min : " + extreme_coord.get("y_min") + "  y_max : " + extreme_coord.get("y_max"));
			extreme_coord.put("x_max", extreme_coord.get("x_max") - extreme_coord.get("x_min"));
			extreme_coord.put("y_max", extreme_coord.get("y_max") - extreme_coord.get("y_min"));
			System.out.println("déplacement vers origine xmin : " + extreme_coord.get("x_min") + " x_max : " +
					extreme_coord.get("x_max") + "  y_min : " + extreme_coord.get("y_min") + "  y_max : " +
					extreme_coord.get("y_max"));

			int[] size_space = {1000, 1000};
			double maxSize = Arrays.stream(size_space).min().getAsInt();
			double delta = 0.001;
			double scale = maxSize / Math.max(extreme_coord.get("x_max"), extreme_coord.get("y_max")) * (1 - delta);
			correlationDimension.move_graph(extreme_coord, scale, g);
		}
	}
}
