package org.yi.happy.archive.join;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.yi.happy.archive.Bytes;
import org.yi.happy.archive.Fragment;
import org.yi.happy.archive.block.Block;
import org.yi.happy.archive.key.FullKey;
import org.yi.happy.archive.test_data.TestData;

/**
 * Tests for {@link RestoreEngine}.
 */
public class RestoreEngineTest {
    private LogFragmentHandler log;

    /**
     * set up
     */
    @Before
    public void before() {
        log = new LogFragmentHandler();
    }

    /**
     * tear down
     */
    @After
    public void after() {
        log = null;
    }

    private static final TestData C = TestData.KEY_CONTENT;
    private static final Bytes D = new Bytes("hello\n");

    /**
     * The first basic operations, load a single data block.
     * 
     * @throws Exception
     */
    @Test
    public void testFirstBasic() throws Exception {
        RestoreEngine restore = new RestoreEngine(C.getFullKey(), log);

        assertEquals(Arrays.asList(C.getFullKey()), restore.getNeededNow());

        restore.addBlocks(blockMap(C));

        assertEquals(list(frag(0, D)), log.getFragments());
        assertTrue(log.isDone());
    }

    private static final TestData MAP = TestData.KEY_CONTENT_MAP;
    private static final TestData C1 = TestData.KEY_CONTENT_1;
    private static final TestData C2 = TestData.KEY_CONTENT_2;
    private static final Bytes D1 = new Bytes('0', '1', '2', '3', '4');
    private static final Bytes D2 = new Bytes('5', '6', '7', '8', '9');

    /**
     * process a map, with the later blocks being available before the first.
     * 
     * @throws Exception
     */
    @Test
    public void testOutOfOrderMap() throws Exception {
        RestoreEngine restore = new RestoreEngine(MAP.getFullKey(), log);

        restore.addBlocks(blockMap(MAP));

        assertEquals(Collections.emptyList(), log.getFragments());

        assertEquals(Arrays.asList(C1.getFullKey(), C2.getFullKey()),
                restore.getNeededNow());

        restore.addBlocks(blockMap(C2));

        assertEquals(Arrays.asList(new Fragment(5, D2)), log.getFragments());
        assertFalse(log.isDone());

        assertEquals(Arrays.asList(C1.getFullKey()), restore.getNeededNow());

        restore.addBlocks(blockMap(C1));

        assertEquals(list(frag(5, D2), frag(0, D1)), log.getFragments());
        assertTrue(log.isDone());

        assertEquals(Collections.emptyList(), restore.getNeededNow());
    }

    private static final TestData MAP_PAD = TestData.KEY_CONTENT_MAP_PAD;

    /**
     * Restore a map with padding in it.
     * 
     * @throws Exception
     */
    @Test
    public void testMapPad() throws Exception {
        RestoreEngine restore = new RestoreEngine(MAP_PAD.getFullKey(), log);

        restore.addBlocks(blockMap(MAP_PAD, C1, C2));

        assertEquals(list(frag(0, D1), frag(10, D2)), log.getFragments());
        assertTrue(log.isDone());
    }

    private <T> List<T> list(T... items) {
        return Arrays.asList(items);
    }

    private Fragment frag(int offset, Bytes data) {
        return new Fragment(offset, data);
    }

    private Map<FullKey, Block> blockMap(TestData... blocks) throws IOException {
        MapBuilder<FullKey, Block> b = new MapBuilder<FullKey, Block>();
        for (TestData block : blocks) {
            b.add(block.getFullKey(), block.getClearBlock());
        }
        return b.create();
    }
}

@@ -212,17 +212,20 @@
 il.Array
-s
+List
 ;%0Aimport
@@ -235,26 +235,21 @@
 va.util.
-Collection
+Array
 s;%0Aimpor
@@ -1280,36 +1280,17 @@
 als(
-Arrays.asList(C.getFullKey()
+keyList(C
 ), r
@@ -2124,34 +2124,17 @@
 tEquals(
-Collections.emptyL
+l
 ist(), l
@@ -2179,72 +2179,24 @@
 als(
-Arrays.asList(C1.getFullKey(), C2.getFullKey()),%0A               
+keyList(C1, C2),
  res
@@ -2285,34 +2285,17 @@
 als(
-Arrays.asList(new Fragment
+list(frag
 (5, 
@@ -2382,37 +2382,18 @@
 als(
-Arrays.asList(C1.getFullKey()
+keyList(C1
 ), r
@@ -2593,24 +2593,10 @@
 als(
-Collections.empt
+ke
 yLis
@@ -2624,32 +2624,259 @@
 dNow());%0A    %7D%0A%0A
+    private List%3CFullKey%3E keyList(TestData... items) %7B%0A        List%3CFullKey%3E list = new ArrayList%3CFullKey%3E();%0A        for (TestData item : items) %7B%0A            list.add(item.getFullKey());%0A        %7D%0A        return list;%0A    %7D%0A%0A
     private stat
@@ -3324,32 +3324,507 @@
 Done());%0A    %7D%0A%0A
+    private static final TestData MAP_OVERLAP = TestData.KEY_CONTENT_MAP_OVERLAP;%0A%0A    @Test%0A    public void testMapOverlap() throws Exception %7B%0A        RestoreEngine restore = new RestoreEngine(key(MAP_OVERLAP), log);%0A%0A        restore.addBlocks(blockMap(MAP_OVERLAP, C1, C2));%0A        assertEquals(list(frag(0, D1), frag(3, D2)), log.getFragments());%0A        assertTrue(log.isDone());%0A    %7D%0A%0A    private FullKey key(TestData item) %7B%0A        return item.getFullKey();%0A    %7D%0A%0A
     private %3CT%3E 

test that an overlapping map is processed properly.