package jp.sourceforge.asclipse.as3.adapter;

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

import java.io.FileNotFoundException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import jp.sourceforge.asclipse.as3.IAS3GlobalContext;
import jp.sourceforge.asclipse.as3.TestUtil;
import jp.sourceforge.asclipse.as3.ParserUtil.AS3ParserException;
import jp.sourceforge.asclipse.as3.element.AS3Type;
import jp.sourceforge.asclipse.as3.internal.DefaultAS3GlobalContext;
import jp.sourceforge.asclipse.as3.resolver.AS3TypeRef;

import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link TypeHierarchyProvider}のテストケース。
 * @author shin1ogawa
 */
public class TypeHierarchyProviderTest {

	static final Logger logger = LoggerFactory.getLogger(TypeHierarchyProviderTest.class);

	static IAS3GlobalContext globalContext;


	// public class ClassA
	// public class InterfaceC
	// pkgA/public abstract class ClassB implements InterfaceC
	// pkgA/public class ClassD extends ClassB

	/**
	 * {@link TypeHierarchyProvider#getSuperType()}
	 * <p>D->B->Object</p>
	 */
	@Test
	public void test01() {
		AS3Type typeD = TestUtil.findType(globalContext, "pkgA.ClassD");
		assertThat(typeD, notNullValue());
		TypeHierarchyProvider adapterD = new TypeHierarchyProvider(globalContext);
		typeD.addAdapter(adapterD);
		AS3TypeRef superOfD = adapterD.getSuperType();
		assertThat(superOfD, notNullValue());
		assertThat(superOfD.isResolved(), is(true));
		assertThat(superOfD.getResolvedType(), notNullValue());
		assertThat(superOfD.getResolvedType().getQualifiedName(), is("pkgA.ClassB"));

		AS3Type typeB = superOfD.getResolvedType();
		TypeHierarchyProvider adapterB = new TypeHierarchyProvider(globalContext);
		typeB.addAdapter(adapterB);
		AS3TypeRef superOfB = adapterB.getSuperType();
		assertThat(superOfB, notNullValue());
		assertThat(superOfB, is(AS3TypeRef.OBJECT_TYPE_REF));
	}

	// pkgA/public interface InterfaceE extends InterfaceC
	// pkgB/public class ClassF extends ClassD implements InterfaceE

	/**
	 * {@link TypeHierarchyProvider#getSuperTypes()}
	 */
	@Test
	public void test02() {
		AS3Type typeF = TestUtil.findType(globalContext, "pkgB.ClassF");
		assertThat(typeF, notNullValue());
		TypeHierarchyProvider adapterF = new TypeHierarchyProvider(globalContext);
		typeF.addAdapter(adapterF);
		List<AS3TypeRef> superTypesF = adapterF.getSuperTypes();
		assertThat(superTypesF.size(), is(2));
		AS3TypeRef typeRefD = superTypesF.get(0);
		assertThat(typeRefD.isResolved(), is(true));
		assertThat(typeRefD.getQualifiedName(), is("pkgA.ClassD"));
		AS3TypeRef typeRefE = superTypesF.get(1);
		assertThat(typeRefE.isResolved(), is(true));
		assertThat(typeRefE.getQualifiedName(), is("pkgA.InterfaceE"));

		TypeHierarchyProvider adapterE = new TypeHierarchyProvider(globalContext);
		typeRefE.getResolvedType().addAdapter(adapterE);
		List<AS3TypeRef> superTypesE = adapterE.getSuperTypes();
		assertThat(superTypesE.size(), is(1));
		AS3TypeRef typeRefC = superTypesE.get(0);
		assertThat(typeRefC.isResolved(), is(true));
		assertThat(typeRefC.getQualifiedName(), is("InterfaceC"));
	}

	/**
	 * {@link TypeHierarchyProvider#getSubTypes()}
	 */
	@Test
	public void test03() {
		AS3Type typeC = TestUtil.findType(globalContext, "InterfaceC");
		TypeHierarchyProvider adapterC = new TypeHierarchyProvider(globalContext);
		typeC.addAdapter(adapterC);
		List<AS3TypeRef> subTypes = adapterC.getSubTypes();
		assertThat(subTypes.size(), is(2));
		Collections.sort(subTypes, new Comparator<AS3TypeRef>() {

			public int compare(AS3TypeRef o1, AS3TypeRef o2) {
				if (o1 == null) {
					return -1;
				}
				if (o2 == null) {
					return 1;
				}
				return o1.getQualifiedName().compareTo(o2.getQualifiedName());
			}
		});
		AS3TypeRef typeRefB = subTypes.get(0);
		assertThat(typeRefB.isResolved(), is(true));
		assertThat(typeRefB.getResolvedType().getQualifiedName(), is("pkgA.ClassB"));
		AS3TypeRef typeRefE = subTypes.get(1);
		assertThat(typeRefE.isResolved(), is(true));
		assertThat(typeRefE.getResolvedType().getQualifiedName(), is("pkgA.InterfaceE"));
	}

	/**
	 * テスト用のソースフォルダ配下を取り込む。
	 * @throws FileNotFoundException
	 * @throws AS3ParserException
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws FileNotFoundException, AS3ParserException {
		globalContext = new DefaultAS3GlobalContext();
		globalContext.addContext(TestUtil.createAS3Context(globalContext,
				"src/test/resources/sampleprj"));
	}
}
