package eu.dnetlib.contract.ctx;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import eu.dnetlib.contract.ctx.GlobalContractContext;
import eu.dnetlib.contract.ctx.GlobalContractContextPlaceholder;
import eu.dnetlib.contract.runner.ContractTestRunnerException;
import eu.dnetlib.contract.runner.InvokerDataResultEntry;


/**
 * GlobalContractContext placeholder test.
 * @author mhorst
 *
 */
public class GlobalContractContextPlaceholderTest {
	
	GlobalContractContextPlaceholder phModule = null;
	
	Object resultValue = null;
	
	String auxCtxKey = null;
	
	String auxCtxValue = null;
	
	String afterResultValue = null;
	
	String beforeResultValue = null;
	
	@Before
	public void init() {
		resultValue = new Integer(10);
		auxCtxKey = "someAuxKey";
		auxCtxValue = "someAuxValue";
		afterResultValue = "someAfterResultValue";
		beforeResultValue = "someBeforeResultValue";
		
		phModule = new GlobalContractContextPlaceholder();
		GlobalContractContext context = new GlobalContractContext();
		phModule.setContext(context);
		context.getResultContext().setExecutionDataResultEntries(new InvokerDataResultEntry[] {
				new InvokerDataResultEntry(null, resultValue)});
		context.getAuxContext().put(auxCtxKey, auxCtxValue);
		context.getResultContext().setAfterDataResultEntries(
				new InvokerDataResultEntry[] {new InvokerDataResultEntry(null, afterResultValue)});
		context.getResultContext().setBeforeDataResultEntries(
				new InvokerDataResultEntry[] {new InvokerDataResultEntry(null, beforeResultValue)});
	}

	@Test
	public void testIsSinglePlaceholderOnly() throws Exception {
		String source = phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix();
		assertTrue(phModule.isSinglePlaceholderOnly(source));
		
		phModule.setPlaceholderPrefix("{");
		phModule.setPlaceholderSuffix("}$$");
		source = phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix();
		assertTrue(phModule.isSinglePlaceholderOnly(source));
	
		phModule.setPlaceholderPrefix(GlobalContractContextPlaceholder.DEFAULT_PLACEHOLDER_PREFIX);
		phModule.setPlaceholderSuffix(GlobalContractContextPlaceholder.DEFAULT_PLACEHOLDER_SUFFIX);
		
		source = phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix() + 
			phModule.getPlaceholderSuffix();
		assertFalse(phModule.isSinglePlaceholderOnly(source));
		
		source = phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix() + 
			phModule.getPlaceholderSuffix();
		assertFalse(phModule.isSinglePlaceholderOnly(source));
	}
	
	@Test
	public void testReplaceObject() throws Exception {
		String source = phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix();
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(resultValue, result);
		
//		replace nonexisting
		source = phModule.getPlaceholderPrefix() +
			"nonExistingPlaceholder" +
			phModule.getPlaceholderSuffix();
		try {
			phModule.resolve(source);
			fail("Exception should be thrown!");
		} catch (ContractTestRunnerException e) {
//			ok
		}
//		replace nonexisting, ignoreUnresolvablePlaceholders = true
		phModule.setIgnoreUnresolvablePlaceholders(true);
		result = phModule.resolve(source);
		assertEquals(result, source);
	}
	
	@Test
	public void testReplacePartOfText() throws Exception {
		String prefixText = "some prefix text";
		String suffixText = "some suffix text";
		String source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix() + suffixText;
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + resultValue + suffixText, result);
	}
	
	@Test
	public void testReplacePlaceholderWithNullValue() throws Exception {
		phModule.getContext().getResultContext().setExecutionDataResultEntries(
				new InvokerDataResultEntry[] {new InvokerDataResultEntry(null, null)});
		String prefixText = "some prefix text";
		String suffixText = "some suffix text";
		String source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix() + suffixText;
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + "null" + suffixText, result);
	}
	
	@Test
	public void testReplaceNonExistingPlaceholder() throws Exception {
		String prefixText = "some prefix text";
		String suffixText = "some suffix text";
		String source = prefixText + phModule.getPlaceholderPrefix() +
			"nonExistingPlaceholder" +
			phModule.getPlaceholderSuffix() + suffixText;
		try {
			phModule.resolve(source);
			fail("Exception should be thrown!");
		} catch (ContractTestRunnerException e) {
//			ok
		}
//		replace nonexisting, ignoreUnresolvablePlaceholders = true
		phModule.setIgnoreUnresolvablePlaceholders(true);
		Object result = phModule.resolve(source);
		assertEquals(result, source);
		
	}
	
	@Test
	public void testReplaceWithAfterPlaceholder() throws Exception {
		String prefixText = "some prefix text";
		String suffixText = "some suffix text";
		String source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_AFTER_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() + suffixText;
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + afterResultValue + suffixText, result);
		
//		changed start index
		phModule.setStartIndex(1);
		source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_AFTER_PLACEHOLDER_PREFIX + 1 +
			phModule.getPlaceholderSuffix() + suffixText;
		result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + afterResultValue + suffixText, result);
		
//		index out of range
		source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_AFTER_PLACEHOLDER_PREFIX + 2 +
			phModule.getPlaceholderSuffix() + suffixText;
		try {
			phModule.resolve(source);
			fail("Exception should be thrown!");
		} catch (ContractTestRunnerException e) {
//			ok
		}
	}
	
	@Test
	public void testReplaceWithBeforePlaceholder() throws Exception {
		String prefixText = "some prefix text";
		String suffixText = "some suffix text";
		String source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_BEFORE_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() + suffixText;
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + beforeResultValue + suffixText, result);
		
//		changed start index
		phModule.setStartIndex(1);
		source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_BEFORE_PLACEHOLDER_PREFIX + 1 +
			phModule.getPlaceholderSuffix() + suffixText;
		result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + beforeResultValue + suffixText, result);
		
//		index out of range
		source = prefixText + phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_BEFORE_PLACEHOLDER_PREFIX + 2 +
			phModule.getPlaceholderSuffix() + suffixText;
		try {
			phModule.resolve(source);
			fail("Exception should be thrown!");
		} catch (ContractTestRunnerException e) {
//			ok
		}
	}
	
	@Test
	public void testReplaceMultiplePlaceholders() throws Exception {
		String prefixText = "some prefix text";
		String suffixText = "some suffix text";
		String source = prefixText + 
			phModule.getPlaceholderPrefix() + 
			GlobalContractContextPlaceholder.DEFAULT_BEFORE_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() + 
			phModule.getPlaceholderPrefix() + 
			GlobalContractContextPlaceholder.DEFAULT_AFTER_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() +
			phModule.getPlaceholderPrefix() + 
			GlobalContractContextPlaceholder.DEFAULT_RESULT_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() +
			phModule.getPlaceholderPrefix() + 
			auxCtxKey +
			phModule.getPlaceholderSuffix() +
			suffixText;
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + beforeResultValue + afterResultValue +
				resultValue + auxCtxValue + suffixText, result);
	}

	@Test
	public void testReplaceMultiplePlaceholdersMixed() throws Exception {
		String prefixText = "some prefix text";
		String mixingText = "some mixing text";
		String suffixText = "some suffix text";
		String source = prefixText + 
			phModule.getPlaceholderPrefix() + 
			GlobalContractContextPlaceholder.DEFAULT_BEFORE_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() + 
			mixingText + 
			phModule.getPlaceholderPrefix() + 
			GlobalContractContextPlaceholder.DEFAULT_AFTER_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() +
			mixingText + 
			phModule.getPlaceholderPrefix() + 
			GlobalContractContextPlaceholder.DEFAULT_RESULT_PLACEHOLDER_PREFIX + 0 +
			phModule.getPlaceholderSuffix() +
			mixingText + 
			phModule.getPlaceholderPrefix() + 
			auxCtxKey +
			phModule.getPlaceholderSuffix() +
			suffixText;
		Object result = phModule.resolve(source);
		assertNotNull(result);
		assertEquals(prefixText + beforeResultValue + mixingText + afterResultValue +
				mixingText + resultValue + mixingText + auxCtxValue + suffixText, result);
	}
	
	@Test
	public void testResolveArrayOfPlaceholders() throws Exception {
		String source1 = phModule.getPlaceholderPrefix() +
			GlobalContractContextPlaceholder.DEFAULT_SINGLE_RESULT_PLACEHOLDER +
			phModule.getPlaceholderSuffix();
		String source2 = "someSource";
		Integer source3 = new Integer(10);
		Object[] sourceArray = new Object[] {source1, source2, source3};
		Object[] resultArray = phModule.resolve(sourceArray);
		assertNotNull(resultArray);
		assertEquals(sourceArray.length, resultArray.length);
		assertEquals(resultValue, resultArray[0]);
		assertEquals(source2, resultArray[1]);
		assertEquals(source3, resultArray[2]);
	}
}
