package tasks.bench;

/**
 * Produces executable files for a project
 * 
 * @author Lisa Nguyen Quang Do
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeoutException;

import data.BuildInfo;
import tasks.util.Exec;

public class Executable {

	private BuildInfo buildInfo;
	private File projectDir;

	public Set<File> getExecutables(BuildInfo buildInfo, File projectDir) {
		this.buildInfo = buildInfo;
		this.projectDir = projectDir;

		Set<File> ret = new HashSet<File>();
		for (File buildFile : buildInfo.usedBuildFiles)
			buildProject(buildFile);
		ret.addAll(getExecutables());
		return ret;
	}

	public void buildProject(File buildFile) {
		try {
			switch (buildInfo.usedBuildType) {
			case ANT:
				buildAnt(buildFile);
				break;
			case MAVEN:
				buildMaven(buildFile);
				break;
			case GRADLE:
				buildGradle(buildFile);
				break;
			default:
				throw new RuntimeException("Build type unknown: " + buildInfo.usedBuildType);
			}
		} catch (TimeoutException e) {
			System.out.println("Build timeout for " + buildFile);
		}
	}

	public Set<File> getExecutables() {
		try {
			switch (buildInfo.usedBuildType) {
			case ANT:
				return getAntExecutables();
			case MAVEN:
				return getMavenExecutables();
			case GRADLE:
				return getGradleExecutables();
			default:
				throw new RuntimeException("Build type unknown: " + buildInfo.usedBuildType);
			}
		} catch (TimeoutException e) {
			System.out.println("Error in retrieving the executables ");
		}
		return new HashSet<File>();
	}

	public void buildGradle(File buildFile) throws TimeoutException {
		Exec.exec("gradle jar", buildFile.getParentFile());
		Exec.exec("gradle war", buildFile.getParentFile());
		Exec.exec("gradle ear", buildFile.getParentFile());
	}

	private Set<File> getGradleExecutables() throws TimeoutException {
		Set<File> executables = new HashSet<File>();
		executables.addAll(findFiles(".war", "\\build\\libs", projectDir));
		executables.addAll(findFiles(".jar", "\\build\\libs", projectDir));
		executables.addAll(findFiles(".ear", "\\build\\libs", projectDir));
		return executables;
	}

	private void buildMaven(File buildFile) throws TimeoutException {
		Exec.exec("mvn install", buildFile.getParentFile());
	}

	private Set<File> getMavenExecutables() throws TimeoutException {
		Set<File> executables = new HashSet<File>();
		executables.addAll(findFiles(".war", "\\target", projectDir));
		executables.addAll(findFiles(".jar", "\\target", projectDir));
		executables.addAll(findFiles(".ear", "\\target", projectDir));
		return executables;
	}

	public void buildAnt(File buildFile) throws TimeoutException {
		Exec.exec("ant jar", buildFile.getParentFile());
		Exec.exec("ant war", buildFile.getParentFile());
		Exec.exec("ant ear", buildFile.getParentFile());
	}

	private Set<File> getAntExecutables() throws TimeoutException {
		Set<File> executables = new HashSet<File>();
		executables.addAll(findFiles(".war", "\\dist", projectDir));
		executables.addAll(findFiles(".jar", "\\dist", projectDir));
		executables.addAll(findFiles(".ear", "\\dist", projectDir));
		return executables;
	}

	private Set<File> findFiles(String searchString, String directParentFolder, File parentFile) {
		System.out.println("Searching for files" + searchString);

		Set<File> ret = new HashSet<File>();
		try {
			Process p = Runtime.getRuntime().exec("cmd /c dir *" + searchString + " /s ", null, parentFile);
			String line;
			BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
			while ((line = input.readLine()) != null) {
				if (line.endsWith(directParentFolder)) {
					String[] parts = line.split(" ");
					String path = parts[parts.length - 1];
					File executableFolder = new File(path);
					if (!executableFolder.exists())
						throw new RuntimeException("Error resolving folder for " + path);
					for (File f : executableFolder.listFiles()) {
						if (f.getName().endsWith(searchString))
							ret.add(f);
					}
					break;
				}
			}
			input.close();

		} catch (IOException e) {
			System.out.println("Error resolving folder for " + parentFile);
			e.printStackTrace();
		}
		return ret;
	}
}
