/** 
 * @author YourAndrewIDHere
 * You should fill in the stub for this code file.  The
 * arguments will be given to you 
 */

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.
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		if(args.length < 2)
		{
			System.out.println("Usage: DetermModelDriver Active1 (Active2) ... (ActiveN) (-test)");
			return;
		}
		
		String networkFilename = args[0];
		ArrayList<Integer> initialActiveNodes = new ArrayList<Integer>();
		
		// Open and read from file
		FileReader input = new FileReader(networkFilename);
		BufferedReader bufRead = new BufferedReader(input);
		String line = bufRead.readLine();

		int nNodes = Integer.parseInt(line);
		DetermNode[] nodes = new DetermNode[nNodes];
		for (int i = 0; i < nNodes; i++) {
			line = bufRead.readLine();
			String[] tokens = line.split(" ");
			int name = Integer.parseInt(tokens[0]);
			
			nodes[name] = new DetermNode(name);
			nodes[name].threshold = Double.parseDouble(tokens[1]);
		}
		
		while ((line = bufRead.readLine()) != null) {
			String[] tokens = line.split(" ");
			if (tokens.length < 3)
				break;
			int u = Integer.parseInt(tokens[0]);
			int v = Integer.parseInt(tokens[1]);
			double influence = Double.parseDouble(tokens[2]); 			
			nodes[v].addNeighbor(u, influence);
		}
		
		for(int i = 1; i < args.length; i++)
		{
			if(args[i].toLowerCase().equals("-test"))
			{
				// Put your code to simulate the network
				// here.  You should print out at the end
				// of the simulation all of the nodes which
				// are using the product.  
				ArrayList<Integer> queue = new ArrayList<Integer>();
				
				// Initialize queue
				for (int u: initialActiveNodes) { 					
					queue.add(u);
					nodes[u].isChanged = true;
				}
				while (queue.size() > 0) {
					int u = queue.remove(queue.size() - 1);
					for (Influence inf: nodes[u].neighbors) {
						if (nodes[inf.target].isChanged)
							continue;
						nodes[inf.target].influenced += inf.influence;
						if (nodes[inf.target].influenced >= nodes[inf.target].threshold) {
							queue.add(inf.target);
							nodes[inf.target].isChanged = true;
						}
					}
				}
				
				for (int j = 0; j < nNodes; j++)
					if (nodes[j].isChanged)
						System.out.print(j + " ");
				
				return; // make sure that this return is called!
			}
			
			initialActiveNodes.add(Integer.parseInt(args[i]));
		}

		// You are free to do whatever you want here...
		// Bren suggests that you create some helper classes
		// to do the simulation and then run your simulations
		// here.

		int max = 0;
		int maxi = 0;
		int maxj = 0;
		int maxk = 0;
		for (int i = 0; i < nNodes; i++) {
			ArrayList<Integer> queue = new ArrayList<Integer>();
			
			for (int j = 0; j < nNodes; j++) {
				nodes[j].influenced = 0.0;
				nodes[j].isChanged = false;
			}
			// Initialize queue
			queue.add(i);
			nodes[i].isChanged = true;
	
			while (queue.size() > 0) {
				int u = queue.remove(queue.size() - 1);
				for (Influence inf: nodes[u].neighbors) {
					if (nodes[inf.target].isChanged)
						continue;
					nodes[inf.target].influenced += inf.influence;
					if (nodes[inf.target].influenced >= nodes[inf.target].threshold) {
						queue.add(inf.target);
						nodes[inf.target].isChanged = true;
					}
				}
			}
			int count = 0;
			for (int j = 0; j < nNodes; j++)
				if (nodes[j].isChanged)
					count++;
			if (count > max) {
				max = count;
				maxi = i;
			}
		}
		System.out.println("Maxi: " + maxi + ", with max: " + max);
		
		max = 0;
		maxi = 0;
		maxj = 0;
		maxk = 0;
		for (int i = 0; i < nNodes; i++) {
			for (int k = i + 1; k < nNodes; k++) {
				ArrayList<Integer> queue = new ArrayList<Integer>();
				
				for (int j = 0; j < nNodes; j++) {
					nodes[j].influenced = 0.0;
					nodes[j].isChanged = false;
				}
				// Initialize queue
				queue.add(i);
				nodes[i].isChanged = true;
				queue.add(k);
				nodes[k].isChanged = true;
		
				while (queue.size() > 0) {
					int u = queue.remove(queue.size() - 1);
					for (Influence inf: nodes[u].neighbors) {
						if (nodes[inf.target].isChanged)
							continue;
						nodes[inf.target].influenced += inf.influence;
						if (nodes[inf.target].influenced >= nodes[inf.target].threshold) {
							queue.add(inf.target);
							nodes[inf.target].isChanged = true;
						}
					}
				}
				int count = 0;
				for (int j = 0; j < nNodes; j++)
					if (nodes[j].isChanged)
						count++;
				if (count > max) {
					max = count;
					maxi = i;
					maxj = k;
				}
			}
		}
		System.out.println("Maxi: " + maxi + ", Maxj: " + maxj + ", with max: " + max);
		max = 0;
		maxi = 0;
		maxj = 0;
		maxk = 0;
		for (int i = 0; i < nNodes; i++) {
			for (int l = i + 1; l < nNodes; l++) {
				for (int m = l + 1; m < nNodes; m++) {
			
					ArrayList<Integer> queue = new ArrayList<Integer>();
					
					for (int j = 0; j < nNodes; j++) {
						nodes[j].influenced = 0.0;
						nodes[j].isChanged = false;
					}
					// Initialize queue
					queue.add(i);
					nodes[i].isChanged = true;
					queue.add(l);
					nodes[l].isChanged = true;
					queue.add(m);
					nodes[m].isChanged = true;
			
					while (queue.size() > 0) {
						int u = queue.remove(queue.size() - 1);
						for (Influence inf: nodes[u].neighbors) {
							if (nodes[inf.target].isChanged)
								continue;
							nodes[inf.target].influenced += inf.influence;
							if (nodes[inf.target].influenced >= nodes[inf.target].threshold) {
								queue.add(inf.target);
								nodes[inf.target].isChanged = true;
							}
						}
					}
					int count = 0;
					for (int j = 0; j < nNodes; j++)
						if (nodes[j].isChanged)
							count++;
					if (count > max) {
						max = count;
						maxi = i;
						maxj = l;
						maxk = m;
					}
				}
			}
		}
		System.out.println("Maxi: " + maxi + ", Maxj: " + maxj + ", Maxk: " + maxk + ", with max: " + max);
	}
	
}

