package rank;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import it.unimi.dsi.logging.ProgressLogger;
import it.unimi.dsi.webgraph.labelling.ArcLabelledImmutableGraph;
import it.unimi.dsi.webgraph.labelling.ArcLabelledNodeIterator;
import it.unimi.dsi.webgraph.labelling.BitStreamArcLabelledImmutableGraph;
import it.unimi.dsi.webgraph.labelling.Label;
import it.unimi.dsi.webgraph.labelling.ArcLabelledNodeIterator.LabelledArcIterator;

public class WeightedImmutableGraph extends ArcLabelledImmutableGraph {

	private static Logger LOGGER = LoggerFactory.getLogger(WeightedImmutableGraph.class.getName());
	public static long LOGINT = 5;
	
	private BitStreamArcLabelledImmutableGraph g;
	private double vertexWeight[];
	private double vertexSqNorm[];
	private double maxWeight;
	private int offset[];
	
	public WeightedImmutableGraph(BitStreamArcLabelledImmutableGraph g) {
		this.g = g;
		this.maxWeight = - Double.MAX_VALUE; 
		this.computeVertexWeight();
	}
	
	private void computeVertexWeight() {
		vertexWeight = new double[this.numNodes()];
		vertexSqNorm = new double[this.numNodes()];
		offset = new int[this.numNodes()];
		ProgressLogger pl = new ProgressLogger(LOGGER, LOGINT, TimeUnit.SECONDS);
		pl.start("Computing weights for vertices....");
		pl.expectedUpdates = g.numNodes();
		pl.itemsName = "vertices";
		
		ArcLabelledNodeIterator nIter = this.nodeIterator();
		while (nIter.hasNext()) {
			int u = nIter.next();
			
			if (u > 0)
				offset[u] = offset[u-1] + g.outdegree(u - 1);
			
			LabelledArcIterator eIter = nIter.successors();
			while (eIter.nextInt() != -1) {
				double w = Float.intBitsToFloat(eIter.label().getInt());
				vertexWeight[u] += w;
				vertexSqNorm[u] += w*w;
				
				maxWeight = Math.max(maxWeight, w);
			}
			
			pl.update();
		}
		pl.done();	
	}

	public double getMaxWeight() {
		return maxWeight;
	}
	
	@Override
	public ArcLabelledImmutableGraph copy() {
		return new WeightedImmutableGraph(g.copy());
	}

	@Override
	public Label prototype() {
		return g.prototype();
	}

	@Override
	public LabelledArcIterator successors(int arg0) {
		return g.successors(arg0);
	}

	@Override
	public int numNodes() {
		return g.numNodes();
	}
	
	@Override
	public long numArcs() {
		return g.numArcs();
	}

	public int offset(int arg0) {
		return offset[arg0];
	}
	
	@Override
	public int outdegree(int arg0) {
		return g.outdegree(arg0);
	}

	public double outweight(int arg0) {
		return vertexWeight[arg0];
	}
	
	public double sqNorm(int arg0) {
		return vertexSqNorm[arg0];
	}
	
	@Override
	public boolean randomAccess() {
		return false;
	}
}
