package ash.reverse.struct;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.HashSet;
import ash.reverse.struct.ObjectAggregator;

/**
 * １つのJavaソースファイルに対して以下の情報を管理する。
 * <ul>
 * <li> パッケージ名
 * <li> このファイルで定義されたクラス・インタフェース・列挙型等の型情報のリスト
 * <li> これらの型の実装で参照される型を特定するために必要なパッケージ情報のリスト
 * </ul>
 * import文で型名が明示されたパッケージは型名とパッケージ名のマップで管理する。
 * オンデマンド型宣言のimport文に対してはパッケージ名をセットで管理する。
 * 
 */
public class FileRecord extends GroupRecord {
	private Set<String> onDemandSet = new HashSet<String>();
	public Set<String> onDemandSet() { return onDemandSet; }
	private Map<String,String> typePkgMap = new LinkedHashMap<String,String>();
	public Map<String,String> typePkgMap() { return typePkgMap; }
	private String pkgname = "";
	public void pkgname(String pkgname) { this.pkgname = pkgname; }
	public String pkgname() { return pkgname; }
	@Override public String fqcn() { return pkgname; }

	public FileRecord(String name) {
		super("file", name, 1, null);
	}

	/**
	 * import文で宣言された型とその型が定義されているパッケージ情報を登録する。
	 * import文は単一型宣言(import a.b.T)とオンデマンド型宣言(import a.b.*)の
	 * 二つの形式がある。単一型宣言の場合はtypePkgMapに型名とパッケージ名を、
	 * オンデマンド型宣言の場合は、onDemandSetにパッケージ名を登録する。
	 * staticインポート宣言は無視する。
	 * @param importDecl
	 */
	public void addImportDecl(String importDecl) {
		String tokens[] = importDecl.split("\\s+");
		String decl = tokens[0];
		if(!decl.equals("static")) {
			int index = decl.lastIndexOf('.');
			String pkg = decl.substring(0, index);
			String typeName = decl.substring(index+1);
			if(typeName.equals("*")) {
				onDemandSet.add(pkg);
			} else {
				typePkgMap.put(typeName, pkg);
			}
		}
	}
	/**
	 * 型名からパッケージを得る。
	 * @param typeName 型名
	 */
	public String getPackage(String typeName) {
		return typePkgMap.get(typeName);
	}

	public String fqcn(String name) {
		String pkgname = typePkgMap.get(name);
		return (pkgname != null) ? (pkgname + "." + name) : null;
	}

	/**
	 * パッケージの集計情報を出力する。
	 * @param aggregator 規模情報の集計と出力を行うアグリゲータ
	 * @param pre アグリゲータのタイトル表示のプレフィックス
	 */
	public void printTitle(ObjectAggregator aggregator, String pre) {
		if(name == null) return;
		// ファイル名、全行数、有効行数、クラス数、メソッド数、メソッド行数
		aggregator.print(pre + name, endLine, loc, 
						 members.size(), countMethods(), sumMethodLoc());
	}

	/**
	 * Visitorパターンの受け入れ側メソッド。訪問者を受け入れる。
	 * @param visitor このファイル記録を閲覧したい訪問者
	 */
	@Override public void accept(ObjectVisitor visitor) {
		visitor.visit(this);
	}
}
