package graphtea.extensions.reports.spectralreports.maxflowmincut;

import java.util.List;
import graphtea.graph.graph.Edge;
import graphtea.graph.graph.GraphModel;
import graphtea.graph.graph.Vertex;

public class GusfieldGomoryHuTree {

	private MinCut MC;
	public GraphModel mainGraph, GHTree;
	private int[] flow, neighbors;
	public GusfieldGomoryHuTree(GraphModel g) throws Exception
	{
		if (g.isDirected())
			throw new Exception("Gomory-Hu for directed Graphs may not exist");

		this.mainGraph = g;
		GHTree = new GraphModel(false);
		GHTree.setLabel("Gomory-Hu Tree");
		GHTree.setDrawEdgeLabels(true);
		MC = new MinCut(g, null, null, false);
	}
	public GraphModel perform()
	{
		//HashMap<Vertex, LinkedList<Vertex>> neighbors = new HashMap<Vertex, LinkedList<Vertex>>();
		int size = mainGraph.numOfVertices();
		
		//first node creation
		Vertex s1 = new Vertex();
		s1.setLabel(mainGraph.getVertex(0).getLabel());
		s1.setLocation(mainGraph.getVertex(0).getLocation());
		GHTree.addVertex(s1);
		
		
		MC  = new MinCut(mainGraph, null, null, true);
		neighbors = new int[size];
		flow = new int[size];
		int t, temp;
		

		

		for(int s=1; s<size; s++)
		{			
			
			t = neighbors[s];
			MC.source = mainGraph.getVertex(s);
			MC.sink = mainGraph.getVertex(t);
			
			flow[s] = MC.perform();
			for (int i=1; i < size ; i++)
			{
				if (i!=s && MC.cut.contains(i) && neighbors[i]==t)
					neighbors[i]=s;
			}
			if(MC.cut.contains(neighbors[t]))
			{
				neighbors[s] = neighbors[t];
				neighbors[t]=s;
				temp = flow[t];
				flow[t] = flow[s];
				flow[s] = temp;
				
			}
		}
		
		showResult();
		return GHTree;


	}

	public void showResult()
	{
		GHTree.clear();
		int size = mainGraph.numOfVertices();
		Vertex v, vg;
		for(int s=0; s<size; s++)
		{
			// node creation
			vg = mainGraph.getVertex(s);
			v = new Vertex();
			v.setLabel(vg.getLabel());
			v.setLocation(vg.getLocation());
			GHTree.addVertex(v);
		}
		Edge e;
		for(int i=0; i<size; i++)
		{
			e = new Edge(GHTree.getVertex(i), GHTree.getVertex(neighbors[i]));
			e.setWeight(flow[i]);
			e.setShowWeight(true);
			GHTree.addEdge(e);
		}
		
	}
}



/*
 * 
 * Vertex s,t,i;
		Edge st, it, res;
		Iterator<Edge> itIter;
		Collection<Integer> Cut;
		boolean isSource;
		String label;
		for(int sn=1; sn<size; sn++)
		{
			s = GHTree.getVertex(sn);
			st = GHTree.lightEdgeIterator(s).next();
			t = (st.source==s? st.target : st.source);

			MC.source = mainGraph.getVertex(sn);
			MC.sink = mainGraph.getVertex(t.getId());

			st.setWeight(MC.perform());
			Cut = MC.cut;

			itIter = GHTree.lightEdgeIterator(t);
			while(itIter.hasNext())
			{
				it = itIter.next();

				if(it.source==t)
				{
					i=it.target;
					isSource = false;
				}
				else
				{
					i = it.source;
					isSource = true;
				}
				//TODO: modify this for efficiency 
				if(Cut.contains(i))
				{
					{
						if(isSource)
						{
							label = GHTree.getEdge(i, t).getLabel();
							GHTree.removeEdge(GHTree.getEdge(i, t));
						}
						else
						{
							label = GHTree.getEdge(t, i).getLabel();
							GHTree.removeEdge(GHTree.getEdge(t, i));
						}
						res = new Edge(i, s);
						res.setLabel(label);
						GHTree.addEdge(res);
					}
				}
			}
		}

 */
