package at.ac.tuwien.lsdc;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.ac.tuwien.lsdc.sched.AbstractScheduler;
import at.ac.tuwien.lsdc.sched.SchedulerA;
import at.ac.tuwien.lsdc.sched.SchedulerB;
import at.ac.tuwien.lsdc.sched.SchedulerC;
import at.ac.tuwien.lsdc.types.Application;
import at.ac.tuwien.lsdc.types.ScenarioData;
import at.ac.tuwien.lsdc.types.ScenarioType;
import at.ac.tuwien.lsdc.types.SchedulerType;
import at.ac.tuwien.lsdc.util.CSVLogger;
import at.ac.tuwien.lsdc.util.CSVParser;

/**
 * Read config (command line properties) and start Scheduler-Simulation.
 */
public class SchedSimulator {

	private static final String USAGE = "SchedSimulator needs exactly 7 parameters: scheduler, scenario, numPMS, numCloudPartners, inputFile, generalLogPath, schedulerLogPath";

	private static final Logger log = LoggerFactory
			.getLogger(SchedSimulator.class);

	private static ScenarioType scenario;
	private static SchedulerType schedulerType;
	private static int numPMs;
	private static int numCloudPartners;
	private static File inputFile;
	private static File generalLog;
	private static File schedulerLog;

	public static void main(String[] args) throws Exception {
		if (args.length == 7) {
			parseCommandLineArgs(args);
		} else if (args.length == 1) {
			String[] splitArgs = args[0].split(" ");
			if (splitArgs.length == 7) {
				parseCommandLineArgs(splitArgs);
			} else {
				log.info(USAGE);
				System.exit(1);
			}
		} else {
			log.info(USAGE);
			System.exit(1);
		}
		LinkedList<Application> apps = CSVParser.parseFile(inputFile);
		Collections.sort(apps);
		AbstractScheduler scheduler;
		switch (schedulerType) {
		case A:
			scheduler = new SchedulerA(numPMs, numCloudPartners, schedulerLog, scenario);
			break;
		case B:
			scheduler = new SchedulerB(numPMs, numCloudPartners, schedulerLog, scenario);
			break;
		default:
			scheduler = new SchedulerC(numPMs, numCloudPartners, schedulerLog, scenario);
			break;
		}
		ScenarioData data = scheduler.initAndStart(apps);
		CSVLogger logger = new CSVLogger(generalLog);
		logger.logScenarioData(data);
	}

	/**
	 * Commandline arguments parsed (mandatory):
	 * - type of scheduler
	 * - type of scenario
	 * - number of available PMs
	 * - number of cloud partners
	 * - scenario input file with applications
	 * - general output file for all schedulers
	 * - specific output file for this scheduler/scenario combination
	 * @param args the command line arguments to parse
	 */
	private static void parseCommandLineArgs(String[] args) {
		String schedulerTypeStr = args[0];
		String scenarioStr = args[1];
		String numPMsStr = args[2];
		String numCloudPartnersStr = args[3];
		String inputFileStr = args[4];
		String generalLogStr = args[5];
		String schedulerLogStr = args[6];

		try {
			schedulerType = SchedulerType.valueOf(schedulerTypeStr);
			scenario = ScenarioType.valueOf(scenarioStr);
			numPMs = Integer.parseInt(numPMsStr);
			numCloudPartners = Integer.parseInt(numCloudPartnersStr);
			inputFile = new File(inputFileStr);
			
			if (!inputFile.canRead())
				throw new IOException("Can not read input file");
			generalLog = new File(generalLogStr);
			boolean  generalLogOK = false;

			if ( generalLog.canWrite() ) {
				generalLogOK = true;
			}
			else if (!generalLog.exists()) {
				log.info("General Log doesn't exist, create new File");
				generalLog.createNewFile();
				generalLogOK = true;
			}
			if (!generalLogOK)
				throw new IOException("Can not write to general log file");
			
			boolean schedulerLogOK = false;
			schedulerLog = new File(schedulerLogStr);
			log.info(schedulerLogStr.toString());
			if (schedulerLog.exists()) {
				schedulerLogOK = schedulerLog.canWrite();
				schedulerLog.delete();
				schedulerLog.createNewFile();
			} else {
				schedulerLog.createNewFile();
				schedulerLogOK = true;
			}
			if (!schedulerLogOK)
				throw new IOException("Can not write to scheduler log file "
						+ schedulerLogStr);
		} catch (Exception e) {
			e.printStackTrace();
			log.info(USAGE);
			System.exit(1);
		}
	}

	public static ScenarioType getScenario() {
		return scenario;
	}

}
