package fr.iri.thd.sonyengine.test;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.core.MediaType;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.sleepycat.persist.EntityCursor;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.representation.Form;

import fr.iri.thd.sonyengine.core.DataAccessor;
import fr.iri.thd.sonyengine.core.DbEnv;

public class TestMovieFragmentResource {

	public static final String BASE_URL = "http://localhost:9080/sonyengine/";
	public static final String DATABASE_PATH = "/Users/ymh/dev/tmp/db";

	private DbEnv dbenv = null;
	private File databasePathFile = null;
	private String baseurl = null;
			
	@Before
	public void setup()
	{
		String databasepath = System.getProperty("database_path");
		if(databasepath == null)
			databasepath = DATABASE_PATH;
		this.databasePathFile = new File(databasepath);
		
		this.baseurl = System.getProperty("baseurl");
		if(this.baseurl == null)
			this.baseurl = BASE_URL;
	}
	
	@After
	public void teardown() {
	
		if(dbenv != null)
			dbenv.close();
	}
	
	@Test
	public void testCreateMovieFragment() {
				
		String movieName = "movie" + System.currentTimeMillis();
		
		Client c = Client.create();
		WebResource res = c.resource(this.baseurl + "segment/create/" + movieName);
		
		String response = res.accept(MediaType.APPLICATION_XML_TYPE).post(String.class);
				
		Assert.assertNotNull(response);
		
		
		dbenv = new DbEnv();
		dbenv.setup(databasePathFile, true, true);

		DataAccessor da = new DataAccessor(this.dbenv.getEntityStore());

		
		EntityCursor<String> cursor = da.movieFragmentById.keys();
		
		for (String key : cursor) {
			Assert.assertNotNull(key);
		}
		
		cursor.close();
		
		Assert.assertTrue(da.movieFragmentById.contains(movieName));
		
	}

	@Test
	public void testCreateMovieFragmentForm() {
				
		String movieName = "movie" + System.currentTimeMillis();
		
		Client c = Client.create();
		
		Form form = new Form();
		form.add("id", movieName);
		
		WebResource res = c.resource(this.baseurl + "segment/create");		

		String response = res.type(MediaType.APPLICATION_FORM_URLENCODED).post(String.class, form);
				
		Assert.assertNotNull(response);
		
		dbenv = new DbEnv();
		dbenv.setup(databasePathFile, true, true);

		DataAccessor da = new DataAccessor(this.dbenv.getEntityStore());

		
		EntityCursor<String> cursor = da.movieFragmentById.keys();
		
		for (String key : cursor) {
			Assert.assertNotNull(key);
		}
		
		cursor.close();
		
		Assert.assertTrue(da.movieFragmentById.contains(movieName));
		
	}

	@Test
	public void testCreateMovieFragmentFormRetrain() throws InterruptedException {
						
		Client c = Client.create();
		WebResource.Builder res = c.resource(this.baseurl + "segment/create").type(MediaType.APPLICATION_FORM_URLENCODED);		
		List<String> movieNames = new ArrayList<String>();
		
		String movieName = "movie" + System.currentTimeMillis();
		movieNames.add(movieName);
		
		Form form = new Form();
		form.add("id", movieName);
		form.add("retrain", "true");
		
		String response = res.post(String.class, form);
				
		Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><movieFragment><id>"+movieName+"</id></movieFragment>",response);

		Thread.sleep(1);
		movieName = "movie" + System.currentTimeMillis();
		movieNames.add(movieName);

		form = new Form();
		form.add("id", movieName);
		form.add("retrain", "false");
		
		response = res.post(String.class, form);
				
		Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><movieFragment><id>"+movieName+"</id></movieFragment>",response);

		Thread.sleep(1);
		movieName = "movie" + System.currentTimeMillis();
		movieNames.add(movieName);
		
		form = new Form();
		form.add("id", movieName);
		form.add("retrain", "foo");
		
		response = res.post(String.class, form);
				
		Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><movieFragment><id>"+movieName+"</id></movieFragment>",response);

		Thread.sleep(1);
		movieName = "movie" + System.currentTimeMillis();
		movieNames.add(movieName);
		
		form = new Form();
		form.add("id", movieName);
		form.add("retrain", "1");
		
		response = res.post(String.class, form);
				
		Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><movieFragment><id>"+movieName+"</id></movieFragment>",response);

		
		dbenv = new DbEnv();
		dbenv.setup(databasePathFile, true, true);

		DataAccessor da = new DataAccessor(this.dbenv.getEntityStore());

		
		EntityCursor<String> cursor = da.movieFragmentById.keys();
		
		for (String key : cursor) {
			Assert.assertNotNull(key);
		}
		
		cursor.close();
		
		for (String name : movieNames) {
			Assert.assertTrue(da.movieFragmentById.contains(name));	
		}
		
		
	}

	@Test
	public void testTrain() {

		Client c = Client.create();
		WebResource res = c.resource(this.baseurl);
		String response = res.path("engine").path("reset").accept(MediaType.TEXT_PLAIN).post(String.class);
		
		String[] ids = new String[]{"ref1","ref2","ref3","ref4","ref5","ref6", "ref7"};

		String xmlSegment = "<segments>";
		for(String sequenceId: ids) {
			xmlSegment += String.format("<segment id=\"%s\"/>", sequenceId);
		}
		xmlSegment += "</segments>";

		c = Client.create();
		res = c.resource(this.baseurl).path("segment").path("createall");
		Form form = new Form();
		form.add("xml", xmlSegment);
		response = res.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_XML_TYPE).post(String.class, form);

		Assert.assertNotNull(response);

		
		ArrayList<String[]> tags = new ArrayList<String[]>();
		tags.add(new String[]{"crayon", "ref1"});
		tags.add(new String[]{"carte", "ref1"});
		tags.add(new String[]{"bateau", "ref1"});
		tags.add(new String[]{"voiture", "ref1"});
		tags.add(new String[]{"car", "ref1"});

		tags.add(new String[]{"enfant", "ref2"});
		tags.add(new String[]{"famille", "ref2"});
		tags.add(new String[]{"violon", "ref2"});
		tags.add(new String[]{"maison", "ref2"});
		tags.add(new String[]{"hopital", "ref2"});

		tags.add(new String[]{"enfant", "ref3"});
		tags.add(new String[]{"famille", "ref3"});
		tags.add(new String[]{"violon", "ref3"});
		tags.add(new String[]{"maison", "ref3"});
		tags.add(new String[]{"ordinateur", "ref3"});
		tags.add(new String[]{"fenetre", "ref3"});
		tags.add(new String[]{"voiture", "ref3"});
		tags.add(new String[]{"guitare", "ref3"});
		tags.add(new String[]{"carte", "ref3"});

		tags.add(new String[]{"enfant", "ref4"});
		tags.add(new String[]{"famille", "ref4"});
		tags.add(new String[]{"violon", "ref4"});
		tags.add(new String[]{"bateau", "ref4"});
		tags.add(new String[]{"ordinateur", "ref4"});
		tags.add(new String[]{"fenetre", "ref4"});
		tags.add(new String[]{"stylo", "ref4"});
		tags.add(new String[]{"perroquet", "ref4"});
		tags.add(new String[]{"crayon", "ref4"});
		tags.add(new String[]{"tele", "ref4"});
		tags.add(new String[]{"bateau", "ref4"});
		
		tags.add(new String[]{"ordinateur", "ref5"});
		tags.add(new String[]{"crayon", "ref5"});
		tags.add(new String[]{"fenetre", "ref5"});
		tags.add(new String[]{"hopital", "ref5"});
		tags.add(new String[]{"carte", "ref5"});
		tags.add(new String[]{"tele", "ref5"});
		tags.add(new String[]{"stylo", "ref5"});
		tags.add(new String[]{"perroquet", "ref5"});
		tags.add(new String[]{"bateau", "ref5"});
		tags.add(new String[]{"guitare", "ref5"});
		
		tags.add(new String[]{"maison", "ref6"});
		tags.add(new String[]{"perroquet", "ref6"});
		tags.add(new String[]{"stylo", "ref6"});
		tags.add(new String[]{"guitare", "ref6"});
		tags.add(new String[]{"hopital", "ref6"});
		tags.add(new String[]{"tele", "ref6"});
		tags.add(new String[]{"car", "ref6"});
		tags.add(new String[]{"voiture", "ref6"});
		tags.add(new String[]{"fenetre", "ref6"});
		
		tags.add(new String[]{"car", "ref7"});
		tags.add(new String[]{"voiture", "ref7"});

		String xmlTags = "<tags>";
		for(String[] tagdef: tags) {
			xmlTags += String.format("<tag name=\"%s\" segment=\"%s\"/>", (Object[])tagdef);
		}
		xmlTags += "</tags>";

		res = c.resource(this.baseurl).path("tag").path("add");
		form = new Form();
		form.add("xml", xmlTags);
		response = res.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_XML_TYPE).post(String.class, form);

		Assert.assertNotNull(response);
		
		response = c.resource(this.baseurl).path("engine").path("train").accept(MediaType.TEXT_PLAIN).post(String.class);
        
        Assert.assertEquals("ok", response);
		
		//"engine/find/{segment}/{tag}/{percent}/{more}"
		//Neighbor neighbor = engine.findMore("ref1", "enfant", .05f, true);
		res = c.resource(this.baseurl).path("engine").path("find").path("ref1").path("enfant").path("0.05").path("true");
		response = res.accept(MediaType.APPLICATION_XML_TYPE).get(String.class);
		Assert.assertNotNull(response);
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    	InputSource source = new InputSource(new StringReader(response));
    	Document doc = null;
		try {
			doc = factory.newDocumentBuilder().parse(source);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		
		NodeList nodes = doc.getElementsByTagName("neighbor");
		
		Assert.assertEquals(1, nodes.getLength());
		
	}

	
}
