/** 
 * @author gswong
 * Compilation: javac ProbModelDriver.java ProbGraph.java
 */
 
import java.io.*;
import java.util.*;

public class ProbModelDriver {

	/**
	 * The first argument is the model filename
	 * The second argument should be the value of p, as an ASCII string
	 * The third argument should be the NodeID of the initial product user
	 */
	public static void main(String[] args) {
		if(args.length < 3)
		{
			System.out.println("Usage: java "
                + "ProbModelDriver netDefFilename pValue initialNode (-test)");
			return;
		}
		
		String networkFilename = args[0];
		double successProb = Double.parseDouble(args[1]);
		int    startNode = Integer.parseInt(args[2]);
        
        // Read in graph data from file
        File f = new File(networkFilename);
        Scanner sc;
        try {
            sc = new Scanner(f);
        } catch(FileNotFoundException fnfe) {
            System.out.println(networkFilename + " not found.  "
                + "Did you type it correctly?  "
                + "Is it in the right directory?");
            return;
            // should quit program!
            // what can you do if you have no file?
        }
        
        // Establish graph storage variables
        int     nodes = sc.nextInt();
        int[][] adj = new int[nodes][nodes];
        int[][] dist = new int[nodes][nodes];
		
        // Fill in adjacency matrix from file
        while(sc.hasNextInt()) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            
            adj[a][b]++;    adj[b][a]++;
            dist[a][b]++;   dist[b][a]++;
        }
        sc.close();
        
        if(args.length == 4 && args[3].toLowerCase().equals("-test"))
		{
            // use Floyd-Warshall to find shortest distance between all pairs
            ProbGraph.initializeDistance(dist);
            ProbGraph.findDistance(dist);
            
            // Print all nodes who are using the product
            boolean debug = false;
            int[] adopted =
                ProbGraph.runSimulation(adj, dist, successProb, startNode,
                debug);
            
            output(adopted);    // outputs indices that have a 1
            
			return;
		}
        
        int trials = 20000;
        int reached = 0;
        int distances = 0;
        
        ProbGraph.initializeDistance(dist);
        ProbGraph.findDistance(dist);
        
        
        if(args.length == 4 && args[3].toLowerCase().equals("-debug")) {
            System.out.println("Adjacency matrix:");
            ProbGraph.printGraph(adj);
            System.out.println("Distance matrix:");
            ProbGraph.printGraph(dist);
            return;
        }
        
        int[] degree = new int[nodes];
        ProbGraph.findDegree(degree, adj);
        
        for(int i = 0; i < trials; i++) {
            int[] adopted =
                ProbGraph.runSimulation(adj, dist, successProb, startNode, false);
            int saturation = count(adopted);
            reached += count(adopted);
            
            int thisDistance = maxDistance(dist[startNode], adopted);
            distances += thisDistance;
        }
        double average = (double)reached / trials;
        double avgDist = (double)distances / trials;
        
        System.out.println(average);
	}
    
    private static int maxDistance(int[] dist, int[] adopted) {
        int max = 0;
        for(int i = 0; i < dist.length; i++) {
            if(adopted[i] == 1 && dist[i] > max)
                max = dist[i];
        }
        return max;
    }
    
    private static void output(int[] adopted) {
        for(int i = 0; i < adopted.length; i++)
            if(adopted[i] == 1)
                System.out.print(i + " ");
        System.out.println();
    }
    
    private static void printOut(int[] degree) {
        System.out.println("Degrees:");
        for(int i = 0; i < degree.length; i++)
            System.out.println(i + "\t" + degree[i]);
    }
    
    private static int count(int[] adopted) {
        int count = 0;
        for(int i = 0; i < adopted.length; i++)
            if(adopted[i] == 1)
                count++;
        return count;
    }
}

