package sync;

import static org.junit.Assert.*;

import java.io.IOException;
import java.io.StringReader;

import org.apache.log4j.PropertyConfigurator;
import org.junit.BeforeClass;
import org.junit.Test;

import data.MVDataEntry;
import data.filters.MVDataCombiner;
import data.filters.MVDataCombiner.MVDataCombineMode;
import data.io.MVDataReader;
import data.io.SafeDataReader;
import data.io.csv.CSVDataReader;
import data.io.stub.StubDataReader;
import data.io.stub.StubDataWriter;

public class BasicSyncTaskTest {
	
	private static final String LOG_PROPERTIES_FILE = "conf/log4j.properties";
	
	@BeforeClass
	public static void setup() {
		PropertyConfigurator.configure(LOG_PROPERTIES_FILE);
	}

	@Test
	public void test() throws IOException {
		
		// Input flows setup
		MVDataEntry[] fakeEntries1 = new MVDataEntry[5];
		fakeEntries1[0] = new MVDataEntry("line1");
		fakeEntries1[0].put("hello", "world");
		
		fakeEntries1[1] = new MVDataEntry("line2");
		fakeEntries1[1].put("bla", "hidden");
		fakeEntries1[1].put("hello", "merged");
		
		fakeEntries1[2] = new MVDataEntry("line3");
		fakeEntries1[2].put("hello", "world");
		
		fakeEntries1[3] = new MVDataEntry("line4");
		fakeEntries1[3].put("hello", "world");
		
		fakeEntries1[4] = new MVDataEntry("line5");
		fakeEntries1[4].put("hello", "world");		
		
		
		MVDataEntry[] fakeEntries2 = new MVDataEntry[3];
		fakeEntries2[0] = new MVDataEntry("line1");
		fakeEntries2[0].put("hello", "world");
		
		fakeEntries2[1] = new MVDataEntry("line2");
		fakeEntries2[1].put("bla", "replaced");
		
		fakeEntries2[2] = new MVDataEntry("line3");
		fakeEntries2[2].put("hello", "world");
		
		
		MVDataEntry[] fakeEntries3 = new MVDataEntry[5];
		fakeEntries3[0] = new MVDataEntry("line2");
		fakeEntries3[0].put("hello", "world");
		fakeEntries3[0].put("extra", "to be preserved");

		fakeEntries3[1] = new MVDataEntry("line2b");
		fakeEntries3[1].put("to be", "removed", null);

		fakeEntries3[2] = new MVDataEntry("line4");
		fakeEntries3[2].put("hello", "world");
		fakeEntries3[2].put("extra", "to be preserved");
		
		fakeEntries3[3] = new MVDataEntry("line5");
		fakeEntries3[3].splitAndPut("hello", "too;much;world", ";");
		
		fakeEntries3[4] = new MVDataEntry("line6");
		fakeEntries3[4].put("to be", "removed");
		
		StubDataReader fakeReader1 = new StubDataReader("testSrc1", fakeEntries1);
		StubDataReader fakeReader2 = new StubDataReader("testSrc3", fakeEntries2);
		StubDataReader fakeReader3 = new StubDataReader("testDst", fakeEntries3);
		
		MVDataReader readers[] = new MVDataReader[]{
				new SafeDataReader(fakeReader1,false),
				new SafeDataReader(
					new CSVDataReader("testSrc2",
						new StringReader(CSVDataReader.CSV_DEMO),
						false
					), false
				),
				new SafeDataReader(fakeReader2,false),
		};
				
		MVDataCombineMode mergeModes[] = new MVDataCombineMode[]{
				MVDataCombineMode.PRIMARY_SOURCE,
				MVDataCombineMode.MERGE_APPEND,
				MVDataCombineMode.MERGE_REPLACE,
		};
		
		MVDataReader srcReader = new MVDataCombiner("testSrcComb", readers, mergeModes);
		MVDataReader dstReader = fakeReader3;
		
		// Output flow setup
		StubDataWriter dstWriter = new StubDataWriter(10);
		
		// Data sync'er initialization
		BasicSyncTask task = new BasicSyncTask("task1", false, srcReader, dstReader, dstWriter);
		task.setOperationLimits(10,10,10);
		
		// Data sync'er run
		assertTrue(task.call());
		
		// Expected outputs
		String expectedDstOps = 
				"INSERT: {key=line1, attrValPairs={hello=[world], attr2=[csv1], from=[csv1, csv1bis]}}\n" +
				"UPDATE: {key=line2, attrValPairs={hello=[the, merged, world, all], bla=[replaced]}}\n" +
				"DELETE: {key=line2b, attrValPairs={to be=[removed]}}\n" +
				"INSERT: {key=line3, attrValPairs={hello=[world]}}\n" +
				// Line 4 must not be updated !
				"UPDATE: {key=line5, attrValPairs={hello=[world]}}\n" +
				"DELETE: {key=line6, attrValPairs={to be=[removed]}}\n";

		// Check results
		assertEquals(expectedDstOps, dstWriter.toString());
	}

}