package antipatternsrecovery.antipatterns;

import java.util.Vector;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
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 SpeculativeGenerality {
	private IJavaProject projectToAnalyze;
	private Vector<IType> types;
	private Vector<IType> abstractTypes;
	private Vector<ClassBean> candidateSpeculativeGeneralities;

	public SpeculativeGenerality(IJavaProject pProject){
		this.setProjectToAnalyze(pProject);
		this.types=new Vector<IType>();
		this.abstractTypes=new Vector<IType>();
	}

	public Vector<ClassBean> searchSpeculativeGeneralities() {		
		candidateSpeculativeGeneralities=new Vector<ClassBean>();		
		try {
			for(IPackageFragment p: this.projectToAnalyze.getPackageFragments()) {
				for(ICompilationUnit cu: p.getCompilationUnits()){
					for(IType t: cu.getTypes()){
						this.types.add(t);
						int index=0;
						try {
							index = t.getSource().indexOf("{");
							if(index!=-1) {
								String signature=t.getSource().substring(0, index-1);
								if(signature.contains(" abstract class"))
									this.abstractTypes.add(t);		
							}
						} catch (JavaModelException e) {
							e.printStackTrace();
						}
					}
				}	
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}

		for(IType type: this.abstractTypes) {
			int counterOfChildren=0;
			for(IType check: this.types){
				try {
					if(check.getSuperclassName()!=null){
						if(check.getSuperclassName().equals(type.getElementName()))
							counterOfChildren++;
					}
				} catch (JavaModelException e) {
					return candidateSpeculativeGeneralities;
				}
			}

			if(counterOfChildren<2) {
				try {
					ClassBean newClass=BeanConverter.softCastCUToClassBean(type.getCompilationUnit());
					if(! this.isIn(newClass))
						this.candidateSpeculativeGeneralities.add(newClass);
				} catch (JavaModelException e) {
					return candidateSpeculativeGeneralities;
				}
			}
		}

		return candidateSpeculativeGeneralities;
	}

	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 boolean isIn(ClassBean pClassBean){
		for(ClassBean cb: this.candidateSpeculativeGeneralities) {
			if(cb.getName().equals(pClassBean.getName()))
				return true;
		}
		return false;
	}

	public String toString() {
		String toReturn="";
		for(ClassBean classBean: this.candidateSpeculativeGeneralities) {
			if(classBean.getBelongingPackage()!=null)
				toReturn+=classBean.getName()+"; " +classBean.getBelongingPackage().getName()+";\n";
			else 
				toReturn+=classBean.getName()+";\n";
		}
		return toReturn;
	}
}