/*
+----------------------------------------------------------------------+
|                    Class: CLauncherImpl                              |
|                                                                      |
| Developper:  Eric Gavaldo (eric.gavaldo@xqual.com)                   |
| Version:     1.0                                                     |
| License:     LGPL (http://www.gnu.org/licenses/lgpl.html)            |
+----------------------------------------------------------------------+
*/
package com.xqual.xlauncher.silktest;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
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.xagent.launcher.runner.CRunner;
import com.xqual.xagent.launcher.runner.IRunner;
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;
import com.xqual.xcommon.utils.CUtils;
import com.xqual.xlauncher.CTimeoutListener;

/**
 * The <code>CLauncherImpl</code> implementation of <code>ILauncher</code> for Borland SilkTest.
 * The command line interface is as following:
 * C:\Program Files\SilkTest\partner.exe -q -quiet -resexport -resextract -r <testPath>/<testName>.t
 * * @author egavaldo
 */
public class CLauncherImpl extends CLauncher implements IConstantsResults {

	// +==============================================================+
	// | Attributes                                                   |
	// +==============================================================+

	static final String TRACE_HEADER = "{silk_test     }  ";

	// parameters impacting executing at run time set by the test operator
	private String testRootPath;
	private String silkTestInstallPath;
	private String silkTestOption;
	private String silkTestArgs;

	private final int TIMEOUT = 600;
	
	File resFile;
	File rexFile;
	File toFile;
	File txtFile;

	// +==============================================================+
	// | Constructors                                                 |
	// +==============================================================+

	public CLauncherImpl() {
		super(TRACE_HEADER);
	}

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

	@Override
	public CReturnStatus initialize(int sutId, String sutName, String sutVersion) {
		// check the configuration sent by the manager
		printConfiguration();

		try {
			// retrieve the parameters we need
			testRootPath        = getStringParamValue("General", "Test Root Path");
			
			silkTestInstallPath = getStringParamValue("SilkTest", "SilkTest Install Path");
			silkTestOption      = getStringParamValue("SilkTest", "Options (Opt.)");
			silkTestArgs        = getStringParamValue("SilkTest", "Additional arguments (Opt.)");
			return new CReturnStatus(RESULT_SUCCESS, null);
		} catch (CParamParsingException e) {
			traceln(LOG_PRIORITY_SEVERE, "parsing error during initialization");

			Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, e.getMessage()));
			return new CReturnStatus(RESULT_FAILURE, 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 + "]...");

		printAttributes(attributes);

		return new CReturnStatus(RESULT_SUCCESS);
	}

	@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 + " testcaseIndex=" + testcaseIndex + "...");
		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();

		/*
		Partner [-complog filename] [-m mach] [-opt optionset.opt] [-p mess] [-proj filename [-base filename]] [[-q] [-query query name] 
		        [-r filename] [-resexport] [-resextract] [-r] scr.t/suite.s/plan.pln/link.lnk [args]]
		*/
		
		resFile = new File(testRootPath + "/" + testPath + "/" + testName + ".res");
		rexFile = new File(testRootPath + "/" + testPath + "/" + testName + ".rex");
		toFile  = new File(testRootPath + "/" + testPath + "/" + testName + ".to");
		txtFile = new File(testRootPath + "/" + testPath + "/" + testName + ".txt");
		
		CFileUtils.deleteFile(resFile);
		CFileUtils.deleteFile(rexFile);
		CFileUtils.deleteFile(toFile);
		CFileUtils.deleteFile(txtFile);
		
		File tFile = new File(testRootPath + "/" + testPath + "/" + testName + ".t");
		if (!tFile.exists()) {
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "test file " + tFile + " does not exist"));
			return new CReturnStatus(RESULT_FAILURE, executionSteps);
		}
		
		// +------------------------------------+
		// | run the silktest runner            |
		// +------------------------------------+
		CRunner silkRunner = new CRunner("[" + testId + "] "+ testPath + ":" + testName + "." + testcaseIndex,
                                        CFileUtils.quoteFilePath(silkTestInstallPath + "/" + CUtils.getExecutableName("partner")) + " " +
                                        silkTestOption + " -resexport -resextract " + silkTestArgs + " " +
                                        "-r " + CFileUtils.quoteFilePath(tFile.getAbsolutePath()));
		short result = silkRunner.requestAction(IRunner.START_PROCESS, IRunner.DO_NOT_WAIT_END_OF_EXECUTION);
		if (result == RESULT_FAILURE) {
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "script interpretation failed"));
			return new CReturnStatus(RESULT_FAILURE, executionSteps);
		}

		// to check if the execution completed correctly, we need to check if the "<testName>.txt" has been created
	    short resultTimeout = CTimeoutListener.waitForFile(txtFile, TIMEOUT); // 3 minutes timeout
		if (resultTimeout != RESULT_SUCCESS) {
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "timeout of " + TIMEOUT + " seconds to execute the test case expired"));
			return new CReturnStatus(RESULT_FAILURE, executionSteps);
		}
		
		addAttachment(resFile);
		addAttachment(rexFile);
		addAttachment(toFile);
		addAttachment(txtFile);

		return parseResultFile(txtFile, executionSteps);
	}

	@Override
	public CReturnStatus postRun(int testId, String testPath, String testName) {
		traceln(LOG_PRIORITY_INFO, "postRun testId=" + testId + " testPath=" + testPath + ":" + testName + "...");
		return new CReturnStatus(RESULT_SUCCESS);
	}

	@Override
	public CReturnStatus terminate() {
		return new CReturnStatus(RESULT_SUCCESS);
	}
	
	// +--------------------------+
	// ¦        Utilities         ¦
	// +--------------------------+

	private CReturnStatus parseResultFile(File resultFile, Vector<CExecutionStep> executionSteps) {
		String line;
		boolean errorDetected = false;

		try {
			FileInputStream fileInputStream = new FileInputStream(resultFile);
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));

			while ((line = bufferedReader.readLine()) != null) {
				line = line.trim();
				System.out.println(">" + line);
				if (line.indexOf("Passed")>=0) {
					executionSteps.add(new CExecutionStep(RESULT_SUCCESS, line));

				} else if (line.indexOf("Failed")>=0 || line.indexOf("error")>=0) {
					executionSteps.add(new CExecutionStep(RESULT_FAILURE, line));
					errorDetected = true;

				} else {
					executionSteps.add(new CExecutionStep(RESULT_UNKNOWN, line));
				}
			}

			bufferedReader.close();
			fileInputStream.close();
		} catch (Exception e) {
			traceln(LOG_PRIORITY_SEVERE, "exception while parsing the result file: " + e);
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception whle parsing the result file: " + e));
			errorDetected = true;
		}

		if (errorDetected) {
			return new CReturnStatus(RESULT_FAILURE, executionSteps);
		} else {
			return new CReturnStatus(RESULT_SUCCESS, executionSteps);
		}
	}	
}

