package sample.entity;

import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import appengine.util.AppEngineUtil;
import appengine.util.DatastoreServiceUtil;
import appengine.util.TestUtil;
import appengine.util.TraceLowLevelDelegate;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyRange;
import com.google.appengine.api.datastore.Transaction;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

import static org.junit.Assert.assertThat;

/**
 * @author shin1ogawa
 */
public class SampleEntity1Test {

	static {
		Logger.getLogger("DataNucleus.Plugin").setLevel(Level.OFF);
	}


	/**
	 * ファイルへの保存ありで、低レベルAPIのトレースを行う設定をする。
	 * @throws IOException 
	 */
	@Before
	public void setUp() throws IOException {
		if (AppEngineUtil.isLocalDevelopment()) {
			TestUtil.setUpAppEngine("gae-j-sandbox", "gae-j-sandbox.1", "target/test", false);
		}
		DatastoreServiceUtil.deleteKind(SampleEntity1.class.getSimpleName(), 100);
		DatastoreServiceUtil.deleteKind("Parent", 100);
		DatastoreServiceUtil.deleteKind("Child", 100);
		TraceLowLevelDelegate.delegateToTraceLowLevel();
	}

	/**
	 * 終了処理。
	 */
	@After
	public void tearDown() {
		TraceLowLevelDelegate.restoreDelegateFromTraceLowLevel();
		if (AppEngineUtil.isLocalDevelopment()) {
			TestUtil.tearDownAppEngine();
		}
	}

	/**
	 * JDOの単体試験の確認。
	 */
	@Test
	public void jdo() {
		PersistenceManager manager = PMF.get().getPersistenceManager();
		SampleEntity1 entity1 = new SampleEntity1();
		entity1.setValue("value1");
		SampleEntity1 entity2 = new SampleEntity1();
		entity2.setValue("value2");
		manager.makePersistentAll(entity1, entity2);
		manager.close();

		manager = PMF.get().getPersistenceManager();
		Query query = manager.newQuery(SampleEntity1.class);
		query.setResult("count(this)");
		int count = (Integer) query.execute();
		assertThat(count, is(equalTo(2)));
		manager.close();
	}


	final String KIND = SampleEntity1.class.getSimpleName();


	/**
	 * 低レベルAPIの単体試験の確認。
	 */
	@Test
	public void lowLevelApi() {
		Entity entity1 = new Entity(KIND);
		entity1.setProperty("value", "value1");
		Entity entity2 = new Entity(KIND);
		entity2.setProperty("value", "value2");
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		service.put(entity1);
		service.put(entity2);

		int count =
				service.prepare(new com.google.appengine.api.datastore.Query(KIND)).countEntities();
		assertThat(count, is(equalTo(2)));
	}

	/**
	 * SDK1.2.5で提供された{@link DatastoreService#allocateIds(String, long)}の確認。
	 */
	@Test
	public void allocateIds() {
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		KeyRange parentKeys = service.allocateIds("Parent", 1);
		Key parentKey = parentKeys.getStart();
		KeyRange childKeys = service.allocateIds(parentKey, "Child", 2);
		Iterator<Key> childKeysIterator = childKeys.iterator();
		Entity parent = new Entity(parentKey);
		parent.setProperty("property1", "parent");
		Entity child1 = new Entity(childKeysIterator.next());
		child1.setProperty("property1", "child-1");
		Entity child2 = new Entity(childKeysIterator.next());
		child2.setProperty("property1", "child-2");

		Transaction transaction = service.beginTransaction();
		service.put(Arrays.asList(parent, child1, child2));
		transaction.commit();

		assertThat(service.prepare(new com.google.appengine.api.datastore.Query("Parent"))
			.countEntities(), is(equalTo(1)));
		assertThat(service
			.prepare(new com.google.appengine.api.datastore.Query("Child", parentKey))
			.countEntities(), is(equalTo(2)));
	}
}
