package it.mice.voila.runtime.oawtemplate.runner;

import it.mice.voila.runtime.oawtemplate.utils.TempDirectory;
import it.mice.voila.runtime.oawtemplate.utils.ZipFolder;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.lf5.util.StreamUtils;
import org.openarchitectureware.workflow.WorkflowRunner;
import org.openarchitectureware.workflow.issues.Issues;
import org.openarchitectureware.workflow.issues.IssuesImpl;
import org.openarchitectureware.workflow.monitor.NullProgressMonitor;

public class OAWWorkflowRunner {

	public void execute(Object model, InputStream resource, ZipOutputStream zos) throws Exception {
		File fileResource = createJarResource(resource);
		execute(model, fileResource.getPath(), zos);
	}

	public void execute(Map<String, Object> model, InputStream resource, ZipOutputStream zos) throws Exception {
		File fileResource = createJarResource(resource);
		execute(model, fileResource.getPath(), zos);
	}

	public void execute(Object model, String resource, ZipOutputStream zos) throws Exception {
		Map<String, Object> models = new HashMap<String, Object>();
		models.put("model", model);
		execute(models, resource, zos);
	}

	public void execute(Map<String, Object> model, String resource, ZipOutputStream zos) throws Exception {
		ClassLoader backupClassLoader = null;
		TempDirectory tempDir = new TempDirectory();

		try {
			if (resource != null) {
				backupClassLoader = instrumentClassLoader("file:///" + resource);
			}

			Map<String, String> properties = new HashMap<String, String>();
			tempDir.create();
			properties.put("targetDir", tempDir.getDirectory().getAbsolutePath());
			
			Map<String, Object> slotContents = new HashMap<String, Object>();
			Iterator<String> i = model.keySet().iterator();
			while (i.hasNext()) {
				String key = (String) i.next();
				slotContents.put(key, model.get(key));
			}
			
			String wfFile = "workflow.oaw";
			WorkflowRunner theWorkflowRunner = new WorkflowRunner();

			boolean configOK = theWorkflowRunner.prepare(wfFile, new NullProgressMonitor(), properties);
			final Issues issues = new IssuesImpl();
			if (configOK) {
				configOK = theWorkflowRunner.executeWorkflow(slotContents, issues);
				ZipFolder.zipDir(tempDir.getDirectory(), zos);
				zos.close();
			} else {
				issues.addError("Error during prepare phase of the generation. See log file for more information.");
			}
		} finally {
			tempDir.dispose();
			if (resource != null) {
				Thread.currentThread().setContextClassLoader(backupClassLoader);
			}
		}
	}

	private File createJarResource(InputStream resource) throws IOException, FileNotFoundException {
		File fileResource = File.createTempFile(Thread.currentThread().getName(), ".jar");
		FileOutputStream fos = new FileOutputStream(fileResource);

		StreamUtils.copy(resource, fos);
		fos.close();
		return fileResource;
	}

	private ClassLoader instrumentClassLoader(String jar) {
		ClassLoader backupClassLoader = Thread.currentThread().getContextClassLoader();

		try {
			URL[] url = new URL[] {new URL(jar)};
			ClassLoader myClassLoader = new URLClassLoader(url, backupClassLoader);
			Thread.currentThread().setContextClassLoader(myClassLoader);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return backupClassLoader;
	}
}
