package be.ehealth.technicalconnector.config.impl;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.Configuration;
import be.ehealth.technicalconnector.config.ConfigurationModule;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.LoggingRule;
import be.fgov.ehealth.technicalconnector.tests.log4j.TestAppender;

/**
 * @author Hannes De Clercq (ehd3)
 */
@RunWith(Parameterized.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ConfigurationModuleReloader {

    private static Configuration configuration;

    private TestAppender appender = new TestAppender();

    @Rule
    public LoggingRule logging = LoggingRule.with().consoleAppender().and().appender(appender).build();

    private static List<Object[]> data = new ArrayList<Object[]>();

    @Parameters(name = "{0}")
    public static Collection<Object[]> data() throws Exception {
        add(ConfigurationModuleBootstrap.class);
        add(ConfigurationModuleClassloader.class);
        add(ConfigurationModuleDefaultLanguage.class);
        add(ConfigurationModuleHostNameVerifier.class);
        add(ConfigurationModuleLogging.class);
        add(ConfigurationModuleProperties.class);
        add(ConfigurationModuleProxy.class);
        add(ConfigurationModuleSecurityProvider.class);
        add(ConfigurationModuleServiceLoader.class);
        add(ConfigurationModuleSSL.class);
        add(ConfigurationModuleSSLVerifier.class);
        add(ConfigurationModuleSysOut.class);
        add(ConfigurationModuleSystemProps.class);
        add(ConfigurationModuleVersion.class);
        add(ConfigurationModuleXmlSec.class);
        return data;
    }

    private static void add(Class<? extends ConfigurationModule> module) throws Exception {
        data.add(new Object[]{module.getName(), module.newInstance()});
    }

    @BeforeClass
    public static void before() throws Exception {
        ConfigFactory.setLocation(new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY));
        System.setProperty(ConfigurationImpl.SYSPROP_MODULE_LOADING, "false");
        configuration = ConfigFactory.getConfigValidator();
        configuration.setProperty("KEYSTORE_DIR", "/P12/int/");
        configuration.setProperty("truststore_location", "trustStore.jks");
        configuration.setProperty("truststore_password", "changeit");
        configuration.setProperty("connector.configurationmodule.ssl.debug", "true");
    }

    @AfterClass
    public static void after() throws Exception {
        configuration.invalidate();
    }

    @Before
    @After
    public void reset() throws Exception {
        appender.getLogEvents().clear();
    }

    @Parameter(0)
    public String name;

    @Parameter(1)
    public ConfigurationModule configurationModule;

    @Test
    public void load() throws Exception {
        configurationModule.init(configuration);
        assertLogs();
    }

    @Test
    public void reload() throws Exception {
        configurationModule.init(configuration);
        assertLogs();
    }

    private void assertLogs() {
        for (LoggingEvent event : appender.getLogEvents()) {
            if (event.getLevel().equals(Level.ERROR) && event.getThreadName().equals("main")) {
                Assert.fail("Error level detected." + event.getMessage());
            }
        }
    }

}
