package jp.sourceforge.asclipse.as3;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import jp.sourceforge.asclipse.as3.ParserUtil.AS3ParserException;
import jp.sourceforge.asclipse.as3.element.AS3Root;
import jp.sourceforge.asclipse.as3.element.AS3Type;

/**
 * 解析されたツリーをソースフォルダ単位で保持する。
 * @author shin1ogawa
 */
public interface IAS3Context extends Serializable {

	/**
	 * 対応するファイルシステムのルートを返す。
	 * <p>TopLevel等の組み込み系は{@code null}を返す。</p>
	 * @return 対応するファイルシステムのルート
	 */
	String getRootFolder();

	/**
	 * 構築済みのツリーを追加する。
	 * <p>登録済みのリスナがあれば、通知する。</p>
	 * @param root ツリーのルート要素
	 */
	void addAS3Root(AS3Root root);

	/**
	 * ツリーを削除する。
	 * <p>登録済みのリスナがあれば、通知する。</p>
	 * @param root ツリーのルート要素
	 */
	void removeAS3Root(AS3Root root);

	/**
	 * 保持しているツリーのリストを返す。
	 * @return 保持しているツリーのリスト
	 */
	List<AS3Root> getAS3Roots();

	/**
	 * @param resourceName parse時に設定したリソース名
	 * @return リソース名に対応する{@link AS3Root}。見つからない場合は{@code null}
	 */
	AS3Root getAS3Root(String resourceName);

	/**
	 * リソースを解析し、構築したツリーのルート要素を返す。
	 * <p>内部的に{@link #addAS3Root(AS3Root)}も実行される。</p>
	 * <p>また、指定されたリソースに対応する{@link AS3Root}が存在した場合はそれを破棄し、新たに解析しなおす。</p>
	 * @param globalContext {@link IAS3GlobalContext}
	 * @param input 入力
	 * @param resourceName ルートフォルダからの相対パス
	 * @return 解析し、構築したツリーのルート要素
	 * @throws AS3ParserException 
	 */
	AS3Root parseInput(IAS3GlobalContext globalContext, InputStream input, String resourceName)
			throws AS3ParserException;

	/**
	 * ルートフォルダ配下のリソースを解析し、構築したツリーのルート要素を返す。
	 * <p>内部的に{@link #addAS3Root(AS3Root)}も実行される。</p>
	 * <p>リソースファイル名として、ルートフォルダからの相対パスが設定される。
	 * また、指定されたリソースに対応する{@link AS3Root}が存在した場合はそれを破棄し、新たに解析しなおす。</p>
	 * @param globalContext {@link IAS3GlobalContext}
	 * @param file 対象ファイル
	 * @return 解析し、構築したツリーのルート要素
	 * @throws AS3ParserException 
	 * @throws FileNotFoundException 
	 */
	AS3Root parseFile(IAS3GlobalContext globalContext, File file) throws AS3ParserException,
			FileNotFoundException;

	/**
	 * @return 保持しているツリー内から、全ての型を返す。
	 */
	Collection<AS3Type> getAllTypes();

	/**
	 * @param packageName
	 * @return 指定されたパッケージに存在する全ての型
	 */
	List<AS3Type> getTypesInPackage(String packageName);

	/**
	 * 指定された型名に一致する{@link AS3Type}を返す。
	 * @param qualifiedName
	 * @return 指定された型名に一致する{@link AS3Type}
	 */
	AS3Type getTypeElement(String qualifiedName);

	/**
	 * ツリー要素の変更を監視するリスナを追加する。
	 * @param listener
	 */
	void addListener(IAS3ContextListener listener);

	/**
	 * ツリー要素の変更を監視するリスナを削除する。
	 * @param listener
	 */
	void removeListener(IAS3ContextListener listener);


//	/**
//	 * {@link AS3TypeRef}が参照している型を解決する。
//	 * @param typeRef
//	 * @return 保持しているツリーのリスト内から解決できなければ{@code false}
//	 */
//	boolean resolve(AS3TypeRef typeRef);

	/**
	 * ツリー要素の変更を監視するリスナのインターフェース。
	 * @author shin1ogawa
	 */
	static interface IAS3ContextListener {

		void added(AS3Root root);

		void removed(AS3Root root);
	}
}
