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

import java.io.File;
import java.util.Vector;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

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.CXmlDocumentFactory;
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;

/**
 * The <code>CLauncherImpl</code> implementation of <code>ILauncher</code> for WebUI.
 * @author egavaldo
 * developed based on:
 * - http://blogs.telerik.com/testing/posts/10-07-01/a_look_under_the_hood_at_webui_test_studio_s_execution_engine_part_1_of_2.aspx
 * - http://blogs.telerik.com/testing/posts/10-07-06/a_look_under_the_hood_at_webui_test_studio_s_execution_engine_part_2_of_2.aspx
 */
public class CLauncherImpl extends CLauncher implements IConstantsResults {

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

	static final String TRACE_HEADER = "{webui         }  ";

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

	private File workingDir;

	private static final String WEBUI_RUNNER = CUtils.getExecutableName("ArtOfTest.Runner");

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

	public CLauncherImpl() {
		super(TRACE_HEADER);
	}

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

	@Override
	public boolean getDefaultTestcaseMustBeCreated() {
		return true;
	}
	
	@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 {
			// retrieve the parameters we need
			testRootPath     = getStringParamValue("General",  "Test root path"); 
			webUIInstallPath = getStringParamValue("WebUI",    "WebUI install path");
		} catch (CParamParsingException e) {
			traceln(LOG_PRIORITY_SEVERE, "parsing error during initialization");
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception during initialize: " + e.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=" + testRootPath + "/" + testPath + "/" + testName + " testcaseIndex=" + testcaseIndex + "...");
		Vector<CExecutionStep> executionSteps = new Vector<CExecutionStep>();

		String scriptParentFolderPath = testRootPath + "/" + testPath;
		workingDir = new File(scriptParentFolderPath);

		deleteResultfiles(workingDir);
		
		
		// +------------------------------------+
		// | Interpret the script
		// +------------------------------------+
		CRunner webUIRunner = new CRunner("[" + testId + "] "+ testPath + ":" + testName + "." + testcaseIndex,
		                                   CFileUtils.quoteFilePath(webUIInstallPath + "/Bin/" + WEBUI_RUNNER) + " " +
		                                   "aii=" + CFileUtils.quoteFilePath(testRootPath + "/" + testPath + "/" + testName + ".aii") + " " +
		                                   "out=" + CFileUtils.quoteFilePath(testRootPath + "/" + testPath) + " " + // where the .aiiresult file is generated
                                           workingDir);
		short result = webUIRunner.requestAction(IRunner.START_PROCESS, IRunner.WAIT_END_OF_EXECUTION);
		if (result == RESULT_FAILURE) {
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "script interpretation failed"));
			return new CReturnStatus(RESULT_FAILURE, executionSteps);
		}

		File resultFile = searchResultfiles(workingDir);
		if (resultFile != null) {
			executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "result file found: " + resultFile));
			addAttachment(resultFile);
			return parseResultFile(resultFile, executionSteps);
		} else {
			executionSteps.add(new CExecutionStep(RESULT_FAILURE, "result file not found!"));
			return new CReturnStatus(RESULT_FAILURE, 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 void deleteResultfiles(File folder) {
		if (folder.isDirectory()) {
			File[] files = folder.listFiles();
			for (int i=0; i<files.length; i++) {
				File file = files[i];
				if (file.isFile()) {
					if (CFileUtils.getExtension(file).equalsIgnoreCase("aairesult")) {
						traceln(LOG_PRIORITY_INFO, "deleting former result file: " + file);
						CFileUtils.deleteFile(file);
					}
				}
			}
		}
	}
	
	private File searchResultfiles(File folder) {
		// search for the result file
		File resultFile = null;
		if (folder.isDirectory()) {
			File[] files = folder.listFiles();
			for (int i=0; i<files.length; i++) {
				File file = files[i];
				if (file.isFile()) {
					if (CFileUtils.getExtension(file).equalsIgnoreCase("aairesult")) {
						resultFile = file;
						break;
					}
				}
			}
		}
		return resultFile;
	}
	
	public static CReturnStatus parseResultFile(File resultFile, Vector<CExecutionStep> executionSteps) {	
		Document xmlDocument = CXmlDocumentFactory.createXMLDoc(resultFile);	
		boolean errorDetected = false;
		System.out.println("xml = " + CFileUtils.FileToString(resultFile));
		
		NodeList testNodes = CXmlDocumentFactory.getNodeObjListFromXPath(xmlDocument, "/RunResult/TestResults/Item");
		System.err.println("- - - - - nb tests: " + testNodes.getLength());
		for (int i = 0; i < testNodes.getLength(); i++) {
            Node testNode = testNodes.item(i);
            
            String testResult = CXmlDocumentFactory.getNodeStringValueFromXPath(testNode, "ResultType[@Type='ArtOfTest.Common.Design.ResultType']");
            if (!testResult.equalsIgnoreCase("Pass")) errorDetected = true;
            executionSteps.add(new CExecutionStep(testResult.equalsIgnoreCase("Pass") ? RESULT_SUCCESS : RESULT_FAILURE, testResult));
            
            NodeList stepNodes = CXmlDocumentFactory.getNodeObjListFromXPath(testNode, "AutomationStepResults/Item[@Type='ArtOfTest.WebAii.Design.AutomationStepResult']");
            System.err.println("- - - - - nb steps: " + stepNodes.getLength());
            for (int j = 0; j < stepNodes.getLength(); j++) {
            	Node stepNode = stepNodes.item(j);

            	String stepStatus     = CXmlDocumentFactory.getNodeStringValueFromXPath(stepNode, "ResultType[@Type='ArtOfTest.Common.Design.ResultType']");
            	String stepDescription = CXmlDocumentFactory.getNodeStringValueFromXPath(stepNode, "StepDescription");
            	if (!stepStatus.equalsIgnoreCase("Pass")) errorDetected = true;
                executionSteps.add(new CExecutionStep(stepStatus.equalsIgnoreCase("true") ? RESULT_SUCCESS : RESULT_FAILURE, " > " + stepDescription)); 
            }
		}

		System.out.println("executionSteps=" + executionSteps);
		return new CReturnStatus(errorDetected ? RESULT_FAILURE : RESULT_SUCCESS, executionSteps);
	}	
}

