package appengine.util;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import org.junit.After;
import org.junit.Before;
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.Key;
import com.google.appengine.api.datastore.Transaction;
import com.google.apphosting.api.ApiProxy;

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

import static org.junit.Assert.assertThat;

/**
 * {@link DatastoreServiceUtil}のテストケース。
 * @author shin1ogawa
 */
public class DatastoreServiceUtilTest {

	static final Logger logger = Logger.getLogger(DatastoreServiceUtilTest.class.getName());


	/**
	 * {@link DatastoreServiceUtil#getEntityGroupKey(DatastoreService, Key, String[])}
	 */
	@Test
	public void getEntityGroupKeys() {
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		Key[] keys = createSampleEntities2(service);
		final String[] kinds = new String[] {
			"Root",
			"Child",
			"ChildChild"
		};
		List<Key> list = DatastoreServiceUtil.getEntityGroupKey(service, keys[0], kinds);
		assertThat(list.size(), is(equalTo(5)));
		list = DatastoreServiceUtil.getEntityGroupKey(service, keys[1], kinds);
		assertThat(list.size(), is(equalTo(3)));
	}

	/**
	 * {@link DatastoreServiceUtil#backupEntities(DatastoreService, String, Collection)}
	 * @throws IOException
	 */
	@Test
	public void backup() throws IOException {
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		Key[] keys = createSampleEntities2(service);
		final String[] kinds = new String[] {
			"Root",
			"Child",
			"ChildChild"
		};
		List<Key> keyList = DatastoreServiceUtil.getEntityGroupKey(service, keys[0], kinds);
		Collection<Entity> entities = service.get(keyList).values();
		Key backupKey = DatastoreServiceUtil.backupEntities(service, "backup", entities);

		keyList = DatastoreServiceUtil.getEntityGroupKey(service, backupKey, new String[] {
			"backup"
		});
		assertThat(keyList.size(), is(equalTo(5 + 1))); // backupのルートEntityが含まれるのでひとつ多い。
	}

	private Key[] createSampleEntities2(DatastoreService service) {
		Iterator<Key> i = service.allocateIds("Root", 2).iterator();
		Entity root1 = new Entity(i.next());
		root1.setProperty("p1", "root1");
		Entity root2 = new Entity(i.next());
		root2.setProperty("p1", "root2");

		i = service.allocateIds(root1.getKey(), "Child", 3).iterator();
		Entity child1_1 = new Entity(i.next());
		child1_1.setProperty("p1", "child1_1");
		Entity child1_2 = new Entity(i.next());
		child1_2.setProperty("p1", "child1_2");
		Entity child1_3 = new Entity(i.next());
		child1_3.setProperty("p1", "child1_3");
		Entity child1_1_1 =
				new Entity(service.allocateIds(child1_1.getKey(), "ChildChild", 1).getStart());
		child1_1_1.setProperty("p1", "child1_1_1");

		i = service.allocateIds(root2.getKey(), "Child", 2).iterator();
		Entity child2_1 = new Entity(i.next());
		child2_1.setProperty("p1", "child2_1");
		Entity child2_2 = new Entity(i.next());
		child2_2.setProperty("p1", "child2_2");

		Transaction tx = service.beginTransaction();
		service.put(tx, Arrays.asList(root1, child1_1, child1_2, child1_3, child1_1_1));
		tx.commit();

		tx = service.beginTransaction();
		service.put(tx, Arrays.asList(root2, child2_1, child2_2));
		tx.commit();

		return new Key[] {
			root1.getKey(),
			root2.getKey()
		};
	}

	/**
	 * ファイルへの保存ありモードで準備。
	 * @throws IOException 
	 */
	@Before
	public void setUp() throws IOException {
		if (AppEngineUtil.isLocalDevelopment()) {
			TestUtil.setUpAppEngine("gae-j-sandbox", "gae-j-sandbox.1",
					"target/DatastoreServiceUtilTest", true);
		} else {
			logger.fine("ApiProxy.getDelegate()=" + ApiProxy.getDelegate());
			DatastoreServiceUtil.deleteKind("Root", 10);
			DatastoreServiceUtil.deleteKind("Child", 10);
			DatastoreServiceUtil.deleteKind("ChildChild", 10);
		}
	}

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