package eu.dnetlib.dlms.config;

import static org.junit.Assert.assertTrue;

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.Statement;
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.daos.ExtSetDAOHibernate;
import eu.dnetlib.dlms.impl.hibobjects.RepositoryWrapper;
import eu.dnetlib.dlms.lowlevel.objects.Set;
import eu.dnetlib.dlms.lowlevel.types.ObjType;
import eu.dnetlib.dlms.lowlevel.types.ObjTypeDAO;
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.objects.UnionSetDAO;

/**
 * test class for systemSetsRefresher.
 * 
 * @author lexis
 * 
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SystemSetsRefresherTest {
	/** Logger. */
	private static final Log log = LogFactory.getLog(SystemSetsRefresherTest.class);

	/** Entity under test. */
	@Resource
	private SystemSetsRefresher refresher;
	@Resource
	private ObjTypeDAO objTypeDao;
	@Resource
	private SetTypeDAO setTypeDAO;
	@Resource
	private ExtSetDAOHibernate extSetDAO;
	@Resource
	private RepositoryWrapper repositoryWrapper;
	@Resource
	private UnionSetDAO simpleUnionSetDAO;

	/** Name of the system set whose content is to delete. */
	private String systemSetName = SystemSetsNames.STRUCT_SETS;

	/**
	 * Prepare obj set to delete the System set named SystemObjSets.
	 */
	@Before
	public void setUp() {
		final ObjType ot = this.objTypeDao.create();
		ot.setName("anObjType");
		this.objTypeDao.save(ot);
		final SetType st = this.setTypeDAO.create(ot);
		st.setName("aSet");
		this.setTypeDAO.save(st);
		final Set testSet = this.extSetDAO.create();
		testSet.setObjectType(st);
		this.extSetDAO.save(testSet);
		this.systemSetName = SystemSetsNames.OBJ_SETS;
		final int elsInSetToEmpty = this.refresher.getSimpleSetDAO().getSetByName(this.systemSetName).count();
		log.debug("Elements in set : " + this.systemSetName + " before starting tests = " + elsInSetToEmpty);

	}

	/**
	 * Test method for {@link eu.dnetlib.dlms.config.SystemSetsRefresher#deleteAllContent(java.lang.String)}. Given the
	 * name of a system set, it should delete all its content and relative entries in the system union set.
	 * 
	 * @throws RepositoryException
	 */
	@Test
	@DirtiesContext
	public void testDeleteAllContent() throws RepositoryException {
		UnionSet allSets = this.simpleUnionSetDAO.getUnionSetByName(SystemSetsNames.ALL_SETS);
		this.simpleUnionSetDAO.load(allSets);
		final int countBefore = allSets.count();
		log.debug("Objects in SystemSets before refresher: " + countBefore);
		final int elsInSet = this.extSetDAO.getSetByName(this.systemSetName).count();
		log.debug("Elements in set : " + this.systemSetName + " before deleteAllContent = " + elsInSet);
		this.refresher.deleteAllContent(this.systemSetName);
		final Set systemSet = this.extSetDAO.getSetByName(this.systemSetName);
		this.extSetDAO.load(systemSet);
		assertTrue(systemSet.getObjects().isEmpty());
		allSets = this.simpleUnionSetDAO.getUnionSetByName(SystemSetsNames.ALL_SETS);
		this.simpleUnionSetDAO.load(allSets);
		final int countAfter = allSets.count();
		log.debug("Objects in SystemSets after refresher: " + countAfter);
		final int elsInEmptiedSet = this.extSetDAO.getSetByName(this.systemSetName).count();
		log.debug("Elements in set : " + this.systemSetName + " after deleteAllContent = " + elsInEmptiedSet);
		assertTrue(countBefore > countAfter);

	}

	/**
	 * Test method for {@link eu.dnetlib.dlms.config.SystemSetsRefresher#deleteAllContent(java.lang.String)}. Given the
	 * name of a system set, it should delete all its content and relative entries in the system union set.
	 * 
	 * @throws RepositoryException
	 */
	@Test
	@DirtiesContext
	public void testRefreshSystemSetsContent() throws RepositoryException {
		this.printTriples();
		final int countBefore = this.extSetDAO.getSetByName(SystemSetsNames.ALL_SETS).count();
		RepositoryConnection con = this.repositoryWrapper.getConnection();
		RepositoryResult<Statement> triples = con.getStatements(null, null, null, false);
		triples.close();
		final int countTriplesBefore = triples.asList().size();
		this.repositoryWrapper.closeConnection();
		log.debug("Objects in SystemSets before refresher: " + countBefore + " #TRIPLES: " + countTriplesBefore);
		this.refresher.refreshSystemSetsContent();
		final int countAfter = this.extSetDAO.getSetByName(SystemSetsNames.ALL_SETS).count();
		con = this.repositoryWrapper.getConnection();
		triples = con.getStatements(null, null, null, false);
		final int countTriplesAfter = triples.asList().size();
		triples.close();
		this.repositoryWrapper.closeConnection();
		log.debug("Objects in SystemSets after refresher: " + countAfter + " #TRIPLES: " + countTriplesAfter);
		this.printTriples();
		assertTrue(countBefore == countAfter);
		assertTrue(countTriplesBefore == countTriplesAfter);
	}

	private void printTriples() throws RepositoryException {
		final RepositoryConnection con = this.repositoryWrapper.getConnection();
		final RepositoryResult<Statement> triples = con.getStatements(null, null, null, false);
		while (triples.hasNext())
			log.debug(triples.next());
		triples.close();
		this.repositoryWrapper.closeConnection();
	}
}
