package jp.sourceforge.asclipse.as3;

import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Collection;

import jp.sourceforge.asclipse.as3.ParserUtil.AS3ParserException;
import jp.sourceforge.asclipse.as3.adapter.TypeHierarchyProviderTest;
import jp.sourceforge.asclipse.as3.element.AS3Root;
import jp.sourceforge.asclipse.as3.element.AS3Type;
import jp.sourceforge.asclipse.as3.internal.DefaultAS3Context;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * テストの為のユーティリティクラス。
 * @author shin1ogawa
 */
public class TestUtil {

	static Logger logger = LoggerFactory.getLogger(TestUtil.class);

	static IAS3Context builtinContext;


	private TestUtil() {
	}

	/**
	 * ビルトインクラスを読み込む。
	 * <p>時間がかかるのがうっとうしいのでキャッシュしておく。</p>
	 * @return 読み込んだビルトインクラス一式を保持する{@link IAS3Context}
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static IAS3Context readBuiltinClasses() throws IOException, ClassNotFoundException {
		if (builtinContext != null) {
			return builtinContext;
		}
		ObjectInputStream objectInputStream = null;
		try {
			objectInputStream =
					new ObjectInputStream(TypeHierarchyProviderTest.class
						.getResourceAsStream("/builtin.ser"));
			long currentTimeMillis = System.currentTimeMillis();
			logger.debug("builtin.ser 読み込み開始");
			builtinContext = (IAS3Context) objectInputStream.readObject();
			logger.debug("builtin.ser 読み込み終了[ms]="
					+ (System.currentTimeMillis() - currentTimeMillis));
			return builtinContext;
		} finally {
			if (objectInputStream != null) {
				objectInputStream.close();
			}
		}
	}

	/**
	 * フォルダ配下の{@literal *.as"}ファイルを解析し、{@link IAS3Context}を作成する。
	 * @param globalContext
	 * @param folderName
	 * @return 作成した{@link IAS3Context}
	 */
	public static IAS3Context createAS3Context(IAS3GlobalContext globalContext, String folderName) {
		File rootFolder = new File(folderName);
		if (!rootFolder.exists() || !rootFolder.isDirectory()) {
			throw new IllegalArgumentException(rootFolder.getAbsolutePath());
		}
		IAS3Context as3context = new DefaultAS3Context(folderName);
		parseFolder(globalContext, as3context, rootFolder, rootFolder);
		return as3context;
	}

	private static void parseFolder(IAS3GlobalContext globalContext, IAS3Context context,
			File rootFolder, File parent) {
		File[] files = parent.listFiles(new FileFilter() {

			public boolean accept(File pathname) {
				return pathname.isDirectory() || pathname.getAbsolutePath().endsWith(".as") ? true
						: false;
			}
		});
		if (files != null) {
			for (File file : files) {
				if (file.isDirectory()) {
					parseFolder(globalContext, context, rootFolder, file);
				} else {
					AS3Root root = null;
					try {
						root = context.parseFile(globalContext, file);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (AS3ParserException e) {
						e.printStackTrace();
					}
					assertThat(root, notNullValue());
					assertThat(root.hasParserError(), is(false));
				}
			}
		}
	}

	/**
	 * {@link IAS3GlobalContext}が保持する型の一覧から、特定のQualifiedNameを持つ型を返す。
	 * @param context
	 * @param qualifiedName
	 * @return 指定されたQualifiedNameに対応する{@link AS3Type}
	 */
	public static AS3Type findType(IAS3GlobalContext context, String qualifiedName) {
		Collection<AS3Type> allTypes = context.getAllTypes();
		for (AS3Type type : allTypes) {
			if (qualifiedName.equals(type.getQualifiedName())) {
				return type;
			}
		}
		return null;
	}
}
