/** 
 * @author gswong
 * Compilation: javac DetermModelDriver.java DetGraph.java
 */

import java.io.*;
import java.util.*;

public class DetermModelDriver {

	/**
	 * The first argument is the model filename
	 * 
	 * All other arguments are integers which are the NodeIDs of states 
	 * initially active in the simulation.
	 * 
	 * The last argument is potentially a flag indicating that a test run
	 * will be performed.
	 */
	public static void main(String[] args) {
		if(args.length < 2)
		{
			System.out.println("Usage: DetermModelDriver Active1 (Active2) ... (ActiveN) (-test)");
			return;
		}
		
		String networkFilename = args[0];
		ArrayList initialActiveNodes = new ArrayList();
        
        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?
        }
        
        int nodes = sc.nextInt();
        double[] thresh = new double[nodes];
        
        // Build a list of each node's threshold
        for(int i = 0; i < nodes; i++) {
            int nodeID = sc.nextInt();
            double threshold = sc.nextDouble();
            thresh[nodeID] = threshold;
        }
        
        // Fill bias table
        double[][] bias = new double[nodes][nodes];
        while(sc.hasNextInt()) {
            int m = sc.nextInt();
            int n = sc.nextInt();
            bias[m][n] = sc.nextDouble();
        }
        
        int[] adopted = new int[nodes];
        
        sc.close();
        
        for(int i = 1; i < args.length; i++)
		{
			if(args[i].toLowerCase().equals("-test"))
			{
                DetGraph.runSim(bias, thresh, adopted);
                output(adopted);
				return;
			}
            adopted[Integer.parseInt(args[i])] = 1;
		}
        
		int optimalStart = findOne(bias, thresh, adopted);
        System.out.println("Optimal start node: " + optimalStart);
        
        int[] pair = findTwo(bias, thresh, adopted);
        System.out.println("Optimal start set: " + pair[0] + ", " +
            pair[1]);
        
        int[] set = findThree(bias, thresh, adopted);
        System.out.println("Optimal start set: " + set[0] + ", " +
            set[1] + ", " + set[2]);
	}

    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 int count(int[] array) {
        int ret = 0;
        for(int i = 0; i < array.length; i++)
            ret += array[i];
        return ret;
    }
    
    private static void setOne(int[] adopted, int start) {
        for(int i = 0; i < adopted.length; i++)
            adopted[i] = 0;
        adopted[start] = 1;
    }
    
    private static void setThree(int[] adopted, int one, int two, int three) {
        for(int i = 0; i < adopted.length; i++)
            adopted[i] = 0;
        adopted[one] = 1;
        adopted[two] = 1;
        adopted[three] = 1;
    }
    
    private static void setTwo(int[] adopted, int one, int two) {
        for(int i = 0; i < adopted.length; i++)
            adopted[i] = 0;
        adopted[one] = 1;
        adopted[two] = 1;
    }
    
    private static int findOne(double[][] bias, double[] thresh,
        int[] adopted) {
        int max = 0;
        int maxIndex = 0;
        
        for(int i = 0; i < bias.length; i++) {
            setOne(adopted, i);
            DetGraph.runSim(bias, thresh, adopted);
            if(count(adopted) > max) {
                max = count(adopted);
                maxIndex = i;
            }
        }
        
        return maxIndex;
    }
    
    private static int[] findTwo(double[][] bias, double[] thresh,
        int[] adopted) {
        int max = 0;
        int[] indices = new int[2];
        int nodes = bias.length;
        
        for(int i = 0; i < nodes; i++) {
            for(int j = 0; j < nodes; j++) {
                setTwo(adopted, i, j);
                DetGraph.runSim(bias, thresh, adopted);
                if(count(adopted) > max) {
                    max = count(adopted);
                    indices[0] = i;
                    indices[1] = j;
                }
            }
        }
        
        return indices;
    }
    
    private static int[] findThree(double[][] bias, double[] thresh,
        int[] adopted) {
        int max = 0;
        int[] indices = new int[3];
        int nodes = bias.length;
        
        for(int i = 0; i < nodes; i++) {
            for(int j = 0; j < nodes; j++) {
                for(int k = 0; k < nodes; k++) {
                    setThree(adopted, i, j, k);
                    DetGraph.runSim(bias, thresh, adopted);
                    if(count(adopted) > max) {
                        max = count(adopted);
                        indices[0] = i;
                        indices[1] = j;
                        indices[2] = k;
                    }
                }
            }
        }
        
        return indices;
    }
}

