package com.shin1ogawa.entity;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.junit.Test;

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.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
import com.shin1ogawa.AbstractRelasionShipTest;

/**
 * どちらの方向にもEntityの実体を参照していないEntityGroupに関するテストケース。
 * <p>
 * 子Entityがancestor keyのみ保持する。
 * </p>
 */
public class ParentCTest extends AbstractRelasionShipTest {

	@Test
	public void transaction() {
		Key key = create1EntityGroup();
		PersistenceManager pm = getFactory().getPersistenceManager();
		ParentC parent = pm.getObjectById(ParentC.class, key);
		assertThat(parent.getName(), is(equalTo("parent")));
	}

	@Test
	public void getByAncestor() {
		Key key = create1EntityGroup();
		DatastoreService service = DatastoreServiceFactory
				.getDatastoreService();
		Query query = new Query(ChildC.class.getSimpleName(), key);
		List<Entity> list = service.prepare(query).asList(
				FetchOptions.Builder.withOffset(0));
		for (Entity entity : list) {
			System.out.println(ToStringBuilder.reflectionToString(entity));
		}
		assertThat(list.size(), is(equalTo(2)));
	}

	@Test
	public void delete1() {
		createDummyChildC(); // childCがみっつ作成される。
		Key key = create1EntityGroup();

		DatastoreService service = DatastoreServiceFactory
				.getDatastoreService();
		Query queryAll = new Query(ChildC.class.getSimpleName()).setKeysOnly();
		List<Entity> childrenAll = service.prepare(queryAll).asList(
				FetchOptions.Builder.withOffset(0));
		assertThat(childrenAll.size(), is(equalTo(5)));

		Query queryChild = new Query(ChildC.class.getSimpleName(), key)
				.setKeysOnly();
		List<Entity> children = service.prepare(queryChild).asList(
				FetchOptions.Builder.withOffset(0));
		assertThat(children.size(), is(equalTo(2)));

		com.google.appengine.api.datastore.Transaction transaction = service
				.beginTransaction();
		try {
			// deletecascade が効かないので子Entityは自前で削除する。
			service.delete(transaction, children.get(0).getKey(), children.get(
					1).getKey());
			service.delete(transaction, key);
			transaction.commit();
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
		}
		assertThat(service.prepare(queryAll).countEntities(), is(equalTo(3)));
	}

	private Key create1EntityGroup() {
		ParentC parent = new ParentC();
		parent.setName("parent");
		ChildC child1 = new ChildC();
		child1.setName("child1");
		ChildC child2 = new ChildC();
		child2.setName("child2");

		PersistenceManager pm = getFactory().getPersistenceManager();
		Transaction transaction = pm.currentTransaction();
		transaction.begin();
		try {
			pm.makePersistent(parent);
			child1.setAncestor(parent.getKey());
			child2.setAncestor(parent.getKey());
			// entity groupとして扱われるからひとつのTransaction内で更新が実行できる。
			pm.makePersistentAll(child1, child2);
			transaction.commit();
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			pm.close();
		}
		return parent.getKey();
	}

	private void createDummyChildC() {
		String[] names = { "dummy1", "dummy2", "dummy3" };
		PersistenceManager pm = getFactory().getPersistenceManager();
		for (String name : names) {
			ChildC child = new ChildC();
			child.setName(name);
			pm.makePersistent(child);
		}
		pm.close();
	}
}
