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.IField;
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 SpaghettiCode {
	private IJavaProject javaProject;
	private Vector<ClassBean> candidateSpaghettiCodes;

	public SpaghettiCode(IJavaProject pProject){
		this.javaProject=pProject;
		this.candidateSpaghettiCodes=new Vector<ClassBean>();
	}

	public Vector<ClassBean> searchCandidateSpaghettiCodes(){
		try {
			for(IPackageFragment pack: this.javaProject.getPackageFragments()){
				for(ICompilationUnit cu: pack.getCompilationUnits()){
					for(IType type: cu.getTypes()){
						for(IMethod method: type.getMethods()){
							int loc=this.LOC(method);

							if((loc>100) && (method.getParameterNames().length==0)){
								for(IField field: type.getFields()) {
									Pattern pattern=Pattern.compile("[^A-Za-z]"+field.getElementName()+"[^A-Za-z]");
									Matcher matcher = pattern.matcher(method.getSource());	
									if(matcher.find()) {
										ClassBean newClass=BeanConverter.softCastCUToClassBean(type.getCompilationUnit());
										if(! this.isIn(newClass))
											this.candidateSpaghettiCodes.add(newClass);
									}
								}
							}
						}
					}
				}
			}
		} catch (JavaModelException e) {
			return this.candidateSpaghettiCodes;
		}

		return this.candidateSpaghettiCodes;
	}

	private int LOC(IMethod pMethod) {
		int loc=0;
		try {
			String source=pMethod.getSource();
			String regex="[\n]";
			Pattern pattern=Pattern.compile(regex);
			Matcher matcher = pattern.matcher(source);
			while (matcher.find()) 
				loc++;		    
		} catch (JavaModelException e) {
			return loc;
		}
		return loc+1;
	}

	private boolean isIn(ClassBean pClassBean){
		for(ClassBean cb: this.candidateSpaghettiCodes) {
			if(cb.getName().equals(pClassBean.getName()))
				return true;
		}
		return false;
	}

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