/*
 * Copyright (c) eHealth
 */
package be.fgov.ehealth.technicalconnector.tests.junit.rule;

import java.util.Properties;

import org.apache.commons.lang.Validate;
import org.junit.rules.ExternalResource;

import be.ehealth.technicalconnector.config.ConfigurationModule;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.technicalconnector.tests.session.SessionDestroyer;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import be.fgov.ehealth.technicalconnector.tests.utils.LoggingUtils;
import be.fgov.ehealth.technicalconnector.tests.utils.SupportedLanguages;

/**
 * @author EHP
 */
public class SessionRule extends ExternalResource {

    public static EnvironmentSelectorStep withActiveSession() {
        return new InnerStep(true);
    }

    public static EnvironmentSelectorStep withInactiveSession() {
        return new InnerStep(false);
    }

    public interface EnvironmentSelectorStep extends ConfigurationModuleStep {

        ProfessionSelectorStep forEnvironment(String env);

        BuilderStep baseOn(String location);
    }

    public interface ProfessionSelectorStep {

        UserSelectorStep forProfession(String prof);
    }

    public interface UserSelectorStep {

        ProgramLangStep forUser(String env);
    }

    public interface ProgramLangStep extends ConfigurationModuleStep {

        ConfigurationModuleStep forProgrammingLanguage(SupportedLanguages lang);

    }

    public interface ConfigurationModuleStep extends BuilderStep {

        BuilderStep with(Class<? extends ConfigurationModule>... modules);

    }

    public interface BuilderStep {

        SessionRule build();
    }


    private static class InnerStep implements EnvironmentSelectorStep, ProfessionSelectorStep, UserSelectorStep, ProgramLangStep {

        private boolean activate;

        private SupportedLanguages lang = SupportedLanguages.JAVA;

        private Properties props = new Properties();
        private Class<? extends ConfigurationModule>[] modules = new Class[]{};

        private InnerStep(boolean activeSession) {
            this.activate = activeSession;
        }

        @Override
        public BuilderStep baseOn(String location) {
            Validate.notEmpty(location);
            try {
                props.load(ConnectorIOUtils.getResourceAsStream(location));
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
            return this;
        }

        @Override
        public ConfigurationModuleStep forProgrammingLanguage(SupportedLanguages lang) {
            this.lang = lang;
            return this;
        }

        @Override
        public ProgramLangStep forUser(String user) {
            Validate.notEmpty(user);
            props.setProperty(SessionInitializer.SESSION_USERNAME, user);
            return this;
        }

        @Override
        public UserSelectorStep forProfession(String prof) {
            Validate.notEmpty(prof);
            props.setProperty(SessionInitializer.SESSION_PROFESSION_TYPE, prof);
            return this;
        }

        @Override
        public ProfessionSelectorStep forEnvironment(String env) {
            Validate.notEmpty(env);
            props.setProperty(SessionInitializer.SESSION_ENVIRONMENT, env);
            return this;
        }

        @Override
        public BuilderStep with(Class<? extends ConfigurationModule>... modules) {
            Validate.noNullElements(modules);
            this.modules = modules;
            return this;
        }

        @Override
        public SessionRule build() {
            LoggingUtils.bootstrap();
            return new SessionRule(props, activate, lang, modules);
        }

    }

    private Properties props;

    private boolean activate;

    private SupportedLanguages devLang;

    private Class<? extends ConfigurationModule>[] modules;

    private SessionRule(Properties props, boolean activate, SupportedLanguages devLang, Class<? extends ConfigurationModule>... modules) {
        this.props = props;
        this.activate = activate;
        this.devLang = devLang;
        this.modules = modules;
    }


    @Override
    protected void before() throws Throwable {
        SessionInitializer.init(props, activate, devLang.getAbbreviation());
        for (Class module : modules) {
            ((ConfigurationModule) module.newInstance()).init(null);
        }
    }


    @Override
    protected void after() {
        try {
            SessionDestroyer.destroy();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public String getSessionProperty(String key) {
        return SessionInitializer.getSessionProps().getProperty(key);
    }

}
