package dst.ass1.jpa.tests;

import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.isA;
import static org.hamcrest.object.IsCompatibleType.typeCompatibleWith;
import static org.junit.Assert.assertThat;

import java.util.List;

import javax.persistence.EntityTransaction;

import org.junit.ClassRule;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.junit.runners.MethodSorters;

import dst.ass1.jpa.ITestData;
import dst.ass1.jpa.ORMService;
import dst.ass1.jpa.dao.ICourseDAO;
import dst.ass1.jpa.dao.ICoursePlatformDAO;
import dst.ass1.jpa.dao.IDAOFactory;
import dst.ass1.jpa.dao.ILecturerDAO;
import dst.ass1.jpa.dao.ILessonDAO;
import dst.ass1.jpa.dao.IMaterialDAO;
import dst.ass1.jpa.dao.IMaterialServerDAO;
import dst.ass1.jpa.dao.IMembershipDAO;
import dst.ass1.jpa.dao.IMetadataDAO;
import dst.ass1.jpa.dao.IParticipantDAO;
import dst.ass1.jpa.model.IAddress;
import dst.ass1.jpa.model.ICourse;
import dst.ass1.jpa.model.ICoursePlatform;
import dst.ass1.jpa.model.IEnrollment;
import dst.ass1.jpa.model.IEnrollmentKey;
import dst.ass1.jpa.model.ILecturer;
import dst.ass1.jpa.model.ILesson;
import dst.ass1.jpa.model.IMaterial;
import dst.ass1.jpa.model.IMaterialServer;
import dst.ass1.jpa.model.IMembership;
import dst.ass1.jpa.model.IMetadata;
import dst.ass1.jpa.model.IModelFactory;
import dst.ass1.jpa.model.IParticipant;

/**
 * Tests the basic setup of the model and dao factory (makes sure they don't return null), and also tests whether all
 * relevant entities have been mapped at all and test data can be inserted.
 */
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Ass1_1_1_00Test {

    @ClassRule
    public static ORMService orm = new ORMService();

    @Rule
    public ErrorCollector err = new ErrorCollector();

    @Test
    public void test01_modelFactoryReturnsThings() {
        IModelFactory modelFactory = orm.getModelFactory();

        err.checkThat(modelFactory.createAddress(), isA(IAddress.class));
        err.checkThat(modelFactory.createCourse(), isA(ICourse.class));
        err.checkThat(modelFactory.createCoursePlatform(), isA(ICoursePlatform.class));
        err.checkThat(modelFactory.createEnrollment(), isA(IEnrollment.class));
        err.checkThat(modelFactory.createEnrollmentKey(), isA(IEnrollmentKey.class));
        err.checkThat(modelFactory.createLecturer(), isA(ILecturer.class));
        err.checkThat(modelFactory.createLesson(), isA(ILesson.class));
        err.checkThat(modelFactory.createMaterial(), isA(IMaterial.class));
        err.checkThat(modelFactory.createMaterialServer(), isA(IMaterialServer.class));
        err.checkThat(modelFactory.createMembership(), isA(IMembership.class));
        err.checkThat(modelFactory.createMetadata(), isA(IMetadata.class));
        err.checkThat(modelFactory.createParticipant(), isA(IParticipant.class));
    }

    @Test
    public void test02_daoFactoryReturnsThings() {
        IDAOFactory daoFactory = orm.getDaoFactory();

        err.checkThat(daoFactory.createMembershipDAO(), isA(IMembershipDAO.class));
        err.checkThat(daoFactory.createParticipantDAO(), isA(IParticipantDAO.class));
        err.checkThat(daoFactory.createLessonDAO(), isA(ILessonDAO.class));
        err.checkThat(daoFactory.createLecturerDAO(), isA(ILecturerDAO.class));
        err.checkThat(daoFactory.createCourseDAO(), isA(ICourseDAO.class));
        err.checkThat(daoFactory.createMaterialDAO(), isA(IMaterialDAO.class));
        err.checkThat(daoFactory.createMaterialServerDAO(), isA(IMaterialServerDAO.class));
        err.checkThat(daoFactory.createMetadataDAO(), isA(IMetadataDAO.class));
        err.checkThat(daoFactory.createCoursePlatformDAO(), isA(ICoursePlatformDAO.class));
    }

    @Test
    public void test03_entityTypesManagedCorrectly() throws Exception {
        List<Class<?>> types = orm.getDatabaseGateway().getManagedJavaTypes();

        assertThat("No managed types found", types.isEmpty(), is(false));
        System.out.println("Managed types: " + types);
        err.checkThat(types, hasItem(typeCompatibleWith(ICourse.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IAddress.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(ICoursePlatform.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IEnrollment.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IEnrollmentKey.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(ILecturer.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(ILesson.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IMaterial.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IMaterialServer.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IMembership.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IMetadata.class)));
        err.checkThat(types, hasItem(typeCompatibleWith(IParticipant.class)));
    }

    @Test
    public void test04_canInsertTestFixture() throws Exception {
        ITestData testData = new TestData();

        EntityTransaction tx = orm.em().getTransaction();
        tx.begin();
        try {
            testData.insert(orm.getModelFactory(), orm.em());
        } catch (Exception e) {
            throw new AssertionError("Exception while inserting test fixture.", e);
        } finally {
            tx.rollback();
        }
    }

}
