package example.das;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.sdo.ImplHelper;
import org.apache.tuscany.das.rdb.Command;
import org.apache.tuscany.das.rdb.DAS;

import commonj.sdo.DataObject;
import commonj.sdo.Type;
import commonj.sdo.helper.DataFactory;


public class TestDAS extends DASTestCase {
	/**
	 * Persist a DataObject. 
	 * Verifies that the instance count is increased.
	 * Also verifies that the DataObject is cached.
	 * <br>
	 * Shows persist() and find() call with DataObjects.
	 */
	public void testPersist() {
		int before = count("Person");

		String ssn = ""+System.currentTimeMillis();
		DataObject person = createPerson(ssn, "Fluid", "Guy", 17);
		DAS das = getDAS();
		Command insert = das.getCommand("INSERT");
		insert.setParameter(0, person);
		insert.execute();
		int after = count("Person");
		
		assertEquals(before+1, after);
		
		// Shows how to find DataObject via em.find()
		// Notice how the identity is prefixed with Type name
		String id = "Person:"+ssn;
		Command find = das.getCommand("FIND");
		find.setParameter(1, id);
		DataObject result = find.executeQuery();
		assertNotNull(result);
		assertEquals(person,result);
	}
	

	/**
	 * Query using JPQL. The query results should be DataObjects. The related
	 * DataObjects should also be fetched.
	 */
	public void testQuery() {
		DAS das = getDAS();
		String jpql = "SELECT o FROM Person o WHERE o.firstName=?1 AND o.age=?2";
		Command query = das.getCommand(jpql);
		query.setParameter(1, "Fluid");
		query.setParameter(2, 17);
		DataObject list = query.executeQuery();
		List result = (List)list.get(0);
		assertFalse(result.isEmpty());
		for (Object o : result) {
			assertTrue(o instanceof DataObject);
			DataObject dataObject = (DataObject) o;
			assertEquals("Person", dataObject.getType().getName());
			String firstName = dataObject.getString("firstName");
			assertEquals("Fluid", firstName);
			String lastName = dataObject.getString("lastName");
			assertEquals("Guy", lastName);
		}
	}
	
	/**
	 * Tests that DataObject can be modified and merged. The changes are 
	 * persisted and the merged DataObjects returned reflect the modifications
	 * as well as the version updates.
	 */
	public void testUpdate() {
		DAS das = getDAS();
		String jpql = "SELECT o FROM Person o WHERE o.firstName=?1 AND o.age=?2";
		Command query = das.getCommand(jpql);
		query.setParameter(1, "Fluid");
		query.setParameter(2, 17);
		DataObject list = query.executeQuery();
		List result = list.getList(0);
		assertFalse(result.isEmpty());
		for (Object o : result) {
			assertTrue(o instanceof DataObject);
			DataObject dataObject = (DataObject) o;
			assertEquals("Person", dataObject.getType().getName());
			String firstName = dataObject.getString("firstName");
			assertEquals("Fluid", firstName);
			String lastName = dataObject.getString("lastName");
			assertEquals("Guy", lastName);
		}
		for (Object o : result) {
			int before = count("Person");
			DataObject dataObject = (DataObject) o;
			int v0 = ImplHelper.getVersion(dataObject);
			assertTrue(v0>0);
			assertNotNull(ImplHelper.getIdValue(dataObject));
			
			dataObject.setString("firstName", "Solid");
			das.applyChanges(dataObject);
			int v1 = ImplHelper.getVersion(dataObject);
			assertTrue(v1>v0);
			assertEquals("Solid", dataObject.getString("firstName"));
			int after = count("Person");
			assertEquals(before, after);
		}
	}
	
	/**
	 * Tests that DataObjects can be deleted from persistent store via remove()
	 * method.
	 *
	 */
	public void testDelete() {
		DAS das = getDAS();
		String jpql = "SELECT o FROM Person o WHERE o.lastName=?1 AND o.age=?2";
		Command query = das.getCommand(jpql);
		query.setParameter(1, "Guy");
		query.setParameter(2, 17);
		DataObject list = query.executeQuery();
		List result = list.getList(0);
		assertFalse(result.isEmpty());
		Command delete = das.createCommand("DELETE");
		for (Object o : result) {
			int before = count("Person");
			DataObject dataObject = (DataObject) o;
			delete.setParameter(0, dataObject);
			delete.execute();
			int after = count("Person");
			assertEquals(before-1, after);
		}
	}
	
	public void testUnknownCommand() {
		DAS das = getDAS();
		try {
			Command bad = das.getCommand("UNKNOWN");
			fail("Expected exception on UNKNOWN command");
		} catch (RuntimeException e) {
			// good;
		}
	}
	
	/**
	 * Helper method to create and populate a Person DataObject.
	 */
	DataObject createPerson(String ssn, String first, String last, int age) {
		Type type = getType("Person");
		DataObject data = DataFactory.INSTANCE.create(type);
		data.set("ssn", ssn);
		data.setString("firstName", first);
		data.setString("lastName", last);
		data.setInt("age", age);
		return data;
	}
}
