package org.ntlab.traceanalyzer;

import java.util.ArrayList;
import java.util.HashSet;

import org.ntlab.trace.MethodExecution;

public class MarkedMethodExecution {
	private MethodExecution methodExecution;
	private ArrayList<MarkedMethodExecution> children = null;
	private int uniqueMethodInvokedFrom = 0;
	
	public MarkedMethodExecution(MethodExecution methodExecution) {
		this.methodExecution = methodExecution;
	}

	public void addChild(MarkedMethodExecution child) {
		if (children == null) {
			children = new ArrayList<MarkedMethodExecution>();
		}
		children.add(child);
	}
	
	public ArrayList<MarkedMethodExecution> getChildren() {
		if (children == null) {
			ArrayList<MethodExecution> rawChildren = methodExecution.getChildren();
			children = new ArrayList<MarkedMethodExecution>();
			for (int i = 0; i < rawChildren.size(); i++) {
				children.add(0, new MarkedMethodExecution(rawChildren.get(i)));
			}
		}
		return children;
	}

	public Object getParent() {
		return methodExecution.getParent();
	}

	public String getSignature() {
		return methodExecution.getSignature();
	}
	
	public String getDeclaringClassName() {
		return methodExecution.getDeclaringClassName();
	}
	
	public String getReceiverClassName() {
		return methodExecution.getThisClassName();
	}

	/**
	 * マーク固有のメソッドが呼び出されたかどうかを調べる
	 * @param commonMethodSignatures マーク外で呼び出された全メソッドのシグニチャ
	 */
	public int searchUniqueMethodInvocation(HashSet<String> commonMethodSignatures) {
		if (uniqueMethodInvokedFrom  > 0) return uniqueMethodInvokedFrom;
		if (isUniqueMethod(commonMethodSignatures)) uniqueMethodInvokedFrom = 2;
		ArrayList<MarkedMethodExecution> children = getChildren();
		for (int i = 0; i < children.size(); i++) {
			int u = children.get(i).searchUniqueMethodInvocation(commonMethodSignatures);
			if (uniqueMethodInvokedFrom == 0 && u > 0) uniqueMethodInvokedFrom = 1;
		}
		return uniqueMethodInvokedFrom;
	}

	/**
	 * マーク固有のメソッド実行をすべて取得する
	 * @param commonMethodSignatures マーク外で実行された全メソッドのシグニチャ
	 * @return このメソッド実行以下のマーク固有の全メソッド実行
	 */
	public void getUniqueMethodExecutions(HashSet<String> commonMethodSignatures, ArrayList<MarkedMethodExecution> uniqueMethodExecutions) {
		if (isUniqueMethod(commonMethodSignatures)) {
			uniqueMethodExecutions.add(this);
		}
		for (int n = 0; n < children.size(); n++) {
			children.get(n).getUniqueMethodExecutions(commonMethodSignatures, uniqueMethodExecutions);
		}
	}
	
	/**
	 * このメソッド実行からマーク固有のメソッドが呼び出されたか?
	 * @return 0: 呼び出されていない, 1: 呼び出された, 2: 自分自身がマーク固有メソッド
	 */
	public int isUniqueMethodInvokedFrom() {
		return uniqueMethodInvokedFrom;
	}

	private boolean isUniqueMethod(HashSet<String> commonMethodSignatures) {
		return !commonMethodSignatures.contains(getSignature());
	}
}
