package graph;

import exp.BoundUtility;
import exp.RunMesasurements;
import generator.DynamicModel;
import generator.GraphGenerator;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;

public class WeightedTimeGraph extends Graph implements ITimeGraph{
	public final float[][] wsl;
	
	public WeightedTimeGraph(Graph g, float[][] sl) {
		super(g);
		wsl = sl;
	}
	
	public WeightedTimeGraph(TimeGraph tg) {
		super(tg);
		wsl = new float[tg.gett()][tg.getm()];
		for (int t = 0 ; t < tg.gett(); t++ ) {
			for (int j = 0; j < tg.getm(); j++) {
				if (tg.slices[t].get(j)) wsl[t][j] = 1;
				else wsl[t][j] = -1;
			}
		}
	}

	public int gett() {
		return wsl.length;
	}

	public void aggregateByTime(int s, int e, double[] weights) {
		assert(s<=e && s >= 0 && e < gett()):"Incorrect interval" + s + " " + e;
		Arrays.fill(weights, 0.0);
		for (int i = s; i <=e; i++) {
			for(int j = 0; j < getm(); j++) {
				weights[j] += wsl[i][j];
			}
		}
	}

	public void aggregateByTime(int s, int e) {
		assert(s<=e && s >= 0 && e < gett()):"Incorrect interval" + s + " " + e;
		//Graph g = getStructure();
		Arrays.fill(we, 0.0);
		for (int i = s; i <=e; i++) {
			for(int j = 0; j < getm(); j++) {
				we[j] += wsl[i][j];
			}
		}
	}
	
	public Graph getGraph() {
		return this;
	}
	
	public static void testWeightedEquivalenceWithDiscrete() throws IOException{
		Graph g = GraphGenerator.generateRandom(500, 1000);
		DynamicModel dm = new DynamicModel();
		dm.PNeighbor = 0.3;
		dm.PNextGivenCurrent = 0.9;
		dm.POne = 0.1;
		TimeGraph tg = generator.GraphGenerator.generateTimeRWSampling(200, dm, g);
		
		Pattern pt1 = BoundUtility.runCoarse(tg, 0, 199, 200, 0.4, 10, new RunMesasurements(),false);
		
		WeightedTimeGraph wtg = new WeightedTimeGraph(tg);
		
		Pattern pt2 = BoundUtility.runCoarse(wtg, 0, 199, 200, 0.4, 10, new RunMesasurements(),false);
		
		assert (pt1.equals(pt2));
	}
	
	public long getNNegEdgeCount() {
		long cnt = 0;
		for (int t = 0; t < wsl.length; t++) {
			for (int i = 0; i < wsl[t].length; i++) {
				if (wsl[t][i] >= 0.0) cnt++;
			}
		}
		return cnt;
	}
	
	public double getMaxEdgeScore(int t, int n) {
		float max = Float.NEGATIVE_INFINITY;
		for (int i = ind[n]; i < ind[n+1]; i++) {
			max = Math.max(max, wsl[t][i]);
		}
		return max;
	}

	public WeightedTimeGraph getBFSSubgraph(int seed, int size, int s , int e) {
		Graph gg = super.getBFSSubgraph(seed, size);
		HashMap<Integer,Integer> edge_map = new HashMap<Integer, Integer>();
		gg.buildN2I();
		for (int i = 0; i < gg.getn(); i++) {
			for (int j = gg.ind[i]; j < gg.ind[i+1]; j++) {
				int v1 = getNodeIndex(gg.names[i]);
				int v2 = getNodeIndex(gg.names[gg.endv[j]]);
				int ed = getEdgeIndex(v1,v2);
				if (ed == -1) {
					System.err.print("negative");
				}
				edge_map.put(j, ed);
			}
		}
		float[][] nslices = new float[e-s+1][gg.getm()];
		for (int t = s; t <= e; t++) {
			for (int i = 0; i < gg.getm(); i++) {
				nslices[t-s][i] = wsl[t][edge_map.get(i)];
			}
		}
		
		WeightedTimeGraph wtg = new WeightedTimeGraph(gg, nslices);
		
		return wtg;
	}

	@Override
	public float[][] getTimeseries() {
		return wsl;
	}
	
	@Override
	public String toString() {
		String res = "Nodes:\n";
		for (int i=0;i<names.length;i++) {
			res += names[i] + "(" + wn[i] + "),";
		}
		res += "\nEdges:\n";
		if (getn()==1) return res;
		for(int i=0;i<ind.length-1;i++) {
			for (int j=ind[i];j<ind[i+1];j++) {
				res += j+ ":" + names[i] + "\t" + names[endv[j]] + "\t";
				for(int t = 0; t < gett(); t++) {
					if (wsl[t][j] >= 0) res += "+";
					else res += "-";
				}
				res += "\n";
			}
		}
		return res;
	}
	
	public static void main(String[] args) {
		try {
			testWeightedEquivalenceWithDiscrete();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}