package testsmell.smell;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import testsmell.AbstractSmell;
import testsmell.SmellyElement;
import testsmell.TestClass;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;


/*
This class checks if the code file contains a Constructor. Ideally, the test suite should not have a constructor. Initialization of fields should be in the setUP() method
If this code detects the existence of a constructor, it sets the class as smelly
 */
public class ConstructorInitialization extends AbstractSmell {

    private List<SmellyElement> smellyElementList;
    private String testFileName;

    public ConstructorInitialization() {
        smellyElementList = new ArrayList<>();
    }

    /**
     * Checks of 'Constructor Initialization' smell
     */
    @Override
    public String getSmellName() {
        return "Constructor Initialization";
    }

    /**
     * Returns true if any of the elements has a smell
     */
    @Override
    public boolean getHasSmell() {
        return smellyElementList.stream().filter(x -> x.getHasSmell()).count() >= 1;
    }

    /**
     * Analyze the test file for Constructor Initialization smell
     */
    @Override
    public void runAnalysis(CompilationUnit testFileCompilationUnit,CompilationUnit productionFileCompilationUnit, String testFileName, String productionFileName) throws FileNotFoundException {
        this.testFileName = testFileName;
        ConstructorInitialization.ClassVisitor classVisitor;
        classVisitor = new ConstructorInitialization.ClassVisitor();
        classVisitor.visit(testFileCompilationUnit, null);
    }

    /**
     * Returns the set of analyzed elements (i.e. test methods)
     */
    @Override
    public List<SmellyElement> getSmellyElements() {
        return smellyElementList;
    }


    private class ClassVisitor extends VoidVisitorAdapter<Void> {
        TestClass testClass;
        boolean constructorAllowed=false;

        @Override
        public void visit(ClassOrInterfaceDeclaration n, Void arg) {
            for(int i=0;i<n.getExtendedTypes().size();i++){
                ClassOrInterfaceType node = n.getExtendedTypes().get(i);
                constructorAllowed = node.getNameAsString().equals("ActivityInstrumentationTestCase2");
            }
            super.visit(n, arg);
        }

        @Override
        public void visit(ConstructorDeclaration n, Void arg) {
            // This check is needed to handle java files that have multiple classes
            if(n.getNameAsString().equals(testFileName)) {
                if(!constructorAllowed) {
                    testClass = new TestClass(n.getNameAsString());
                    testClass.setHasSmell(true);
                    smellyElementList.add(testClass);
                }
            }
        }
    }
}