package org.bndtools.utils.javaproject;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;

public class JavaProjectUtils {

	/**
	 * Access the project's (Eclipse) classpath to determine the source
	 * directories and their output directories
	 *
	 * @param project the project
	 * @return a map of source directories and their output directories, all
	 *         relative to the project directory. empty map when project is null
	 *         or when an error occurred.
	 */
	static public Map<String, String> getSourceOutputLocations(IJavaProject project) {
		if (project == null) {
			return Collections.emptyMap();
		}

		IClasspathEntry[] classPathEntries = null;
		IPath defaultOutputLocation = null;
		try {
			classPathEntries = project.getRawClasspath();
			defaultOutputLocation = project.getOutputLocation();
		} catch (Throwable e) {
			return Collections.emptyMap();
		}

		if (classPathEntries == null || defaultOutputLocation == null) {
			return Collections.emptyMap();
		}

		IPath projectPath = project.getPath();

		Map<String, String> sourceOutputLocations = new LinkedHashMap<>();
		for (IClasspathEntry classPathEntry : classPathEntries) {
			if (classPathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
				IPath src = classPathEntry.getPath();
				IPath bin = classPathEntry.getOutputLocation();

				if (bin == null) {
					bin = defaultOutputLocation;
				}

				assert (src != null);
				assert (bin != null);

				sourceOutputLocations.put(src.makeRelativeTo(projectPath)
					.toString(),
					bin.makeRelativeTo(projectPath)
						.toString());
			}
		}

		return sourceOutputLocations;
	}

	public static final String	PATH_JRE_CONTAINER		= "org.eclipse.jdt.launching.JRE_CONTAINER";
	public static final String	PATH_JRE_STANDARD_VM	= "org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType";

	private enum JavaLevel {
		J2SE_1_2("J2SE-1.2", "1.2"),
		J2SE_1_3("J2SE-1.3", "1.3"),
		J2SE_1_4("J2SE-1.4", "1.4"),
		J2SE_1_5("J2SE-1.5", "1.5"),
		JAVASE_1_6("JavaSE-1.6", "1.6"),
		JAVASE_1_7("JavaSE-1.7", "1.7"),
		JAVASE_1_8("JavaSE-1.8", "1.8"),
		JAVASE_9("JavaSE-9", "9");

		private final String	label;
		private final String	level;

		JavaLevel(String label, String level) {
			this.label = label;
			this.level = level;
		}

		String getLevel() {
			return level;
		}

		static JavaLevel fromLabel(String label) {
			for (JavaLevel level : JavaLevel.values()) {
				if (level.label.equals(label))
					return level;
			}
			throw new IllegalArgumentException("Unrecognized Java compliance level: " + label);
		}
	}

	public static String getJavaLevel(IJavaProject project) throws Exception {
		IClasspathEntry[] classpathEntries = project.getRawClasspath();

		for (IClasspathEntry classpathEntry : classpathEntries) {
			if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
				IPath path = classpathEntry.getPath();
				if (path == null || path.segmentCount() < 3)
					continue;
				if (PATH_JRE_CONTAINER.equals(path.segment(0)) && PATH_JRE_STANDARD_VM.equals(path.segment(1))) {
					String jreName = path.segment(2);
					return JavaLevel.fromLabel(jreName)
						.getLevel();
				}
			}
		}
		throw new IllegalArgumentException("No standard JRE container found on project classpath");
	}
}
