package antipatternsrecovery.antipatterns;

import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;

import antipatternsrecovery.beans.BeanConverter;
import antipatternsrecovery.beans.ClassBean;

public class RefusedBequest {
	private IJavaProject projectToAnalyze;
	private Vector<IType> types;
	private Vector<Vector<ClassBean>> candidateRefusedBequests;
	
	public RefusedBequest(IJavaProject pProject){
		this.setProjectToAnalyze(pProject);
		this.types=new Vector<IType>();
	}
	
	public Vector<Vector<ClassBean>> searchRefusedBequests() {		
		double refusedCounter=0.0;
		double numberOfSuperclassMethods=0.0;
		candidateRefusedBequests=new Vector<Vector<ClassBean>>();		
		try {
			for(IPackageFragment p: this.projectToAnalyze.getPackageFragments()) {
				for(ICompilationUnit cu: p.getCompilationUnits()){
					if(cu.getElementName().contains(".java")) {
						for(IType t: cu.getTypes()){
							types.add(t);
						}
					}
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		
		for(IType type: types) { 
			if(this.LOC(type.getCompilationUnit()) > 300) {
				try {
					if(type.getSuperclassName()!=null){
						IType superclass=this.searchSuperclass(type, type.getSuperclassName());
						if((superclass!=null) && (! superclass.getSource().contains("abstract"))) {
							numberOfSuperclassMethods=superclass.getMethods().length;
							for(IMethod method: type.getMethods()){
								for(IMethod superMethod: superclass.getMethods()) {
									if((method.getSignature().equals(superMethod.getSignature())) && 
									   (method.getElementName().equals(superMethod.getElementName()))) {
										refusedCounter++;
									}
								}
							}
	
							if((refusedCounter/numberOfSuperclassMethods)>0.7){
								Vector<ClassBean> couple=new Vector<ClassBean>();
								couple.add(BeanConverter.softCastCUToClassBean(type.getCompilationUnit()));
								couple.add(BeanConverter.softCastCUToClassBean(superclass.getCompilationUnit()));
								candidateRefusedBequests.add(couple);
							}
						}
					}
				} catch (JavaModelException e) {
					e.printStackTrace();
				}
			}
		}
		
		return candidateRefusedBequests;
	}
	public IJavaProject getProjectToAnalyze() {
		return this.projectToAnalyze;
	}

	public void setProjectToAnalyze(IJavaProject pProjectToAnalyze) {
		this.projectToAnalyze = pProjectToAnalyze;
	}
	
	public Vector<IType> getTypes() {
		return this.types;
	}

	public void setTypes(Vector<IType> types) {
		this.types = types;
	}
	
	private int LOC(ICompilationUnit pClass){
		int loc=0;
		try {
			String source=pClass.getSource();
			String regex="[\n]";
			Pattern pattern=Pattern.compile(regex);
			Matcher matcher = pattern.matcher(source);
			while (matcher.find()) 
			      loc++;		    
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		return loc+1;
	}

	private IType searchSuperclass(IType pType, String superclassName) {
		try {
			for(IPackageFragment p: this.projectToAnalyze.getPackageFragments()) {
				for(ICompilationUnit cu: p.getCompilationUnits()){
					for(IType t: cu.getTypes()) {
						if(t.getElementName().equals(superclassName)) { // I found the superclass	
							return t;
						}
					}
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public String toString() {
		String toReturn="";
		for(Vector<ClassBean> classes: this.candidateRefusedBequests) {
			for(ClassBean classBean: classes){
				if((classBean.getBelongingPackage()!=null))
					toReturn+=classBean.getName()+"; " + classBean.getBelongingPackage().getName() +";	";
				else toReturn+=classBean.getName() + ";	";
			}
			toReturn+="\n";
		}
		return toReturn;
	}
}