/*
+----------------------------------------------------------------------+
|                    Class: CLauncher                                  |
|                                                                      |
| Developper:  Eric Gavaldo (eric.gavaldo@xqual.com)                   |
| Version:     1.1                                                     |
| License:     LGPL (http://www.gnu.org/licenses/lgpl.html)            |
+----------------------------------------------------------------------+
*/

package com.xqual.xlauncher.testcomplete;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Vector;

import com.xqual.xagent.launcher.CExecutionStep;
import com.xqual.xagent.launcher.CLauncher;
import com.xqual.xagent.launcher.CReturnStatus;
import com.xqual.xcommon.CAttribute;
import com.xqual.xcommon.IConstantsResults;
import com.xqual.xcommon.type.CParam;
import com.xqual.xcommon.type.CParamParsingException;
import com.xqual.xcommon.utils.CFileUtils;

public class CLauncherImpl extends CLauncher implements IConstantsResults {
	// +==============================================================+
	// | Attributes                                                   |
	// +==============================================================+

	static final private short TESTCOMPLETE_RESULT_SUCCESS      = 0;
	static final private short TESTCOMPLETE_RESULT_RELATIVE     = 1;
	static final private short TESTCOMPLETE_RESULT_FAILURE      = 2;
	static final private short TESTCOMPLETE_RESULT_NOT_EXECUTED = 3;

	static final String TRACE_HEADER = "{testcomplete  }  ";

	// parameters impacting executing at run time set by the test operator
	private String testRootPath;
	private String testCompleteInstallPath;
	private String testCompleteLogDirectoryPath;

	private static final String TESTCOMPLETE_INTERPRETER_FILE = "bin/TestComplete.exe";
	
	/*
	 * Example of correct command:
	 * "C:/Program Files/Automated QA/TestComplete 8/bin/TestComplete.exe" 
	 *      "C:/Program Files/Automated QA/TestComplete 8/Bin/New Folder/JavaTestProject1/JavaTestProject1/JavaTestProject1.mds" 
	 *      /run /exit
	 */
		
	// +==============================================================+
	// | Constructors                                                 |
	// +==============================================================+

	public CLauncherImpl() {
		super(TRACE_HEADER);
	}

	// +==============================================================+
	// | Methods                                                      |
	// +==============================================================+

	@Override
	public CReturnStatus initialize(int sutId, String sutName, String sutVersion) {
		setSutDetails(sutId, sutName, sutVersion);

		// check the configuration sent by the manager
		printConfiguration();

		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();
		try {
			testRootPath                 = getStringParamValue("General", "Test root path");                       // i.e. C:/Program Files/Automated QA/TestComplete 8/Bin
			
			testCompleteInstallPath      = getStringParamValue("TestComplete", "TestComplete install path");       // i.e. C:/Program Files/Automated QA/TestComplete 8
			testCompleteLogDirectoryPath = getStringParamValue("TestComplete", "TestComplete log directory path"); // i.e. C:/Program Files/Automated QA/TestProject/Log
			
		} catch (CParamParsingException localCParamParsingException) {
			traceln(LOG_PRIORITY_SEVERE, "parsing error during initialization");
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception during initialize: " + localCParamParsingException.getMessage()));
			return new CReturnStatus(RESULT_FAILURE, executionSteps);
		}
		return new CReturnStatus(RESULT_SUCCESS, executionSteps);
	}

	@Override
	public CReturnStatus preRun(int testId, String testPath, String testName, Vector<CAttribute> attributes, String additionalInfo) {
		traceln(LOG_PRIORITY_INFO, "preRun testId=" + testId + " testPath=" + testPath + " [" + testName + "]...");
		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();
		return new CReturnStatus(RESULT_SUCCESS, executionSteps);
	}

	@Override
	public CReturnStatus run(int testId, String testPath, String testName, int testcaseId, int testcaseIndex, String testcaseName, Vector<CParam> params, String additionalInfo) {
		traceln(LOG_PRIORITY_INFO, "run testId=" + testId + " testPath=" + testPath + " testName=" + testName + " testcaseIndex=" + testcaseIndex + "...");

		File workingDirectory = new File(".");
		traceln(LOG_PRIORITY_INFO, "Working directory: " + workingDirectory.getAbsolutePath());
		
		String commandLine = CFileUtils.quoteFilePath(testCompleteInstallPath + "/" + TESTCOMPLETE_INTERPRETER_FILE) + " " + 
		                     CFileUtils.quoteFilePath(CFileUtils.replaceSlashByBackslash(testRootPath + "/" + testPath + "/" + testName + "/" + testcaseName + ".mds")) + " /run /exit";
				
		traceln(LOG_PRIORITY_INFO, "Running the command: " + commandLine);
		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();

		Runtime runtime = null;
		Process process = null;
		try {
			runtime = Runtime.getRuntime();
			process = runtime.exec(commandLine);
			executionSteps.add(new CExecutionStep(now(), RESULT_SUCCESS, "Process started..."));
		} catch (IOException e) {
			traceln(LOG_PRIORITY_SEVERE, "Exception while running the process: " + e.getMessage());
			if (process != null)
				process.destroy();
			process = null;
			return new CReturnStatus(RESULT_NOT_EXECUTED, executionSteps);
		}

		short result = RESULT_FAILURE;
		try {
			result = (short)process.waitFor();
			executionSteps.add(new CExecutionStep(now(), RESULT_SUCCESS, "Process returned..."));
		} catch (InterruptedException e) {
			traceln(LOG_PRIORITY_SEVERE, "Exception while waiting for the end of the process: " + e.getMessage());
			if (process != null)
				process.destroy();
			process = null;
			return new CReturnStatus(RESULT_NOT_EXECUTED, executionSteps);
		}

		if (process != null)
			process.destroy();
		process = null;

		switch (result) {
			case TESTCOMPLETE_RESULT_SUCCESS:
				result = RESULT_SUCCESS;
				break;
			case TESTCOMPLETE_RESULT_RELATIVE:
				result = RESULT_RELATIVE;
				break;
			case TESTCOMPLETE_RESULT_NOT_EXECUTED:
				result = RESULT_NOT_EXECUTED;
				break;
			case TESTCOMPLETE_RESULT_FAILURE:
			default:
				result = RESULT_FAILURE;
				executionSteps.add(new CExecutionStep(now(), RESULT_FAILURE, "See logfile in attachment!"));
				addAttachment(getLogFile());
				traceln(LOG_PRIORITY_SEVERE, "Log file name: " + getLogFile().toString());
				break;
		}
		executionSteps.add(new CExecutionStep(now(), RESULT_SUCCESS, "Test execution ended."));
		return new CReturnStatus(result, executionSteps);
	}

	@Override
	public CReturnStatus postRun(int testId, String testPath, String testName) {
		traceln(LOG_PRIORITY_INFO, "postRun testId=" + testId + " testPath=" + testPath + " [" + testName + "]...");
		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();
		executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "postRun: succeeded"));
		return new CReturnStatus(RESULT_SUCCESS, executionSteps);
	}

	@Override
	public CReturnStatus terminate() {
		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();
		executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "Terminate"));
		return new CReturnStatus(RESULT_SUCCESS, executionSteps);
	}

	// +--------------------------+
	// ¦        Utilities         ¦
	// +--------------------------+

	private String now() {
		Calendar localCalendar = Calendar.getInstance();
		SimpleDateFormat localSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return localSimpleDateFormat.format(localCalendar.getTime());
	}

	private File getLogFile() {
		File logFolder = new File(this.testCompleteLogDirectoryPath);
		String[] childNames = logFolder.list();
		int childsNumber = childNames.length;

		File parentFolder = new File(logFolder.toString() + "/" + childNames[childsNumber-2]);
		String[] logFileNames = parentFolder.list();

		// copy and rename the log file
		File srcLogFile = new File(parentFolder.toString() + "/" + logFileNames[2]);
		File copyLogFile = null;
		try {
			copyLogFile = File.createTempFile("TC7Log", ".xml");
			CFileUtils.copyFiles(srcLogFile, copyLogFile, true);
		} catch (Exception localException) {
			traceln(LOG_PRIORITY_INFO, "Logfile copy exception: " + localException.toString());
		}
		return copyLogFile;
	}
}
