package weka.clusterers.forMetisMQI.util;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Paint;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.swing.JFrame;

import org.apache.commons.collections15.Transformer;

import weka.clusterers.forMetisMQI.Random;
import weka.clusterers.forMetisMQI.graph.Edge;
import weka.clusterers.forMetisMQI.graph.Node;
import weka.clusterers.forMetisMQI.graph.UndirectedGraph;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.BasicVisualizationServer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

public class Util {
	public static void viewClusters(Graph<Node, Edge> g, Set<Set<Node>> clusters) {
		Layout<Node, Edge> layout = new FRLayout<Node, Edge>(g);
		layout.setSize(new Dimension(800, 600)); // sets the initial size of the space
		// The BasicVisualizationServer<V,E> is parameterized by the edge types
		BasicVisualizationServer<Node, Edge> vv = new BasicVisualizationServer<Node, Edge>(
				layout);

		class VertexPaintTransformer implements Transformer<Node, Paint> {
			Set<Set<Node>> clusters = null;
			Map<Set<Node>, Color> clustersColor = null;

			public Set<Node> getCluster(Node node) {
				Iterator<Set<Node>> clusterIterator = clusters.iterator();
				while (clusterIterator.hasNext()) {
					Set<Node> cluster = clusterIterator.next();
					if (cluster.contains(node))
						return cluster;
				}
				return null;
			}

			public VertexPaintTransformer(Set<Set<Node>> clusters) {
				this.clusters = clusters;
				clustersColor = new HashMap<Set<Node>, Color>(clusters.size());
				Iterator<Set<Node>> clusterIterator = clusters.iterator();
				while (clusterIterator.hasNext()) {
					Set<Node> cluster = clusterIterator.next();
					clustersColor.put(cluster, new Color(Random.instance()
							.nextInt(256), Random.instance().nextInt(256),
							Random.instance().nextInt(256)));
				}
			}

			public Paint transform(Node i) {
				Set<Node> cluster = getCluster(i);
				if (cluster == null)
					return Color.RED;
				else
					return clustersColor.get(getCluster(i));
			}
		}

		Transformer<Node, Paint> vertexPaint = new VertexPaintTransformer(
				clusters);
		vv.setPreferredSize(new Dimension(800, 600)); // Sets the viewing area
														// size
		vv.getRenderContext().setVertexLabelTransformer(
				new ToStringLabeller<Node>());
		vv.getRenderContext().setEdgeLabelTransformer(
				new ToStringLabeller<Edge>());
		vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
		JFrame frame = new JFrame("Graph View");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(vv);
		frame.pack();
		frame.setVisible(true);
	}
	
	public static void viewGraph(Graph<Node, Edge> g){
		Layout<Node, Edge> layout = new FRLayout<Node, Edge>(g);
		layout.setSize(new Dimension(800,600)); // sets the initial size of the space
		// The BasicVisualizationServer<V,E> is parameterized by the edge types
		BasicVisualizationServer<Node,Edge> vv =
		new BasicVisualizationServer<Node,Edge>(layout);
		vv.setPreferredSize(new Dimension(800,600)); //Sets the viewing area size
		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>());
		vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<Edge>());
		JFrame frame = new JFrame("Simple Graph View");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(vv);
		frame.pack();
		frame.setVisible(true);
	}
	
	public static void viewFlowGraph(Graph<Node, Edge> g, Map<Edge, Number> edgeFlowMap){
		class EdgeTransformer implements Transformer<Edge,String> {
			Map<Edge,Number> edgeFlowMap = null;
			public String transform(Edge edge){
				return edgeFlowMap.get(edge) + "/" + edge.getCapacity();
			}
			public EdgeTransformer(Map<Edge,Number> edgeFlowMap) {
				this.edgeFlowMap = edgeFlowMap;
			}
		}
		Layout<Node, Edge> layout = new FRLayout<Node, Edge>(g);
		layout.setSize(new Dimension(800,600)); // sets the initial size of the space
		// The BasicVisualizationServer<V,E> is parameterized by the edge types
		BasicVisualizationServer<Node,Edge> vv =
		new BasicVisualizationServer<Node,Edge>(layout);
		vv.setPreferredSize(new Dimension(800,600)); //Sets the viewing area size
		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>());
		vv.getRenderContext().setEdgeLabelTransformer(new EdgeTransformer(edgeFlowMap));
		JFrame frame = new JFrame("Simple Graph View");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(vv);
		frame.pack();
		frame.setVisible(true);
	}
	
	/**
	 * Generates a small graph with 100 nodes and two big components.
	 * For testing purpose.
	 * @return the generated graph
	 */
	public UndirectedGraph generateGraph(){
		UndirectedGraph g = new UndirectedGraph();
		for (int i = 0; i < 50; i++) {
			g.addVertex(new Node(Integer.toString(i)));
		}
		for (int j = 0; j < 120; j++) {
			g.addEdge(new Edge(Integer.toString(j), 1, 1), new Node(Integer
					.toString(Random.instance().nextInt(50))), new Node(Integer
					.toString(Random.instance().nextInt(50))));
		}
		for (int i = 50; i < 100; i++) {
			g.addVertex(new Node(Integer.toString(i)));
		}
		for (int j = 120; j < 240; j++) {
			g.addEdge(new Edge(Integer.toString(j), 1, 1), new Node(Integer
					.toString(50 + Random.instance().nextInt(50))), new Node(
					Integer.toString(50 + Random.instance().nextInt(50))));
		}
		for (int j = 240; j < 250; j++) {
			g.addEdge(new Edge(Integer.toString(j), 1, 1), new Node(Integer
					.toString(50 + Random.instance().nextInt(50))), new Node(
					Integer.toString(Random.instance().nextInt(50))));
		}
		return g;
	}
}
