/*
 * Copyright (c) eHealth
 */
package be.ehealth.technicalconnector.config.impl;

import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.Configuration;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.LoggingRule;
import be.fgov.ehealth.technicalconnector.tests.log4j.TestAppender;
import be.fgov.ehealth.technicalconnector.tests.utils.LoggingUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.*;

import java.io.ByteArrayInputStream;


/**
 * test for the {@link ConfigurationImpl} class.
 *
 * @author EHP
 */

public class ConfigurationImplTest {

    private static final String OTHER_VALUE = "otherValue";
    private static final String FILLED = "test.reference.filledProperty";
    private static final String FILLED2 = "test.reference.filledProperty2";
    private static final String FILLED_VALUE = "filledProperty";
    private static final String FILLED2_VALUE = "another";
    private static final String EMPTY = "test.reference.emptyProperty";
    private static final String NOT_EXISTING = "non.existing.value";
    private static final String COPY_FILLED = "test.reference.copyOfFilledProperty";
    private static final String COPY_EMPTY = "test.reference.copyOfEmptyProperty";
    private static final String COMPOSITION_WITH_PREFIX_SUFFIX = "test.reference.useFilledPropertyInComposition";
    private static final String COMPOSITION_WITH_SUFFIX = "test.reference.useFilledPropertyInCompositionNoPrefix";
    private static final String COMPOSITION_WITH_PREFIX = "test.reference.useFilledPropertyInCompositionNoSuffix";
    private static final String COMPOSITION_WITH_PREFIX_SUFFIX_AND_CASCADING = "test.reference.useMultipleInCompositionAndCascading";
    private static final String CIR_DEP_1 = "test.reference.circularDependency1";
    private static final String CIR_DEP_2 = "test.reference.circularDependency2";
    private static final String CIR_DEP_3 = "test.reference.circularDependency3";
    private static final String COPY_NON_EXISTING = "copy.non.existing.value";
    private static final String PRE = "prefix";
    private static final String SUF = "suffix";

    @ClassRule
    public static LoggingRule logging = LoggingRule.with().consoleAppender().build();
    /**
     * config containing the following properties and values: test.reference.filledProperty=filledProperty
     * test.reference.filledProperty2=another test.reference.emptyProperty=
     * test.reference.copyOfFilledProperty=${test.reference.filledProperty}
     * test.reference.copyOfEmptyProperty=${test.reference.emptyProperty}
     * test.reference.useFilledPropertyInComposition=prefix${test.reference.filledProperty}suffix
     * test.reference.useFilledPropertyInCompositionNoPrefix=${test.reference.filledProperty}suffix
     * test.reference.useFilledPropertyInCompositionNoSuffix=prefix${test.reference.filledProperty}
     * test.reference.useMultipleInCompositionAndCascading=prefix${test.reference.useFilledPropertyInComposition}
     * test.reference.circularDependency1=11111$${test.reference.circularDependency2}
     * test.reference.circularDependency2=22222${test.reference.circularDependency3}
     * test.reference.circularDependency3=33333${test.reference.circularDependency1}
     */
    private Configuration config;
    private TestAppender testAppender;

    @Before
    public void setupConfig() throws TechnicalConnectorException {
        config = new ConfigurationImpl();
        config.setProperty(EMPTY, "");
        config.setProperty(FILLED, FILLED_VALUE);
        config.setProperty(FILLED2, "another${test.reference.emptyProperty}");
        config.setProperty(COPY_FILLED, "${test.reference.filledProperty}");
        config.setProperty(COPY_EMPTY, "${test.reference.emptyProperty}");
        config.setProperty(COMPOSITION_WITH_PREFIX_SUFFIX, "prefix${test.reference.filledProperty}suffix");
        config.setProperty(COMPOSITION_WITH_SUFFIX, "${test.reference.filledProperty}suffix");
        config.setProperty(COMPOSITION_WITH_PREFIX, "prefix${test.reference.filledProperty}");
        config.setProperty(COMPOSITION_WITH_PREFIX_SUFFIX_AND_CASCADING, "prefix${test.reference.useFilledPropertyInComposition}");
        config.setProperty(CIR_DEP_1, "11111$${test.reference.circularDependency2}");
        config.setProperty(CIR_DEP_2, "22222${test.reference.circularDependency3}");
        config.setProperty(CIR_DEP_3, "33333${test.reference.circularDependency1}");
        testAppender = LoggingUtils.getTestAppender();
    }

    @Test
    public void testConfigLoaded() throws Exception {
        Assert.assertNotNull(config);
    }

    @Test
    public void getProperties() {
        Assert.assertEquals(FILLED_VALUE, config.getProperty(FILLED));
        Assert.assertEquals(FILLED_VALUE, config.getProperty(FILLED, OTHER_VALUE));
        Assert.assertEquals(FILLED2_VALUE, config.getProperty(FILLED2));
        Assert.assertEquals(FILLED2_VALUE, config.getProperty(FILLED2, OTHER_VALUE));
        Assert.assertEquals("", config.getProperty(EMPTY));
        Assert.assertEquals("", config.getProperty(EMPTY, OTHER_VALUE));
        Assert.assertEquals(null, config.getProperty(NOT_EXISTING));
        Assert.assertEquals(OTHER_VALUE, config.getProperty(NOT_EXISTING, OTHER_VALUE));
    }


    @Test
    public void testGetPropertiesWithReferencesCopyOfAnotherProperty() {
        Assert.assertEquals(FILLED_VALUE, config.getProperty(COPY_FILLED));
        Assert.assertEquals(FILLED_VALUE, config.getProperty(COPY_FILLED, OTHER_VALUE));
        Assert.assertEquals("", config.getProperty(COPY_EMPTY));
        Assert.assertEquals("", config.getProperty(COPY_EMPTY, OTHER_VALUE));
        Assert.assertEquals(null, config.getProperty(COPY_NON_EXISTING));
        Assert.assertEquals(null, config.getProperty(COPY_NON_EXISTING, null));
    }

    @Test
    public void testRetrieveValueFromReferenceWhichDoesNotExistWithDefault() throws Exception {
        Assert.assertEquals(OTHER_VALUE, config.getProperty(COPY_NON_EXISTING, OTHER_VALUE));
    }

    @Test
    public void testGetPropertiesWithReferencesNewBehaviour() throws Exception {
        // old return : ${non.existing.value}
        Assert.assertEquals(null, config.getProperty(COPY_NON_EXISTING));

        // old return : ${non.existing.value}
        Assert.assertEquals(OTHER_VALUE, config.getProperty(COPY_NON_EXISTING, OTHER_VALUE));
    }

    /**
     * Test method for {@link be.ehealth.technicalconnector.config.impl.ConfigurationImpl#getProperty(java.lang.String)}.
     */
    @Test
    public void testGetPropertiesWithReferencesCombinationOfProperties() {
        Assert.assertEquals(PRE + FILLED_VALUE + SUF, config.getProperty(COMPOSITION_WITH_PREFIX_SUFFIX));
        Assert.assertEquals(PRE + FILLED_VALUE + SUF, config.getProperty(COMPOSITION_WITH_PREFIX_SUFFIX, OTHER_VALUE));
        Assert.assertEquals(PRE + FILLED_VALUE, config.getProperty(COMPOSITION_WITH_PREFIX));
        Assert.assertEquals(PRE + FILLED_VALUE, config.getProperty(COMPOSITION_WITH_PREFIX, OTHER_VALUE));
        Assert.assertEquals(FILLED_VALUE + SUF, config.getProperty(COMPOSITION_WITH_SUFFIX));
        Assert.assertEquals(FILLED_VALUE + SUF, config.getProperty(COMPOSITION_WITH_SUFFIX, OTHER_VALUE));

    }

    @Test
    public void testGetPropertiesWithReferencesCombinationOfPropertiesNewBehaviour() throws Exception {
        Assert.assertEquals(PRE + PRE + FILLED_VALUE + SUF, config.getProperty(COMPOSITION_WITH_PREFIX_SUFFIX_AND_CASCADING));
        Assert.assertEquals(PRE + PRE + FILLED_VALUE + SUF, config.getProperty(COMPOSITION_WITH_PREFIX_SUFFIX_AND_CASCADING, OTHER_VALUE));
    }

    @Test(expected = RuntimeException.class)
    public void testCircularDependenciesCase1() throws Exception {
        config.getProperty(CIR_DEP_1);
    }

    @Test(expected = RuntimeException.class)
    public void testCircularDependenciesCase2() throws Exception {
        config.getProperty(CIR_DEP_2);
    }


    @Test(expected = RuntimeException.class)
    public void testCircularDependenciesCase3() throws Exception {
        config.getProperty(CIR_DEP_3);
    }


    @Test
    public void trimPropsDefault() {
        config.setProperty("endpoint.whitespace", "endpoint ");
        config.setProperty("some.property", "property ");
        config.setProperty("some.password.property", "password ");
        Assert.assertEquals("endpoint", config.getProperty("endpoint.whitespace"));
        Assert.assertEquals("property ", config.getProperty("some.property"));
        Assert.assertEquals("password ", config.getProperty("some.password.property"));
    }

    @Test
    public void trimPropsAllExceptPasswords() {
        config.setProperty("configuration.properties.trim", "true");
        config.setProperty("endpoint.whitespace", "endpoint ");
        config.setProperty("some.property", "property ");
        config.setProperty("some.password.property", "password ");
        Assert.assertEquals("endpoint", config.getProperty("endpoint.whitespace", "endpoint"));
        Assert.assertEquals("property", config.getProperty("some.property", "property "));
        Assert.assertEquals("password ", config.getProperty("ome.password.property", "password "));
    }

    @Test
    public void detectDefaultValue() {

        config.setProperty("default.detection", "true");
        Assert.assertEquals("true", config.getProperty("default.detection", "true"));

        boolean found = false;
        for (LoggingEvent logEvent : testAppender.getLogEvents()) {
            if ("CONFIG CLEANUP [default.detection] configured value is same as default value.".equals(logEvent.getMessage())) {
                found = true;
            }
        }
        Assert.assertTrue(found);

    }

}
