package es.uniovi.reflection.patternmining.visitor.program;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.TreeScanner;

import es.uniovi.reflection.patternmining.features.FileFeatures;
import es.uniovi.reflection.patternmining.features.ProgramFeatures;
import es.uniovi.reflection.patternmining.model.ReturnFeatures;
import es.uniovi.reflection.patternmining.util.Util;

public class ProgramVisitor extends TreeScanner<ReturnFeatures, ProgramFeatures>{
	
	public static void inputVisitor(Iterable<? extends CompilationUnitTree> asts, String userID, String userClass) throws Exception {
		//Create program
		
		ProgramFeatures programFeatures = new ProgramFeatures();
		programFeatures.setId(Util.getNextProgramId());
		programFeatures.setUserID(userID);
		programFeatures.setUserClass(userClass);
		
		ReturnFeatures returnProgramFeatures = new ReturnFeatures();
		int numberOfTypeDefs = 0;
				
		for(CompilationUnitTree as:asts) {
			ReturnFeatures returnProgramFeaturesAux = as.accept(new ProgramVisitor(), programFeatures);			
			returnProgramFeatures.setNumberOfClasses(returnProgramFeatures.getNumberOfClasses() + returnProgramFeaturesAux.getNumberOfClasses());
			returnProgramFeatures.setNumberOfInterfaces(returnProgramFeatures.getNumberOfInterfaces() + returnProgramFeaturesAux.getNumberOfInterfaces());
			returnProgramFeatures.setNumberOfEnums(returnProgramFeatures.getNumberOfEnums() + returnProgramFeaturesAux.getNumberOfEnums());
			returnProgramFeatures.setNumberOfTypesInDefaultPackage(returnProgramFeatures.getNumberOfTypesInDefaultPackage() + returnProgramFeaturesAux.getNumberOfTypesInDefaultPackage());
			returnProgramFeatures.setNumberOfTypesInPackages(returnProgramFeatures.getNumberOfTypesInPackages() + returnProgramFeaturesAux.getNumberOfTypesInPackages());			
		}
				
		numberOfTypeDefs += returnProgramFeatures.getNumberOfClasses() + returnProgramFeatures.getNumberOfInterfaces() +
				returnProgramFeatures.getNumberOfEnums();
		
//		System.out.println("Classes: "+ returnProgramFeatures.getNumberOfClasses());
//		System.out.println("Interfaces: "+ returnProgramFeatures.getNumberOfInterfaces());
//		System.out.println("Enums: "+ returnProgramFeatures.getNumberOfEnums());
//		System.out.println("Total: "+ numberOfTypeDefs);
		
		programFeatures.setClassPercentage((returnProgramFeatures.getNumberOfClasses() * 100.0f) / numberOfTypeDefs);
		programFeatures.setInterfacePercentage((returnProgramFeatures.getNumberOfInterfaces() * 100f)/numberOfTypeDefs);
		programFeatures.setEnumPercentage((returnProgramFeatures.getNumberOfEnums() * 100f)/numberOfTypeDefs);
		programFeatures.setNumberOfTypesInDefaultPackage(returnProgramFeatures.getNumberOfTypesInDefaultPackage());
		programFeatures.setNumberOfTypesInPackages(returnProgramFeatures.getNumberOfTypesInPackages());
		
		try {
			Util.databaseService.insertProgram(programFeatures);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

    @Override
    public ReturnFeatures visitCompilationUnit(CompilationUnitTree compilationUnitTree, ProgramFeatures programFeatures) {
    	
    	if(compilationUnitTree.getPackageName() != null) {
    		programFeatures.setCodeInPackages(true); //package used without being the default one
    	}else {
    		//System.out.println("Code in the Default Package");
    		programFeatures.setDefaultPackage(true); //package used without being the default one
    	}
    	/*System.out.println(compilationUnitTree.getImports().size());
    	System.out.println(compilationUnitTree.getPackageName());
    	
    	if(compilationUnitTree.getPackageName() == null && compilationUnitTree.getImports().size() > 0) {
    		programFeatures.setCodeInPackages(true);
    	}*/
    	
    	
        FileFeatures fileFeatures = new FileFeatures();        
        fileFeatures.setProgramId(programFeatures.getId());
        fileFeatures.setDefaultPackage(compilationUnitTree.getPackageName() == null);
        
        ReturnFeatures returnProgramFeatures=new ReturnFeatures();
        ReturnFeatures returnProgramFeaturesAux=Util.visitors.getVisitorFiles().visitCompilationUnit(compilationUnitTree, fileFeatures);
    	returnProgramFeatures.setNumberOfClasses(returnProgramFeatures.getNumberOfClasses() + returnProgramFeaturesAux.getNumberOfClasses());
        returnProgramFeatures.setNumberOfInterfaces(returnProgramFeatures.getNumberOfInterfaces() + returnProgramFeaturesAux.getNumberOfInterfaces());
        returnProgramFeatures.setNumberOfEnums(returnProgramFeatures.getNumberOfEnums() + returnProgramFeaturesAux.getNumberOfEnums());
        returnProgramFeatures.setNumberOfTypesInDefaultPackage(returnProgramFeatures.getNumberOfTypesInDefaultPackage() + returnProgramFeaturesAux.getNumberOfTypesInDefaultPackage());
        returnProgramFeatures.setNumberOfTypesInPackages(returnProgramFeatures.getNumberOfTypesInPackages() + returnProgramFeaturesAux.getNumberOfTypesInPackages());
        return returnProgramFeatures;
    }
}
