package timing;

import org.jfree.ui.RefineryUtilities;
import graph.Grapher;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * This is the driver class for this project. Run this to time different
 * List and Set operations, collect the data, and to output it in several
 * formats, including as CSV files and as graphs in JPEG files. 
 * @author ben
 */
public class TimerDriver {
	
	public static void main(String[] args) {
		List<Sample> times;

		System.out.println("===========================================================");
		System.out.println("                  Timing Add Operations");
		System.out.println("===========================================================");
		
		times = new ArrayList<>();
		for (int iterations = 1024; iterations <= 4194304; iterations *= 2) {
			final Timer setTimer  = new SetAddTimer();
			final Timer listTimer = new ArrayListAddTimer();
			System.out.println("Iterations = " + iterations);
			setTimer.printResults ("  Running the SetAddTimer"      , iterations + 1);
			listTimer.printResults("  Running the ArrayListAddTimer", iterations + 1);
			times.add(new Sample(iterations, setTimer.secs, listTimer.secs));
			
		}

		processData(times, "add");

		System.out.println("===========================================================");
		System.out.println("               Timing Contains Operations");
		System.out.println("===========================================================");
		
		times = new ArrayList<>();

		
		for (int iterations = 1024; iterations <= 131072; iterations *= 2) {
			final Timer setTimer  = new SetContainsTimer      (iterations / 2);
			final Timer listTimer = new ArrayListContainsTimer(iterations / 2);
			System.out.println("Iterations = " + iterations);
			setTimer .printResults("  Running the SetContainsTimer"      , iterations);
			listTimer.printResults("  Running the ArrayListContainsTimer", iterations);
			times.add(new Sample(iterations, setTimer.secs, listTimer.secs));

		}
		processData(times, "contains");	
		
		System.out.println("===========================================================");
		System.out.println("                Timing Remove Operations");
		System.out.println("===========================================================");
		
		times = new ArrayList<>();

		for (int iterations = 1024; iterations <= 524288; iterations *= 2) {
			Timer setTimer  = new SetRemoveTimer      (iterations / 2);
			Timer listTimer = new ArrayListRemoveTimer(iterations / 2);

			System.out.println("Iterations = " + iterations);
			setTimer .printResults("  Running the SetRemoveTimer"      , iterations);
			listTimer.printResults("  Running the ArrayListRemoveTimer", iterations);
			times.add(new Sample(iterations, setTimer.secs, listTimer.secs));
		}

		processData(times, "remove");
		/**
		 * Dear baffled reader,
		 * 
		 * This is a hacky thing I'm doing to get the program to finish running. A good
		 * programmer would RTFM (i.e., read the docs) and use the library appropriately
		 * so that it wasn't waiting for some user input before exiting. I, on the other
		 * hand, have better things to do (like rewatch Bones for a third time), so I
		 * didn't do this. Instead, I wrote System.exit(0); at the end of a main method
		 * which is such complete and utter code stink that I felt the need to write this
		 * comment explaining myself. I am a code-stink apologist, and I will not apologize
		 * for it!
		 * 
		 *  Anyway, I hope you're having a nice day.
		 *  
		 *  Love,
		 *  Ben
		 */
		System.exit(0);
	}

	/**
	 * Given a list of data samples, return a String containing the body of a CSV
	 * file with those data samples.
	 * @param times
	 * @return String containing the CSV file contents
	 */
	static String makeCSV(final List<Sample> times) {
		
		StringBuilder sb = new StringBuilder();
		sb.append("iterations,set-time(secs),list-time(secs)\n");
		for (Sample s : times) {
			sb.append(s.iters + "," + s.setTime + "," + s.listTime + "\n");
		}
		return sb.toString();
	}
	
	/**
	 * Write a CSV file of the given {@code name} containing data provided by
	 * {@code times}.
	 * @param name File name to write to (will overwrite existing files)
	 * @param times Collection of data samples to write
	 */
	static void writeCSVFile(final String name, List<Sample> times) {
		
		String csvContents = makeCSV(times);
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(name));
			writer.write(csvContents);
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * A catch-all to do all data processing. This
	 * <ol>
	 * 	 <li>
	 *     Creates a new CSV file
	 *   </li>
	 *   <li>
	 *     Creates a line graph and displays it on the screen
	 *   </li>
	 *   <li>
	 *     Saves the file as a JPEG
	 *   </li>
	 * </ol>
	 * @param times The list of data samples that we are plotting
	 * @param opname The operation name that we are concenred with (add, remove, contains)
	 */
	static void processData(final List<Sample> times, final String opname) {
		writeCSVFile(opname + "-times.csv", times);
		Grapher grapher = new Grapher(opname + " times",
				String.format("Times (sec) of iterated set.%s() Vs list.%s()",opname, opname),
				opname + "-times.jpeg",
				times);
		grapher.pack();
		RefineryUtilities.centerFrameOnScreen(grapher);
	}
}
