package antipatternsrecovery.parsingElements;

import java.util.ArrayList;
import java.util.Collection;
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 org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import antipatternsrecovery.beans.ClassBean;
import antipatternsrecovery.beans.MethodBean;
import antipatternsrecovery.beans.PackageBean;

public class ClassParser {
	public static IJavaProject project;

	public static ClassBean parse(TypeDeclaration pClassNode) {
		// Instantiate the bean
		ClassBean classBean = new ClassBean();

		// Set the name
		classBean.setName(pClassNode.getName().toString());

		// Get the instance variable nodes 
		Collection<FieldDeclaration> instanceVariableNodes = new Vector<FieldDeclaration>();
		pClassNode.accept(new InstanceVariableVisitor(instanceVariableNodes));

		classBean.setTextContent(pClassNode.toString());

		try {
			for(IPackageFragment pack: project.getPackageFragments()) {
				for(ICompilationUnit cu: pack.getCompilationUnits()) {
					for(IType t: cu.getTypes()) {
						if(t.getElementName().equals(pClassNode.getName().toString())) {
							PackageBean packageBean=new PackageBean();
							packageBean.setName(pack.getElementName());
							classBean.setBelongingPackage(packageBean);
						}
					}
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}

		classBean.setLOC(countLines(pClassNode.toString()));

		/*// Get the instance variable beans from the instance variable nodes
		Collection<InstanceVariableBean> instanceVariableBeans = new Vector<InstanceVariableBean>();
		for (FieldDeclaration instanceVariableNode : instanceVariableNodes)
			instanceVariableBeans.add(InstanceVariableParser.parse(instanceVariableNode));

		// Set the collection of instance variables
		classBean.setInstanceVariables(instanceVariableBeans);
		 */
		ArrayList<MethodBean> methods=new ArrayList<MethodBean>();
		// Get the method nodes
		MethodDeclarationsVisitor methodVisitor=new MethodDeclarationsVisitor();
		pClassNode.accept(methodVisitor);

		for(MethodDeclaration m: methodVisitor.getMethods()) {
			MethodBean methodBean = new MethodBean();
			methodBean.setName(m.getName().toString());
			methods.add(methodBean);
		}
		
		classBean.setMethods(methods);

		// Get the method beans from the method nodes
		/*Collection<MethodBean> methodBeans = new Vector<MethodBean>();
		for (MethodDeclaration methodNode : methodNodes)
			methodBeans.add(MethodParser.parse(methodNode, instanceVariableBeans));

		// Iterate over the collection of methods
		for (MethodBean classMethod : methodBeans) {

			// Instantiate a collection of class-defined invocations
			Collection<MethodBean> definedInvocations = new Vector<MethodBean>();

			// Get the method invocations
			Collection<MethodBean> classMethodInvocations = classMethod.getMethodCalls();

			// Iterate over the collection of method invocations
			for (MethodBean classMethodInvocation : classMethodInvocations) {

				// If the method is defined into the class, add to the collection of class-defined invocations
				MethodBean definedInvocation = isInto(classMethodInvocation, methodBeans);
				if (definedInvocation != null)
					definedInvocations.add(definedInvocation);
			}

			// Set the class-defined invocations
			classMethod.setMethodCalls(definedInvocations);

		}

		// Set the collection of methods
		classBean.setMethods(methodBeans);*/

		return classBean;

	}

	private static MethodBean isInto(MethodBean pClassMethodInvocation, Collection<MethodBean> pMethodBeans) {

		// Iterate over the collection of methods
		for (MethodBean methodBean : pMethodBeans) {

			// If there is a method with the same name, return it
			if (methodBean.getName().equals(pClassMethodInvocation.getName()))
				return methodBean;
		}

		// No correspondence found
		return null;

	}

	private static int countLines(String str){
		String[] lines = str.split("\r\n|\r|\n");
		return  lines.length;
	}
}
