package laughinglen.domain;

import com.google.common.collect.Lists;
import laughinglen.domain.store.Cache;
import laughinglen.domain.store.Snapshot;
import laughinglen.domain.store.Store;
import laughinglen.domain.store.Version;
import laughinglen.domain.store.memory.MemoryCache;
import laughinglen.domain.store.memory.MemoryStore;
import laughinglen.domain.testing.TestEvent;
import laughinglen.domain.testing.TestId;
import laughinglen.domain.testing.TestRepository;
import laughinglen.domain.testing.TestRoot;
import org.junit.Before;
import org.junit.Test;

import java.util.Optional;

import static org.assertj.core.api.Assertions.*;

public class RepositoryTest {
	private Store store;
	private Cache<TestRoot, TestId> cache;
	private Repository<TestRoot, TestId> repository;

	@Before
	public void setUp()	{
		store = new MemoryStore();
		cache = new MemoryCache<>();
		repository = new TestRepository(store, cache);
	}

	@Test
	public void shouldStoreRoot() {
		final TestRoot root = new TestRoot();
		final TestId id = new TestId("1");
		assertThat(repository.save(id, root)).isFalse();

		root.increment();
		assertThat(repository.save(id, root)).isTrue();

		final Optional<TestRoot> fetched = repository.fetch(id);
		assertThat(fetched.isPresent()).isTrue();
		assertThat(fetched.get().count()).isEqualTo(root.count());

		fetched.get().bigIncrement();
		assertThat(repository.save(id, fetched.get())).isTrue();

		assertThat(repository.save(id, root)).isFalse();
	}

	@Test
	public void shouldIgnoreUnknownEvents() {
		final TestId id = new TestId("1");
		final Event bad = new BadEvent();

		assertThat(store.store(id, Version.ZERO, Lists.newArrayList(bad, bad, bad, bad)).succeeded).isTrue();

		final Optional<TestRoot> fetched = repository.fetch(id);
		assertThat(fetched.isPresent()).isTrue();
		assertThat(fetched.get().count()).isEqualTo(0);

		fetched.get().increment();
		assertThat(fetched.get().count()).isEqualTo(1);
		assertThat(repository.save(id, fetched.get())).isTrue();
	}

	@Test
	public void shouldUseCachedValueIfAvailable()	{
		final TestId id = new TestId("1");
		final TestEvent event = new TestEvent();

		assertThat(store.store(id, Version.ZERO, Lists.newArrayList(event, event, event)).succeeded).isTrue();

		final Optional<TestRoot> original = repository.fetch(id);
		assertThat(original).isNotNull();
		assertThat(original.isPresent()).isTrue();
		assertThat(original.get().count()).isEqualTo(3);

		cache.store(id, new Snapshot<>(original.get(), new Version(3)));
		assertThat(store.store(id, new Version(3), Lists.newArrayList(event, event)).succeeded).isTrue();

		final Optional<TestRoot> cached = repository.fetch(id);
		assertThat(cached).isNotNull();
		assertThat(cached.isPresent()).isTrue();
		assertThat(cached.get().count()).isEqualTo(5);
	}

	private class BadEvent extends Event {
	}
}
@@ -62,16 +62,55 @@
 .Lists;%0A
+import com.google.common.collect.Maps;%0A
 import l
@@ -596,16 +596,38 @@
 .Test;%0A%0A
+import java.util.Map;%0A
 import j
@@ -645,16 +645,16 @@
 tional;%0A
-
 %0Aimport 
@@ -757,16 +757,23 @@
 private 
+Wrapped
 Cache%3CTe
@@ -917,24 +917,43 @@
 cache = new 
+WrappedCache%3C%3E(new 
 MemoryCache%3C
@@ -955,16 +955,17 @@
 ache%3C%3E()
+)
 ;%0A%09%09repo
@@ -2742,32 +2742,79 @@
 tory.fetch(id);%0A
+%09%09assertThat(cache.hits.get(id)).isEqualTo(1);%0A
 %09%09assertThat(cac
@@ -2927,16 +2927,590 @@
 5);%0A%09%7D%0A%0A
+%09private class WrappedCache%3CT extends Root, I extends Id%3E implements Cache%3CT, I%3E%09%7B%0A%09%09private final Cache%3CT, I%3E cache;%0A%09%09final Map%3CId, Integer%3E hits = Maps.newHashMap();%0A%0A%09%09private WrappedCache(final Cache%3CT, I%3E cache) %7B%0A%09%09%09this.cache = cache;%0A%09%09%7D%0A%0A%09%09@Override%0A%09%09public Optional%3CSnapshot%3CT%3E%3E fetch(final I id) %7B%0A%09%09%09final Optional%3CSnapshot%3CT%3E%3E fetch = cache.fetch(id);%0A%09%09%09if(fetch.isPresent())%09%7B%0A%09%09%09%09hits.merge(id, 1, (v, n) -%3E v + n );%0A%09%09%09%7D%0A%09%09%09return fetch;%0A%09%09%7D%0A%0A%09%09@Override%0A%09%09public void store(final I id, final Snapshot%3CT%3E snapshot) %7B%0A%09%09%09cache.store(id, snapshot);%0A%09%09%7D%0A%09%7D%0A%0A
 %09private

Check that cache is actually being used