package eu.dnetlib.dlms.impl.daos;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openrdf.model.Value;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import eu.dnetlib.dlms.impl.hibobjects.RepositoryWrapper;
import eu.dnetlib.dlms.lowlevel.LowLevelException;
import eu.dnetlib.dlms.lowlevel.objects.Set;
import eu.dnetlib.dlms.lowlevel.objects.SetDAO;
import eu.dnetlib.dlms.lowlevel.objects.structures.Structure;
import eu.dnetlib.dlms.lowlevel.types.AtomType;
import eu.dnetlib.dlms.lowlevel.types.AtomTypeDAO;
import eu.dnetlib.dlms.lowlevel.types.SetType;
import eu.dnetlib.dlms.lowlevel.types.SetTypeDAO;
import eu.dnetlib.dlms.union.objects.UnionSet;
import eu.dnetlib.dlms.union.types.UnionSetType;
import eu.dnetlib.dlms.union.types.UnionSetTypeDAO;
import eu.dnetlib.dlms.union.types.UnionType;
import eu.dnetlib.dlms.union.types.UnionTypeDAO;

/**
 * @author lexis
 * 
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ExtUnionSetDAOHibernateTest {

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(ExtUnionSetDAOHibernateTest.class);

	@Resource
	private ExtUnionSetDAOHibernate extUnionSetDAO;
	@Resource
	private RepositoryWrapper repositoryWrapper;

	/** DAO for Set. */
	@Resource
	private SetDAO extSetDAO;
	/** DAO for UnionType. */
	@Resource
	private UnionTypeDAO unionTypeDAO;
	/** DAO for AtomTypes. */
	@Resource
	private AtomTypeDAO atomTypeDAO;
	/** DAO for SetType. */
	@Resource
	private SetTypeDAO setTypeDAO;
	/** DAO for UnionSetType. */
	@Resource
	private UnionSetTypeDAO unionSetTypeDAO;
	/** AtomTypes. */
	@Resource
	private AtomType atomType1;
	/** The UnionType. */
	@Resource
	private UnionType unionType;

	/**
	 * SetTypes for Sets that contain atoms. setType1 has contentType atomType1
	 */
	@Resource
	private SetType setType1;
	/** The union set type. */
	@Resource
	private UnionSetType unionSetType;

	/**
	 * Sets to contain atoms. atomSet1 has setType setType1.
	 */
	@Resource
	private Set atomSet1;

	/** The union set. */
	private UnionSet unionSet;

	/**
	 * Before each methods save all needed entities to work with a union set.
	 * 
	 * @throws RepositoryException
	 * 
	 * @throws RepositoryException
	 */
	@Before
	public void init() throws RepositoryException {
		this.atomTypeDAO.save(this.atomType1);
		this.setTypeDAO.save(this.setType1);
		this.extSetDAO.save(this.atomSet1);
		this.unionType.addType(this.atomType1);
		this.unionTypeDAO.save(this.unionType);
		this.unionSetType.addSetType(this.setType1);
		this.unionSetTypeDAO.save(this.unionSetType);
		this.logTriples();
	}

	public void logTriples() {
		try {
			final RepositoryConnection c = this.repositoryWrapper.getConnection();
			final RepositoryResult<org.openrdf.model.Statement> res = c.getStatements(null, null, (Value) null, false);
			int count = 0;
			while (res.hasNext()) {
				log.debug(res.next());
				count++;
			}
			log.debug("Total number of triples: " + count);
			res.close();
		} catch (final Exception e) {
			throw new LowLevelException(e);
		}
	}

	/**
	 * Test method for
	 * {@link eu.dnetlib.dlms.impl.daos.ExtUnionSetDAOHibernate#delete(eu.dnetlib.dlms.union.objects.UnionSet)}.
	 * 
	 * @throws RepositoryException
	 */
	@Test
	@DirtiesContext
	public void testDeleteUnionSet() throws RepositoryException {
		log.info(this.getClass() + ".testSaveUnionSet");
		this.unionSet = this.extUnionSetDAO.create();
		this.unionSet.setObjectType(this.unionSetType);
		this.unionSet.addSet(this.atomSet1);
		this.unionSet.setInfo("UnionSetForSave");
		this.extUnionSetDAO.save(this.unionSet);
		this.logTriples();
		//let's check if there is an entry for unionSet in systemUnionSets:
		Structure struct = this.extUnionSetDAO.getSystemSetHelper().findSystemStructureFor(this.unionSet);
		assertNotNull(struct);
		//now let's delete the unionSet:
		this.extUnionSetDAO.delete(this.unionSet);
		struct = this.extUnionSetDAO.getSystemSetHelper().findSystemStructureFor(this.unionSet);
		assertNull(struct);
		this.logTriples();
		log.info("-----------------------------------");
	}

	/**
	 * Test method for
	 * {@link eu.dnetlib.dlms.impl.daos.ExtUnionSetDAOHibernate#save(eu.dnetlib.dlms.union.objects.UnionSet)}.
	 * 
	 * @throws RepositoryException
	 */
	@Test
	@DirtiesContext
	public void testSaveUnionSet() throws RepositoryException {
		log.info(this.getClass() + ".testSaveUnionSet");
		this.logTriples();
		this.unionSet = this.extUnionSetDAO.create();
		this.unionSet.setObjectType(this.unionSetType);
		this.unionSet.addSet(this.atomSet1);
		this.unionSet.setInfo("UnionSetForSave");
		this.extUnionSetDAO.save(this.unionSet);
		this.logTriples();
		//let's check if there is an entry for unionSet in systemUnionSets:
		final Structure struct = this.extUnionSetDAO.getSystemSetHelper().findSystemStructureFor(this.unionSet);
		assertNotNull(struct);
		log.info("-----------------------------------");
	}

}
