package jdepend.util.analyzer.element;

import java.util.Collection;
import java.util.HashSet;

import jdepend.metadata.JavaClass;
import jdepend.metadata.Method;
import jdepend.model.JavaClassUnit;
import jdepend.model.result.AnalysisResult;
import jdepend.util.analyzer.framework.AbstractAnalyzer;
import jdepend.util.analyzer.framework.Analyzer;
import jdepend.util.analyzer.framework.AnalyzerException;

public class IdentifyCallback extends AbstractAnalyzer {

	private static final long serialVersionUID = -4566409232231165490L;

	public IdentifyCallback() {
		super("Callback识别", Analyzer.Attention, "识别在组件中设置Callback的情况");
	}

	@Override
	protected void doExecute(AnalysisResult result) throws AnalyzerException {

		boolean isCallback1;// 该类为接口，并且其方法有返回值，该方法被本组件调用
		boolean isCallback2;// 该类的实现类不与该类处于一个组件内
		boolean isCallback3;// 实现类的构造过程不在该组件内

		Method callbackMethod = null;
		Method method1 = null;
		JavaClass subClass2 = null;
		Collection<Method> method3s = null;

		for (JavaClassUnit javaClass : result.getClasses()) {
			isCallback1 = false;
			if (javaClass.getJavaClass().isInterface()) {
				L: for (Method method : javaClass.getJavaClass().getSelfMethods()) {
					if (method.existReturn()) {
						for (Method invokedMethod : method.getInvokedMethods()) {
							if (result.getTheClass(invokedMethod.getJavaClass().getId()).getComponent()
									.equals(javaClass.getComponent())) {
								callbackMethod = method;
								method1 = invokedMethod;
								isCallback1 = true;
								break L;
							}
						}
					}
				}
			}
			isCallback2 = false;
			isCallback3 = false;
			if (isCallback1) {
				M: for (JavaClass subClass : javaClass.getJavaClass().getSubClasses()) {
					if (!result.getTheClass(subClass.getId()).getComponent().equals(javaClass.getComponent())) {
						isCallback2 = true;
						subClass2 = subClass;

						isCallback3 = true;
						method3s = new HashSet<Method>();
						for (Method method : subClass.getConstructorMethods()) {
							for (Method invokedMethod : method.getInvokedMethods()) {
								if (result.getTheClass(invokedMethod.getJavaClass().getId()).getComponent()
										.equals(javaClass.getComponent())) {
									isCallback3 = false;
									break M;
								}
								method3s.add(invokedMethod);
							}
						}
					}
				}
			}
			if (isCallback2 && isCallback3) {
				this.print("\nComponent:" + javaClass.getComponent().getName() + "\n");
				this.print("Callback : " + javaClass.getName() + "." + callbackMethod.getName() + "\n");
				this.printTab();
				this.print("is Invoked Method : " + method1.getJavaClass().getName() + "." + method1.getName() + "\n");
				this.printTab();
				this.print("have subClass : " + subClass2.getName() + " Constructors InvokedMethods:\n");
				for (Method method : method3s) {
					this.printTab();
					this.printTab();
					this.print("Invoked Method : " + method.getJavaClass().getName() + "." + method.getName() + "\n");
				}

			}
		}

	}

	@Override
	public String getExplain() {
		StringBuilder explain = new StringBuilder();
		explain.append("当一个组件中内置了Callback后，其测试结果依赖于Callback接口的实例化类，这会增加测试的难度和组件运行时的不确定性。<br>");
		explain.append("识别Callback的规则是：<br>");
		explain.append("1、该类为接口，并且其方法有返回值，该方法被本组件调用<br>");
		explain.append("2、该类的实现类不与该类处于一个组件内<br>");
		explain.append("3、实现类的构造过程不在该组件内<br>");
		return explain.toString();
	}

}
