package ash.reverse.struct;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

/**
 * 複数要素の集合を管理する抽象クラス<br>
 * ★CompositeパターンのCompositeの役割を果たす。
 */
public abstract class GroupRecord extends ObjectRecord {
	List<ObjectRecord> members = new ArrayList<ObjectRecord>();
	public List<ObjectRecord> members() { return members; }

	GroupRecord(String type, String name, int lineno, GroupRecord owner) {
		super(type, name, lineno, owner);
	}

	/** 所属メンバを登録する。 */
	public void addMember(ObjectRecord member) {
		members.add(member);
	}

	/**
	 * このグループのメンバーから参照できる型を得る。
	 * 参照スコープの内側からファイルのスコープまで順番に探索し、
	 * 見つからなかったらnullを返す。
	 * このグループの直下の型の型名から型情報を見つける。
	 * @param name 型名
	 * @return 型情報（見つからなかったらnull）
	 */
	public ClassRecord findType(String name) {
		//trace("\t" + name + ": " + getTypes().get(name));
		ClassRecord crec = getTypes().get(name);
		if(crec != null) return crec;
		if(owner() == null) return null;
		return owner().findType(name);
	}

	private Map<String,ClassRecord> typeMap;
	/**
	 * このグループの直下の型の型名と型情報のマップを返す。
	 * @return 型名と型情報のマップ
	 */
	private Map<String,ClassRecord> getTypes() {
		if(typeMap != null) return typeMap;
		typeMap = new HashMap<String,ClassRecord>();
		for(ObjectRecord rec : members) {
			if(rec instanceof ClassRecord) {
				//trace(name + ": " + rec.name);
				typeMap.put(rec.name, (ClassRecord)rec);
			}
		}
		return typeMap;
	}

	/**
	 * このグループに含まれる型階層を表示するデバッグ用のメソッド。
	 * @param prefix 表示の行頭に付ける文字列
	 */
	public void printTypes(String prefix) {
		trace(prefix + name);
		for(ObjectRecord rec : members()) {
			if(rec instanceof ClassRecord) {
				((ClassRecord)rec).printTypes(prefix + "\t");
			}
		}
	}

	/** このグループに含まれるすべてのメソッドを集計する。 */
	@Override protected int countMethods() {
		int n = 0;
		for(ObjectRecord rec : members) n += rec.countMethods();
		return n;
	}

	/** このグループに含まれるすべてのメソッド行数を集計する。 */
	@Override protected int sumMethodLoc() {
		int sum = 0;
		for(ObjectRecord rec : members) sum += rec.sumMethodLoc();
		return sum;
	}
}
