package exp;

import index.IntervalBounds;

import java.io.Externalizable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

import generator.GraphGenerator;
import graph.Graph;
import misc.Common;
import misc.ExtToolsDriver;
import misc.IO;
import alg.BUp;

public class HeuristicsComparison {
	
	// Runs TOP-DOWN, GW, LM, LM+SM, LM+SM+TM
	// compares them in terms of time and quality
	public static void compareInstancesFromLiterature() {
		Graph g;
		
		// 
		String path = "/home/petko/data/temporal/PCST_ILP_Instances/pcstp/";
		String files = "K100.dat K100.1.dat K100.2.dat K100.3.dat K100.4.dat K100.5.dat " +
				       "K100.6.dat K100.7.dat K100.8.dat K100.9.dat K100.10.dat " + 
					   "K200.dat " +
					   "K400.dat K400.1.dat K400.2.dat K400.3.dat K400.4.dat K400.5.dat " + 
					   "K400.6.dat K400.7.dat K400.8.dat K400.9.dat K400.10.dat " + 
					   "P100.dat P100.1.dat P100.2.dat P100.3.dat P100.4.dat " +
					   "P200.dat " + 
					   "P400.dat P400.1.dat  P400.2.dat  P400.3.dat P400.4.dat";
//		files = "K400.5.dat  K400.7.dat P100.2.dat P100.dat P400.1.dat " +
//		        "P400.2.dat P400.3.dat P400.dat";
//		files = "P100.4.dat P400.3.dat";
		
		ArrayList<String> quality = new ArrayList<String>();
		ArrayList<String> time = new ArrayList<String>();
		
		for (String fn: files.split("[ ]+")) {
			try {
				g = IO.parseILPPCST(path + fn.trim());
				double opt = g.opt_nw;
				if(!g.isConnected()) {
					g = g.getLargestConnectedComponent();
				}
				String QualitSepTime = evaluateHeuristicsOnGraph(g, opt, fn.replace(".dat", ""));
				quality.add(QualitSepTime.split(Common.SEP)[0]);
				time.add(QualitSepTime.split(Common.SEP)[1]);
				System.out.print("time:" + QualitSepTime.split(Common.SEP)[1] + "\n");
				System.out.print("qual:" + QualitSepTime.split(Common.SEP)[0] + "\n"); 
			} catch (IOException e) {
				System.err.print("Error opening :" + fn + "\n");
				e.printStackTrace();
			}
		}
		ExtToolsDriver.plotHeuristics(quality,time,"ilpexamples");
	}
	
	// Time and quality for varying graph sizes
	// ER and SF, Twitter and Traffic
	// TODO: Decide on Generation
	// TODO: Get snow-balling twitter networks
	public static void compareSyntheticGraphSize() {
		int trials = 3;
		int ewmax = 1000;
		int pnz = 12;
		int nheuristics = -1;
		double[] qres = new double[10];
		double[] tres = new double[10];
		ArrayList<String> quality = new ArrayList<String>();
		ArrayList<String> time = new ArrayList<String>();
		for (int n=200; n <= 1000; n = n + 100) {
			Arrays.fill(qres, 0.0); 
			Arrays.fill(tres, 0.0);
			for (int i = 0; i < trials; i++) {
				Graph g = GraphGenerator.generateRandom(n, (int)n*4);
				GraphGenerator.generateRandomWeighted(g, ewmax, pnz);
				String QualitSepTime = evaluateHeuristicsOnGraph(g, 1.0, "");
				nheuristics = QualitSepTime.split(Common.SEP)[0].split(" ").length;
				double gw_quality = Double.parseDouble(QualitSepTime.split(Common.SEP)[0].split(" ")[2]);
				for (int j = 1; j < QualitSepTime.split(Common.SEP)[0].split(" ").length; j++) {
					qres[j] += Double.parseDouble(QualitSepTime.split(Common.SEP)[0].split(" ")[j])
								/(gw_quality*trials*1.0);
				}
				for (int j = 1; j < QualitSepTime.split(Common.SEP)[1].split(" ").length; j++) {
					tres[j] += Double.parseDouble(QualitSepTime.split(Common.SEP)[1].split(" ")[j])
								/(1.0*trials);
				}
			}
			String qs = "" + n; for (int i=1;i<nheuristics;i++) qs += " " + qres[i];
			String ts = "" + n; for (int i=1;i<nheuristics;i++) ts += " " + tres[i];
			
			quality.add(qs);
			time.add(ts);
			System.out.print("time:" + ts + "\n");
			System.out.print("qual:" + qs + "\n"); 
		}
		ExtToolsDriver.plotHeuristics(quality,time,"gsize");
	}
	
	public static String evaluateHeuristicsOnGraph(Graph g, double opt, String prefix) {
		String qs = prefix, ts = prefix;
		double val;
		long apsp_t;
		BUp b;
		long start, end;
		
		String gsize = g.getn() + "x" + g.getm(); 
		start = System.currentTimeMillis();
		g.getMetic();
		end = System.currentTimeMillis();
		apsp_t = end-start;
		//System.out.print("APSP:[" + apsp_t + "ms]\n");
		//System.out.print("TOTAL P: " + g.getP() +  "\tN: " + g.getN() + "\n");
		//System.out.print("OPT    : " + g.opt_nw + "\n");
		
		// TopDown LB MST 
		start = System.currentTimeMillis();
		val = IntervalBounds.getMinSTLB(g);
		end = System.currentTimeMillis();
		//System.out.print("TopDown: "  + val + "[" + ((end-start)) + "ms]\n");
		qs += " " + val/opt;
		ts += " " + (end-start);
		
		// GW
		b = new BUp(g);
		start = System.currentTimeMillis();
		b.computeOptimalGW(); 
		end = System.currentTimeMillis();
		val = b.getBestClusterGraph().getScore();
		//System.out.print("GW: "  + val + "[" + ((end-start)) + "ms]\n");
		qs += " " + val/opt;
		ts += " " + (end-start);
		
		// LM 
		b = new BUp(g);
		b.useTM = false;b.useSM = false;b.resetClusters = false;
		start = System.currentTimeMillis();
		b.computeOptimalLMSMTM();
		end = System.currentTimeMillis();
		val = b.getBestClusterGraph().getScore();
		//System.out.print("LM: "  + val + "[" + ((end-start)) + "ms]\n");
		qs += " " + val/opt;
		ts += " " + (end-start + apsp_t);
		
		// LM + SM
		b = new BUp(g);
		b.useTM = false;b.resetClusters = false;
		start = System.currentTimeMillis();
		b.computeOptimalLMSMTM();
		end = System.currentTimeMillis();
		val = b.getBestClusterGraph().getScore();
		//System.out.print("LM+SM: "  + val + "[" + ((end-start)) + "ms]\n");
		qs += " " + val/opt;
		ts += " " + (end-start + apsp_t);
		
		// LM + SM + TM
		b = new BUp(g);b.resetClusters = false;
		start = System.currentTimeMillis();
		b.computeOptimalLMSMTM();
		end = System.currentTimeMillis();
		val = b.getBestClusterGraph().getScore();
		//System.out.print("LM+SM+TM: "  + val + "[" + ((end-start)) + "ms]\n");
		qs += " " + val/opt;
		ts += " " + (end-start + apsp_t) ;
		
//		// SPT
//		b = new BUp(g);
//		start = System.currentTimeMillis();
//		b.getOptimalSPTMerging();
//		end = System.currentTimeMillis();
//		val = b.getBestClusterGraph().getScore();
//		System.out.print("SPT: "  + val + "[" + ((end-start)) + "ms]\n");
//		qs += " " + val;
//		ts += " " + (end-start + apsp_t);
		
		return qs + Common.SEP + ts;
	}
	
	
	
	// Time and quality for varying edge correlation
	// same as above for increasing correlation of adjacent
	// edges
	public static void compareSyntheticEdgeCorr() {
		
	}
	
	
	public static void main(String[] args) {
		//compareInstancesFromLiterature();
		compareSyntheticGraphSize();
	}
	
}
