package eu.dnetlib.r2d2.neo4j;

import javax.annotation.Resource;

import org.apache.log4j.BasicConfigurator;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.Transaction;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.google.common.collect.Iterables;

import eu.dnetlib.r2d2.neo4j.dao.ProfileDao;
import eu.dnetlib.r2d2.neo4j.domain.Neo4jProfile;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/eu/dnetlib/r2d2/neo4j/applicationContext-neo4j.xml", "/eu/dnetlib/r2d2/neo4j/applicationContext-r2d2-neo4j-test.xml"})
public class TestFullTextIndex extends AbstractAnnotationAwareTransactionalTests {

	@Resource
	private ProfileDao profileDao = null;
	
	@Resource
	private EmbeddedGraphDatabase graphDb = null;
	
	private Transaction tx = null;
	
	@BeforeClass
	public static void setup() {
		BasicConfigurator.configure();
	}
	
	@Before
	public void before() {
		tx = graphDb.beginTx();
	}
	
	@After
	public void after() {
		tx.failure();
		tx.finish();
		
		// delete everything
		tx = graphDb.beginTx();
		
		for (Neo4jProfile prof:profileDao.getAll())
			profileDao.deleteBean(prof.getId());
		
		tx.success();
		tx.finish();
	}
	
	@Test
	public void testOneField() throws InterruptedException {
		profileDao.newBean().setName("Vaggelis Abc");
		profileDao.newBean().setName("Vaggelis def");
		profileDao.newBean().setName("Vaggelis ghi");
		profileDao.newBean().setName("Vaggelis jkl");
		profileDao.newBean().setName("Diomidis mno");
		
		// the index is updated at tx end
		assertEquals(0, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		
		tx.success();
		tx.finish();
		
		// give it some time to update...
		Thread.sleep(1000);
		
		tx = graphDb.beginTx();
		
		// the search should succeed
		assertEquals(4, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		assertEquals(1, Iterables.size(profileDao.search("Abc", Neo4jProfile.NAME)));
		
		// how about *?
		assertEquals(4, Iterables.size(profileDao.search("Vaggelis")));
		assertEquals(1, Iterables.size(profileDao.search("jkl")));
		
		// search should be case insensitive
		assertEquals(4, Iterables.size(profileDao.search("vaggelis")));
		assertEquals(1, Iterables.size(profileDao.search("abc")));
		
		// will it always succeed?
		assertEquals(0, Iterables.size(profileDao.search("iordanis", Neo4jProfile.NAME)));
		assertEquals(0, Iterables.size(profileDao.search("triantafullos", Neo4jProfile.AVATAR_URL)));
		assertEquals(0, Iterables.size(profileDao.search("vaggelas")));
		
		// the full name??
		assertEquals(1, Iterables.size(profileDao.search("Vaggelis Abc", Neo4jProfile.NAME)));
		assertEquals(1, Iterables.size(profileDao.search("Vaggelis Abc")));
	}
	
	@Test
	public void testMoreFields() throws InterruptedException {
		Neo4jProfile prof = null; 
		
		prof = profileDao.newBean();
		prof.setName("Vaggelis abc");
		prof.setAvatarUrl("http://www.vaggelis.net");
		prof.setMail("vaggelis@myusers.net");
		
		prof = profileDao.newBean();
		prof.setName("Iordanis dfeg");
		prof.setAvatarUrl("http://www.iordanis.com");
		prof.setMail("me@iordanis.com");
		
		prof = profileDao.newBean();
		prof.setName("Vaggelas abc");
		prof.setAvatarUrl("http://www.vaggelis.net");
		prof.setMail("vaggelas@yourusers.net");
	
		// the index is updated at tx end
		assertEquals(0, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		
		tx.success();
		tx.finish();
		
		// give it some time to update...
		Thread.sleep(1000);
		
		tx = graphDb.beginTx();
		
		assertEquals(1, Iterables.size(profileDao.search("Vaggelis")));
		assertEquals(1, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		assertEquals(2, Iterables.size(profileDao.search("abc")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.AVATAR_URL)));
		assertEquals(0, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.NAME)));
		
		// lets change some values
		Iterables.getOnlyElement(profileDao.search("Iordanis")).setName("Diomidis");
		
		// the index is updated at tx end
		tx.success();
		tx.finish();
		
		// give it some time to update...
		Thread.sleep(1000);
		
		tx = graphDb.beginTx();
		
		assertEquals(1, Iterables.size(profileDao.search("Diomidis")));
		assertEquals(1, Iterables.size(profileDao.search("Diomidis", Neo4jProfile.NAME)));
		assertEquals(2, Iterables.size(profileDao.search("abc")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.AVATAR_URL)));
		assertEquals(0, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.NAME)));
		
		// lets change some more values
		Iterables.getOnlyElement(profileDao.search("Vaggelis")).setName("Diomidis");
		
		// the index is updated at tx end
		tx.success();
		tx.finish();
		
		// give it some time to update...
		Thread.sleep(1000);
		
		tx = graphDb.beginTx();
		
		assertEquals(2, Iterables.size(profileDao.search("Diomidis")));
		assertEquals(2, Iterables.size(profileDao.search("Diomidis", Neo4jProfile.NAME)));
		assertEquals(1, Iterables.size(profileDao.search("abc")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.AVATAR_URL)));
		assertEquals(0, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.NAME)));
	}
	
	@Test
	public void testDelete() throws InterruptedException {
		Neo4jProfile prof = null; 
		
		prof = profileDao.newBean();
		prof.setName("Vaggelis abc");
		prof.setAvatarUrl("http://www.vaggelis.net");
		prof.setMail("vaggelis@myusers.net");
		
		prof = profileDao.newBean();
		prof.setName("Iordanis dfeg");
		prof.setAvatarUrl("http://www.iordanis.com");
		prof.setMail("me@iordanis.com");
		
		prof = profileDao.newBean();
		prof.setName("Vaggelas abc");
		prof.setAvatarUrl("http://www.vaggelis.net");
		prof.setMail("vaggelas@yourusers.net");
		
		// the index is updated at tx end
		assertEquals(0, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		
		tx.success();
		tx.finish();
		
		// give it some time to update...
		Thread.sleep(1000);
		
		tx = graphDb.beginTx();
		
		assertEquals(1, Iterables.size(profileDao.search("Vaggelis")));
		assertEquals(1, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		assertEquals(2, Iterables.size(profileDao.search("abc")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net")));
		assertEquals(2, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.AVATAR_URL)));
		assertEquals(0, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.NAME)));
		
		// deleting a profile
		profileDao.deleteBean(Iterables.getOnlyElement(profileDao.search("Vaggelis")).getId());
		
		// the index is updated at tx end
		tx.success();
		tx.finish();
		
		// give it some time to update...
		Thread.sleep(1000);
		
		tx = graphDb.beginTx();
		
		assertEquals(0, Iterables.size(profileDao.search("Vaggelis")));
		assertEquals(0, Iterables.size(profileDao.search("Vaggelis", Neo4jProfile.NAME)));
		assertEquals(1, Iterables.size(profileDao.search("abc")));
		assertEquals(1, Iterables.size(profileDao.search("http://www.vaggelis.net")));
		assertEquals(1, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.AVATAR_URL)));
		assertEquals(0, Iterables.size(profileDao.search("http://www.vaggelis.net", Neo4jProfile.NAME)));
	}
}