package logging;

import generating.GeneratorsController;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import mapping.Mapper;

/**
 * This class provides the service to build reports in the form of text files
 * that can be read by spread sheet programs.
 * 
 * @author Majd Kokaly
 */
public class Reporter {
	/**
	 * Hard coded name of the default folder the reports go in
	 */
	private static final String REPORTS_FOLDER = "Reports";

	/**
	 * The time format used by the class
	 */
	private static DateFormat dateFormatter = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");

	/**
	 * This method generates a report (file) about the job classes during or after a
	 * test. It reports info such as "Class ID", "Number of Jobs", "Arrival
	 * Rate", "Actual Arrival Rate", "Execution Time","Actual Execution Time", "Waiting
	 * Time", "Communication Time"and "Response Time" for every job class in a
	 * particular mapper object.
	 * 
	 * @param mapper
	 *            the Mapper object containing the job classes
	 * @see mapping.Mapper
	 * @param controller
	 *            the GeneratorsController object that generated jobs.
	 * @param fileName
	 *            a target to store the report on
	 * @throws IOException
	 *             that might happened when accessing the file system
	 */
	public static void generateReportAboutJobClasses(Mapper mapper,
			GeneratorsController controller, String fileName)
			throws IOException {

		String[] jobClassesHeaders = { "Class ID", "Number of Jobs",
				"Arrival Rate", "Actual Arrival Rate", "Execution Time",
				"Actual Execution Time", "T/O" , "Waiting Time", "Waiting Time-T/O" ,"Communication Time", "Communication Time-T/O",
				"Response Time (R.T.)", "R.T.-T/O" , "R.T.(TU)" , "R.T.-T/O (TU)" };

		if (fileName == null)
			fileName = REPORTS_FOLDER + "/" + "jobClasses.txt";

		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(new File(fileName));
		} catch (IOException e) {
			e.printStackTrace();
		}
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

		int i;
		for (i = 0; i < jobClassesHeaders.length - 1; i++) {
			bufferedWriter.append(jobClassesHeaders[i] + "\t");
		}
		bufferedWriter.append(jobClassesHeaders[i] + "\n");

		for (i = 1; i <= mapper.getClassesTable().size(); i++) {
			bufferedWriter.append(mapper.getClassesTable().get(i).getIndex()
					+ "\t");
			bufferedWriter.append(controller.getGenerators()[i - 1]
					.getJobsGeneratedNumber()
					+ "\t");
			bufferedWriter
					.append(mapper.getJobClass(i).getArrivalRate() + "\t");
			bufferedWriter.append(controller.getGenerators()[i - 1]
					.getActualRate()
					+ "\t");
			bufferedWriter.append(mapper.getJobClass(i).getexecutionTime() + "\t");
			bufferedWriter.append(controller.getGenerators()[i - 1]
					.getAcutualIterationAverage()
					+ "\t");
			
			bufferedWriter.append(mapper.getJobsTable().getTimeOutedJobsCount(i) + "\t");
			
			bufferedWriter.append(mapper.getJobsTable()
					.getSchedulingDelayInMilliSeconds(i)
					/ 1000 + "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getSchedulingDelayInMilliSecondsIncludingTimedOut(i)
					/ 1000 + "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getCommunicationDelayInSeconds(i)
					+ "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getCommunicationDelayInSecondsIncludingTimedOut(i)
					+ "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getResponseTimeInSeconds(i)
					+ "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getResponseTimeInSecondsIncludingTimedOut(i)
					+ "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getResponseTimeInSeconds(i)/(mapper.getTimeUnitInMinutes()*60)
					+ "\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getResponseTimeInSecondsIncludingTimedOut(i)/(mapper.getTimeUnitInMinutes()*60)
					+ "\n");
		}

		bufferedWriter.append("All\t");
		
		bufferedWriter.append("-\t");
		bufferedWriter.append("-\t");
		bufferedWriter.append("-\t");
		bufferedWriter.append("-\t");
		bufferedWriter.append("-\t");
		bufferedWriter.append("-\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getSchedulingDelayInMilliSeconds()
				+ "\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getSchedulingDelayInMilliSecondsIncludingTimedOut()
				+ "\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getCommunicationDelayInSeconds()
				+ "\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getCommunicationDelayInSecondsIncludingTimedOut()
				+ "\t");

		bufferedWriter.append(mapper.getJobsTable()
				.getResponseTimeInSeconds()
				+ "\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getResponseTimeInSecondsIncludingTimedOut()
				+ "\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getResponseTimeInSecondsIncludingTimedOut() /(mapper.getTimeUnitInMinutes()*60)
				+ "\t");
		
		bufferedWriter.append(mapper.getJobsTable()
				.getResponseTimeInSecondsIncludingTimedOut() /(mapper.getTimeUnitInMinutes()*60)
				+ "\n");
		
		
		// Closing streams
		if (bufferedWriter != null) {
			bufferedWriter.close();
		}

		if (fileWriter != null) {
			fileWriter.close();
		}
	}

	/**
	 * This method generates a report about the job classes during or after a
	 * test. It reports info such as "Class ID", "Number of Jobs", "Arrival
	 * Rate", "Actual Arrival Rate", "Execution Time","Actual Execution Time", "Waiting
	 * Time", "Communication Time"and "Response Time" for every job class in a
	 * particular mapper object.
	 * 
	 * @param mapper
	 *            the Mapper object containing the job classes
	 * @see mapping.Mapper
	 * @param controller
	 *            the GeneratorsController object that generated jobs.
	 * @param fileName
	 *            a target file to store the report on
	 * @throws IOException
	 *             that might happened when accessing the file system
	 */

	/**
	 * This method generates report about system level statistics such as
	 * Scheduling scheme, Start Time, Duration, Communication Delay, and Waiting
	 * time, etc..
	 * 
	 * @param mapper
	 *            the Mapper object containing the job classes
	 * @see mapping.Mapper .
	 * @param fileName
	 *            a target file to store the report on.
	 */
	public static void generateReportAboutSystemStatistics(Mapper mapper,
			String fileName) {
		if (fileName == null)
			fileName = REPORTS_FOLDER + "/" + "statistics.txt";

		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(new File(fileName));
		} catch (IOException e) {
			e.printStackTrace();
		}
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
		try {
			bufferedWriter.append("Scheduling Scheme:\t");
			bufferedWriter.append(mapper.getMappingScheme().getDescription()
					+ "\n");

			bufferedWriter.append("Start Time:\t");
			bufferedWriter.append(dateFormatter.format(mapper.getStartTime()
					.getTime())
					+ "\n");

			bufferedWriter.append("Stop Time:\t");
			if (mapper.getStopTime() == null)
				bufferedWriter.append("Still Running\n");
			else
				bufferedWriter.append(dateFormatter.format(mapper.getStopTime()
						.getTime())
						+ "\n");

			bufferedWriter.append("Duration:\t");
			bufferedWriter.append(mapper.getTimeElapsedInTimeUnits()
					+ " Time Units\n");

			bufferedWriter.append("Minutes Per Time Units:\t");
			bufferedWriter.append(mapper.getTimeUnitInMinutes()
					+ "\tminute(s)\n");
			
			
			bufferedWriter.append("Waiting Time\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getSchedulingDelayInMilliSeconds()
					+ "\tmilliseconds\n");
			
			bufferedWriter.append("Waiting Time with timed out jobs\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getSchedulingDelayInMilliSecondsIncludingTimedOut()
					+ "\tmilliseconds\n");
			
			bufferedWriter.append("Communication Delay\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getCommunicationDelayInSeconds()
					+ "\tseconds\n");
			
			bufferedWriter.append("Communication Delay With timed out jobs\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getCommunicationDelayInSecondsIncludingTimedOut()
					+ "\tseconds\n");

			bufferedWriter.append("Resonse Time:\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getResponseTimeInSeconds()
					+ "\tseconds\n");
			
			bufferedWriter.append("Resonse Time with timed out jobs:\t");
			bufferedWriter.append(mapper.getJobsTable()
					.getResponseTimeInSecondsIncludingTimedOut()
					+ "\tseconds\n");

			bufferedWriter.append("Mean Failure Periods\t");
			bufferedWriter.append(mapper.getServersTable()
					.getFailurePeriodsMeanOfAllServersInMinutes()
					+ "\tminutes\n");

			bufferedWriter.append("Mean Up-time\t");
			bufferedWriter.append(mapper.getServersTable()
					.getUpTimeMeanOfAllServersInMinutes()
					+ "\tminutes\n");
		} catch (IOException ex) {
			ex.printStackTrace();
		}

		finally {
			// Closing streams
			if (bufferedWriter != null) {
				try {
					bufferedWriter.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (fileWriter != null) {
				try {
					fileWriter.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 
	 * This report generates a text file containing Mue Matrix (Processing Rates)
	 * and the actual Processing rates that were obtained during or after a test.
	 * 
	 * @param mapper
	 *            the Mapper object containing the job classes.
	 * @see mapping.Mapper .
	 * @param fileName
	 *            a target file to store the report on.
	 */
	public static void generateReportOfMue(Mapper mapper, String fileName)
			throws IOException {
		if (fileName == null)
			fileName = REPORTS_FOLDER + "/" + "Mue.txt";

		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(new File(fileName));
		} catch (IOException e) {
			e.printStackTrace();
		}
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

		double mue[][] = mapper.constructMueMatrix();
		double actualMue[][] = mapper.constructActualMueMatrix();

		try {
			bufferedWriter.append("Ideal Matrix\n");
			for (int i = 0; i < mue.length; i++) {
				for (int j = 0; j < mue[i].length; j++) {
					bufferedWriter.append(mue[i][j] + "\t");
				}
				bufferedWriter.append("\n");
			}

			bufferedWriter.append("\n\n\nActual Matrix\n");
			for (int i = 0; i < actualMue.length; i++) {
				for (int j = 0; j < actualMue[i].length; j++) {
					bufferedWriter.append(actualMue[i][j] + "\t");
				}
				bufferedWriter.append("\n");
			}
		} catch (IOException ex) {
			throw new IOException();
		}

		finally {
			// Closing streams
			if (bufferedWriter != null) {
				try {
					bufferedWriter.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (fileWriter != null) {
				try {
					fileWriter.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

}
