package de.dhbwstuttgart.environment;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

import de.dhbwstuttgart.exceptions.DebugException;
import de.dhbwstuttgart.parser.JavaTXParser;
import de.dhbwstuttgart.parser.antlr.Java8Parser.CompilationUnitContext;
import de.dhbwstuttgart.parser.scope.GatherNames;
import de.dhbwstuttgart.parser.scope.JavaClassRegistry;

/**
 * Stellt die Java-Environment dar und speichert alle Binarys, Librarys und Sourcefiles im zu kompilierenden Projekt
 * Sie erstellt anhand dieser Informationen die JavaClassNameRegistry
 * 
 * TODO: Zur Initialisierung der CompilationEnvironment sollten alle SourceFiles mit ANTLR geparst werden und alle Klassen Generics und Typen herausgefunden werden
 */
public class CompilationEnvironment {
	private final List<URL> librarys;
	private final List<File> sourceFiles;
	public final PackageCrawler packageCrawler;

	/**
	 * Imitiert die Environment beim Aufruf des JavaCompilers auf einer Menge von java-Dateien
	 * Die Environment enth�lt automatisch die Java Standard Library
	 * @param sourceFiles die zu kompilierenden Dateien
	 */
	public CompilationEnvironment(List<File> sourceFiles) {
		/**
		 * Java 9 bringt einige Änderungen am Classloader
		 * So funktioniert der BootClassLoader nicht mehr.
		 * hier gibts ein paar Quellen zum nachlesen:
		 * http://java9.wtf/class-loading/
		 * https://stackoverflow.com/questions/46494112/classloaders-hierarchy-in-java-9
		 *
		 */
		//String bootClassPath = System.getProperty("sun.boot.class.path");
		//		ClassLoader cl = ClassLoader.getPlatformClassLoader();
				ClassLoader cl = ClassLoader.getSystemClassLoader();
				String bootClassPath = System.getProperty("java.class.path");
		librarys = new ArrayList<>();
		for(String path : bootClassPath.split(File.pathSeparator)) {
				   try {
							   librarys.add(new URL("file:"+path));
							   } catch (MalformedURLException e) {
									   new DebugException("Fehler im Classpath auf diesem System");
							   }
			}
		//URLClassLoader loader = new URLClassLoader(new URL[0], cl);
		//librarys = Arrays.asList(loader.getURLs());

		this.sourceFiles = sourceFiles;
        this.packageCrawler = new PackageCrawler(librarys);
	}

	public JavaClassRegistry getRegistry(File forSourceFile) throws ClassNotFoundException, IOException {
		Map<String, Integer> allNames;
		CompilationUnitContext tree = JavaTXParser.parse(forSourceFile);
		allNames = GatherNames.getNames(tree, packageCrawler);
		return new JavaClassRegistry(allNames);
	}

	public List<ClassOrInterface> getAllAvailableClasses() {
		List<ClassOrInterface> ret = new ArrayList<>();
		for(Class c : new PackageCrawler(librarys).getAllAvailableClasses()){
			ret.add(ASTFactory.createClass(c));
		}
		return ret;
	}

}
