package de.dhbwstuttgart.parser.scope;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.dhbwstuttgart.parser.antlr.Java8BaseListener;
import de.dhbwstuttgart.syntaxtree.AbstractASTWalker;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
import org.antlr.v4.runtime.tree.TerminalNode;

import de.dhbwstuttgart.environment.PackageCrawler;
import de.dhbwstuttgart.parser.antlr.Java8Parser;

public class GatherNames {

	  public static Map<String, Integer> getNames(Java8Parser.CompilationUnitContext ctx, PackageCrawler packages) throws ClassNotFoundException{
		  Map<String, Integer> ret = new HashMap<>();
	    String pkgName = getPackageName(ctx);
	    String nameString = "";
	    for (Java8Parser.TypeDeclarationContext typeDecl : ctx.typeDeclaration()){
	      if(typeDecl.interfaceDeclaration() != null){
	        if(typeDecl.interfaceDeclaration().normalInterfaceDeclaration() != null){
	          if(pkgName != ""){
	            nameString = pkgName + "." + typeDecl.interfaceDeclaration().normalInterfaceDeclaration().Identifier().toString();
	          }
	          else{
	            nameString = typeDecl.interfaceDeclaration().normalInterfaceDeclaration().Identifier().toString();
	          }
				int numGenerics = typeDecl.interfaceDeclaration().normalInterfaceDeclaration().typeParameters()!=null?
						typeDecl.interfaceDeclaration().normalInterfaceDeclaration().typeParameters().typeParameterList().typeParameter().size():0;
	          //Die Generic TypeParameter Definitionen Nicht! an die JavaClassName-Registry anfügen:
	          /* //Diese gelängen dadurch in den globalen Scope, was sie schließlich nicht sind
	          if(typeDecl.classDeclaration().normalClassDeclaration().typeParameters() != null){
	            for(Java8Parser.TypeParameterContext tp : typeDecl.classDeclaration().normalClassDeclaration().typeParameters().typeParameterList().typeParameter()){
	              //this.reg.add(tp.Identifier().toString());
	            }
	          }
	          */
	          ret.put(nameString, numGenerics);
	        }
	      }
	      else{
	        if(typeDecl.classDeclaration().normalClassDeclaration() != null){
	          if(pkgName != ""){
	            nameString = pkgName + "." + typeDecl.classDeclaration().normalClassDeclaration().Identifier().toString();
	          }
	          else{
	            nameString = typeDecl.classDeclaration().normalClassDeclaration().Identifier().toString();
	          }
	          //Die Generic TypeParameter Definitionen Nicht! an die JavaClassName-Registry anfügen:
	          /* //Diese gelängen dadurch in den globalen Scope, was sie schließlich nicht sind
	          if(typeDecl.classDeclaration().normalClassDeclaration().typeParameters() != null){
	            for(Java8Parser.TypeParameterContext tp : typeDecl.classDeclaration().normalClassDeclaration().typeParameters().typeParameterList().typeParameter()){
	              this.reg.add(tp.Identifier().toString());
	            }
	          }
	          */
				int numGenerics = typeDecl.classDeclaration().normalClassDeclaration().typeParameters()!=null?
						typeDecl.classDeclaration().normalClassDeclaration().typeParameters().typeParameterList().typeParameter().size():0;

				ret.put(nameString, numGenerics);
	        }
	      }
	    }
	    ret.putAll(getImports(ctx, packages));
	    return ret;
	  }
	  

	  public static Map<String, Integer> getImports(Java8Parser.CompilationUnitContext ctx, PackageCrawler packages) throws ClassNotFoundException {
		  Map<String, Integer> ret = new HashMap<>();
	    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
		  //ret.putAll(packages.getClassNames("java.lang"));
		  for(Java8Parser.ImportDeclarationContext importDeclCtx : ctx.importDeclaration()){
	      if(importDeclCtx.singleTypeImportDeclaration() != null){
	    	  Class cl = classLoader.loadClass(importDeclCtx.singleTypeImportDeclaration().typeName().getText());
			  ret.put(cl.getName(), cl.getTypeParameters().length);
	      }
	      else if(importDeclCtx.typeImportOnDemandDeclaration() != null){
	    	  ret.putAll(packages.getClassNames(importDeclCtx.typeImportOnDemandDeclaration().packageOrTypeName().getText()));
	      }
	      else if(importDeclCtx.singleStaticImportDeclaration() != null){
			  Class cl = classLoader.loadClass(importDeclCtx.singleStaticImportDeclaration().typeName().getText()+"."+importDeclCtx.singleStaticImportDeclaration().Identifier().getText());
			  ret.put(cl.getName(), cl.getTypeParameters().length);
		  }
	      else{
	    	  ret.putAll(packages.getClassNames(importDeclCtx.staticImportOnDemandDeclaration().typeName().getText()));
	      }
	    }
	    return ret;
	  }

	private static String getPackageName(Java8Parser.CompilationUnitContext ctx){
		String pkgName = "";
		if(ctx.packageDeclaration() != null){
			for(TerminalNode t : ctx.packageDeclaration().Identifier()){
				pkgName = pkgName + "." + t.toString();
			}
			pkgName = pkgName.substring(1);
		}
		return pkgName;
	}
}