package fi.csc.microarray.comp;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import org.apache.log4j.Logger;

import fi.csc.chipster.toolbox.SADLTool.ParsedScript;
import fi.csc.chipster.toolbox.ToolboxTool;
import fi.csc.microarray.config.Configuration;
import fi.csc.microarray.config.DirectoryLayout;
import fi.csc.microarray.description.SADLDescription;
import fi.csc.microarray.description.SADLGenerator;
import fi.csc.microarray.description.SADLParser.ParseException;
import fi.csc.microarray.messaging.message.JobMessage;
import fi.csc.microarray.module.chipster.ChipsterSADLParser;

/**
 * Abstract base class for any JobFactory that connects to external interpreter to run commands.
 *  
 * @author Aleksi Kallio
 *
 */
public abstract class InterpreterJobFactory implements JobFactory {
	
	/**
	 * Logger for this class
	 */
	static final Logger logger = Logger.getLogger(InterpreterJobFactory.class);

	protected String interpreterCommand;
	protected String toolPath;
	protected String externalToolPath;
	protected ProcessPool processPool;
	protected boolean isDisabled = false;


	public InterpreterJobFactory(HashMap<String, String> parameters) throws IOException {
		Configuration configuration = DirectoryLayout.getInstance().getConfiguration();
		
		String command = parameters.get("command");
		if (command == null || command.equals("")) {
			throw new IllegalArgumentException("Illegal command string: " + command);
		}
		
		String commandParameters = parameters.get("commandParameters");
		
		if (commandParameters != null) {
			command += " " + commandParameters;
		}
		this.interpreterCommand = command;
		this.toolPath = parameters.get("toolPath");
	
		this.externalToolPath = parameters.get("externalToolPath");
		if (externalToolPath == null) {
			throw new RuntimeException("externalToolPath must be set in runtimes.xml");
		}		
		
		// initialize process pool
		// TODO fix R specificity
		int poolSizeMin = configuration.getInt("comp", "r-process-pool-size-min");
		int poolSizeMax = configuration.getInt("comp", "r-process-pool-size-max");
		int poolTimeout = configuration.getInt("comp", "r-process-pool-timeout");
		int processUseCountMax = configuration.getInt("comp", "r-process-pool-process-use-count-max");
		int processLifetimeMax = configuration.getInt("comp", "r-process-pool-process-lifetime-max");
	
		try {
			processPool = new ProcessPool(new File(parameters.get("workDir")), interpreterCommand, poolSizeMin, poolSizeMax, 
				poolTimeout, processUseCountMax, processLifetimeMax);
		} catch (Exception e) {
			this.isDisabled = true;
		}
	}

	@Override
	public abstract CompJob createCompJob(JobMessage message, ToolboxTool tool, ResultCallback resultHandler) throws CompException;

	protected abstract String getStringDelimeter();
	protected abstract String getVariableNameSeparator();

	protected ToolDescription createToolDescription(ParsedScript parsedScript, String sourceResourceName, File moduleDir) throws CompException {

		// parse SADL		
		SADLDescription sadlDescription;
		try {
			sadlDescription = new ChipsterSADLParser().parse(parsedScript.SADL);
		} catch (ParseException e) {
			throw new CompException(e);
		}

		// create description
		ToolDescription ad;
		ad = new ToolDescriptionGenerator().generate(sadlDescription, this);

		// SADL back to string
		SADLGenerator.generate(sadlDescription);
		ad.setSADL(SADLGenerator.generate(sadlDescription));

		// add interpreter specific stuff to ToolDescription
		ad.setCommand(interpreterCommand);
		ad.setImplementation(parsedScript.source); // include headers
		ad.setSourceCode(parsedScript.source);

		// tool and script locations and other variables
		int threadsMax = 2;
		try {
			threadsMax = DirectoryLayout.getInstance().getConfiguration().getInt("comp", "job-threads-max");
		} catch (Exception e) {
			logger.warn("could not read job-threads-max from configuration", e);
		}
		int memoryMax = 1024;
		try {
			memoryMax = DirectoryLayout.getInstance().getConfiguration().getInt("comp", "job-memory-max");
		} catch (Exception e) {
			logger.warn("could not read job-memory-max from configuration", e);
		}

		File commonScriptDir = new File(moduleDir.getParentFile(), "common" + toolPath);
		
		String vns = getVariableNameSeparator();
		String sd = getStringDelimeter();
		
		ad.setInitialiser(
				"chipster" + vns + "tools" + vns + "path = " + sd + externalToolPath + sd + "\n" +
				"chipster" + vns + "common" + vns + "path = " + sd + commonScriptDir.getAbsolutePath() + sd + "\n" + 
				"chipster" + vns + "module" + vns + "path = " + sd + moduleDir.getAbsolutePath() + sd + "\n" + 
				"chipster" + vns + "threads" + vns + "max = " + sd + threadsMax + sd + "\n" +
				"chipster" + vns + "memory" + vns + "max = " + sd + memoryMax + sd + "\n");

		return ad;		
	}

	
	public boolean isDisabled() {
		return this.isDisabled;
	}

}

@@ -4152,16 +4152,21 @@
 );%0A%09%09%7D%0A%0A
+%09%09%0A//
 %09%09File c
@@ -4240,16 +4240,315 @@
 lPath);%0A
+%09%09File modulesRootDir;;%0A%09%09try %7B%0A%09%09%09modulesRootDir = DirectoryLayout.getInstance().getModulesDir();%0A%09%09%7D catch (IOException e) %7B%0A%09%09%09throw new CompException(e);%0A%09%09%7D%0A%09%09%0A%09%09// that toolPath is more like runtime path, e.g python or R%0A%09%09File commonScriptDir = new File(modulesRootDir, %22common%22 + toolPath);%0A
 %09%09%0A%09%09Str
@@ -4899,34 +4899,52 @@
 d + 
-moduleDir.getAbsolutePath(
+new File(modulesRootDir, moduleDir.getName()
 ) + 

Fix variable paths