package fireTester.simulator;

import java.io.File;

import com.dragonsoft.tryapp.common.SubmissionObj;

import fireTester.communicator.server.Server;
import fireTester.interfaces.ResultsObserver;
import fireTester.interfaces.ServerController;
import fireTester.interfaces.SubmissionTest;
import fireTester.messages.AcknowledgeMessage;
import fireTester.messages.KeepAliveMessage;
import fireTester.messages.TestUnitResults;
import fireTester.messages.TesterException;
import fireTester.tests.batch.BatchCommand;
import fireTester.tests.batch.BatchTest;
import fireTester.tests.batch.BatchTestUnit;


/**
 * Tests for the distributed compile/test system
 */
public class Simulator implements ResultsObserver {
	private ServerController distributor;
	private static final String[] environment = new String[]{"PATH=.:/usr/java/bin:/usr/local/gnu/bin/"};
	private static int idCount = 0;
	private static final long MB = 1024000L;
	private static final long S = 1000L;
	
	/**
	 * 
	 */
	public Simulator() {
		super();

		this.distributor = new Server();
		this.distributor.registerObserver(this);
	}

	/**
	 * Called by the client every 30 seconds to let the server know
	 * the submission is still in the queue.
	 * 
	 * @param keepAlive
	 */
	public void receive_keep_alive(KeepAliveMessage keepAlive) {
		// ignore
	}
	
	/**
	 * Called when a client begins execution for a submission test.
	 * 
	 * @param ack
	 */
	public void receive_acknowledge(AcknowledgeMessage ack) {
		System.out.println("Started executing " + ack.get_submission().toString());
	}
	
	/**
	 * @param r the results of a test unit (test may or may not be complete,
	 * check 'continue'.
	 */
	public void receive_unit_results(TestUnitResults r) {
		if(r.complete()) {
			System.out.println("Completed " + r.get_submission().toString() + (r.passed() ? " (PASSED)" : " (FAILED)"));
		} else {
			System.out.println("Unit update from " + r.get_submission().toString() + (r.passed() ? " (PASSED)" : " (FAILED)") + " started unitID=" + r.getNextUnitID());
		}
	}

	/**
	 * SubmissionTest failed and will not continue.
	 * 
	 * @param e the exception that was thrown 
	 */
	public void receive_test_failed(TesterException e) {
		System.out.println("Test failed! (" + e + ")");
	}
	
	/**
	 * 
	 *
	 */
	public void RunTests() {
		// Compile, run, diff output - pass
		this.distributor.queueTest(this.helloWorld(true));
		
		// Compile, run, diff output - fail
		this.distributor.queueTest(this.helloWorld(false));
		
		// Compile, run, get stuck in infinate loop - timeout
		this.distributor.queueTest(this.neverEnd());
		
		// Try compile and run - fail compile, never attempt run
		this.distributor.queueTest(this.wontCompile());
		
		// Compile, run, attempt to fill HD with junk - exceed dir size limit, fail
		this.distributor.queueTest(this.wasteSpace());
	}
	
	/**
	 * This test will print a message and diff
	 * 
	 * @param pass true if the test should pass, false if it should fail
	 * @return SubmissionTest
	 */
	public SubmissionTest helloWorld(boolean pass) {
		// ensure each ID is unique
		SubmissionObj submission = new SubmissionObj(
				"Simulator:helloWorld"+pass+idCount++,
				"courseID",
				"test_user"+idCount++,
				"actID",
				"assID");
		submission.recordUploadedFile("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/HelloWorld.java");
		submission.recordUploadedFile("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/expectedStdOut.txt");
		submission.recordUploadedFile("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/expectedErrOut.txt");
		
		BatchTestUnit[] units = new BatchTestUnit[2]; 
		BatchCommand[] passCommand = new BatchCommand[1];
		passCommand[0] = new BatchCommand("javac *.java",
				30000L, null, null);
		
		units[0] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				passCommand, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				1 // next unit id
					  );
		
		BatchCommand[] execute = new BatchCommand[1];
		String command = "java HelloWorld";
		if(!pass)
			command += " WhatsMyName";
		execute[0] = new BatchCommand(command, 10000L, 
				"stdOut.txt", "errOut.txt");
		BatchCommand[] diff = new BatchCommand[2];
		diff[0] = new BatchCommand("diff stdOut.txt expectedStdOut.txt", 5*S, "stdDiffResults.txt", null);
		diff[1] = new BatchCommand("diff errOut.txt expectedErrOut.txt", 5*S, "errDiffResults.txt", null);
		
		units[1] = new BatchTestUnit(
				null, // pre_commands
				execute, // commands
				diff, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				-1 // next_unit
					  );

		File saveDir = new File("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/SubmissionResults/" + submission.getSubmissionID());
		
		BatchTest test = new BatchTest(units, 1*MB, environment, null, null);
		test.set_submission(submission, saveDir);
		
		return test;
	}
	
	/**
	 * This test will execute a never ending loop
	 * @return SubmissionTest
	 */
	public SubmissionTest neverEnd() {
		// ensure each ID is unique
		SubmissionObj submission = new SubmissionObj(
				"Simulator:neverEnd"+idCount++,
				"courseID",
				"test_user"+idCount++,
				"actID",
				"assID");
		submission.recordUploadedFile("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/HelloWorld.java");
		
		BatchTestUnit[] units = new BatchTestUnit[2]; 
		BatchCommand[] passCommand = new BatchCommand[1];
		passCommand[0] = new BatchCommand("javac *.java",
				30*S, null, null);
		
		units[0] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				passCommand, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				1 // next unit id
					  );
		
		BatchCommand[] execute = new BatchCommand[1];
		String command = "java HelloWorld NeverDie";
		execute[0] = new BatchCommand(command, 20*S, 
				null, null);
		
		units[1] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				execute, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				-1 // next_unit
					  );

		File saveDir = new File("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/SubmissionResults/" + submission.getSubmissionID());

		BatchTest test = new BatchTest(units, 1*MB, environment, null, null);
		test.set_submission(submission, saveDir);
		
		return test;
	}

	/**
	 * This test will execute a never ending loop
	 * @return SubmissionTest
	 */
	public SubmissionTest wontCompile() {
		// ensure each ID is unique
		SubmissionObj submission = new SubmissionObj(
				"Simulator:wontCompile"+idCount++,
				"courseID",
				"test_user"+idCount++,
				"actID",
				"assID");
		submission.recordUploadedFile("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/Broken.java");
		
		BatchTestUnit[] units = new BatchTestUnit[2]; 
		BatchCommand[] passCommand = new BatchCommand[1];
		passCommand[0] = new BatchCommand("javac *.java",
				30*S, null, null);
		
		units[0] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				passCommand, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				1 // next unit id
					  );
		
		BatchCommand[] execute = new BatchCommand[1];
		String command = "java Broken";
		execute[0] = new BatchCommand(command, 10*S, 
				null, null);
		
		units[1] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				execute, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				-1 // next_unit
					  );

		File saveDir = new File("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/SubmissionResults/" + submission.getSubmissionID());

		BatchTest test = new BatchTest(units, 1*MB, environment, null, null);
		test.set_submission(submission, saveDir);
		
		return test;
	}
	
	/**
	 *
	 * @return SubmissionTest
	 */
	public SubmissionTest wasteSpace() {
		// ensure each ID is unique
		SubmissionObj submission = new SubmissionObj(
				"Simulator:wasteSpace"+idCount++,
				"courseID",
				"test_user",
				"actID",
				"assID");
		submission.recordUploadedFile("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/HelloWorld.java");
		
		BatchTestUnit[] units = new BatchTestUnit[2]; 
		BatchCommand[] passCommand = new BatchCommand[1];
		passCommand[0] = new BatchCommand("javac *.java",
				30*S, null, null);
		
		units[0] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				passCommand, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				1 // next unit id
					  );
		
		BatchCommand[] execute = new BatchCommand[1];
		String command = "java HelloWorld WasteSpace";
		execute[0] = new BatchCommand(command, 10000*S, 
				null, null);
		
		units[1] = new BatchTestUnit(
				null, // pre_commands
				null, // commands
				execute, // check pass command
				null, // pass_post_commands
				null, // fail_post_commands
				false, // required_test
				-1 // next_unit
					  );

		File saveDir = new File("/home/stu3/s12/tryagain/FireTester/Source/TestFiles/SubmissionResults/" + submission.getSubmissionID());

		BatchTest test = new BatchTest(units, 5*MB, environment, null, null);
		test.set_submission(submission, saveDir);
		
		return test;
	}
	
	/**
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Simulator s = new Simulator();
		for(int i = 0; i < 1; i++) {
		//while(true) {
			s.RunTests();
			try {
				Thread.sleep(1000);
			} catch(InterruptedException e) {
				// ignore
			}
		}
	}

}
