package eu.dnetlib.oai.conf;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import com.google.common.collect.Lists;
import eu.dnetlib.oai.PublisherField;
import eu.dnetlib.oai.info.SetInfo;
import eu.dnetlib.rmi.provision.MDFInfo;
import eu.dnetlib.rmi.provision.OaiPublisherRuntimeException;
import eu.dnetlib.utils.MetadataReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Instances of this class reads the OAI configuration from a string, which is the configuration profile passed in as a string.
 *
 * @author alessia
 */
public class OAIConfigurationStringReader implements OAIConfigurationReader {

	private static final Log log = LogFactory.getLog(OAIConfigurationStringReader.class); // NOPMD by marko on 11/24/08 5:02 PM

	private OAIConfiguration oaiConfiguration;
	@Autowired
	private OAIConfigurationParser configurationParser;

	public OAIConfigurationStringReader() {
		this.oaiConfiguration = null;
	}

	public OAIConfigurationStringReader(final String profile) {
		this.readConfiguration(profile);
	}

	public void readConfiguration(final String profile) {
		log.debug(profile);
		try {
			this.oaiConfiguration = this.configurationParser.getConfiguration(profile);
		} catch (final IOException e) {
			throw new OaiPublisherRuntimeException("Could not read OAI configuration profile", e);
		}
	}

	public boolean isConfigurationLoaded() {
		return this.oaiConfiguration != null;
	}

	@Override
	public List<SetInfo> getSets() {
		if (isConfigurationLoaded()) {
			return Lists.newArrayList(this.oaiConfiguration.getSetsMap().values());
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<SetInfo> getSets(final boolean onlyEnabled) {

		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getSetsMap().values().stream().filter(it -> onlyEnabled ? it.isEnabled() : true).collect(
					Collectors.toList());
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<String> getSetSpecs() {
		if (isConfigurationLoaded()) {
			return Lists.newArrayList(this.oaiConfiguration.getSetsMap().keySet());
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<String> getSetSpecs(final boolean onlyEnabled) {
		if (isConfigurationLoaded()) {
			if (!onlyEnabled) { return this.getSetSpecs(); }
			final List<SetInfo> enabled = this.getSets(true);
			return enabled.stream().map(it -> it.getSetSpec()).collect(Collectors.toList());

		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<MetadataReference> getSourceMetadataFormats() {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getSourcesMDF().stream().collect(Collectors.toList());
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public SetInfo getSetInfo(final String setSpec) {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getSetsMap().get(setSpec);
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<MDFInfo> getMetadataFormatInfo() {
		if (isConfigurationLoaded()) {
			return Lists.newArrayList(this.oaiConfiguration.getMdFormatsMap().values());
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<MDFInfo> getMetadataFormatInfo(final boolean onlyEnabled) {
		if (isConfigurationLoaded()) {
			if (!onlyEnabled) {
				return this.getMetadataFormatInfo();
			} else {
				return this.oaiConfiguration.getMdFormatsMap().values().stream().filter(it -> onlyEnabled ? it.isEnabled() : true).collect(Collectors.toList());
			}

		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public MDFInfo getMetadataFormatInfo(final String mdPrefix) {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getMdFormatsMap().get(mdPrefix);
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<PublisherField> getFields() {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getFields();
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<PublisherField> getFields(final String format, final String interpretation, final String layout) {
		if (isConfigurationLoaded()) {
			return Lists.newArrayList(this.oaiConfiguration.getFieldsFor(format, layout, interpretation));
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<String> getFieldNames() {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getFieldNames();
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public List<MDFInfo> getFormatsServedBy(final String sourceFormatName, final String sourceFormatLayout, final String sourceFormatInterpretation) {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getMdFormatsMap().values().stream()
					.filter(mdf -> (mdf.getSourceFormat() == sourceFormatName) && (mdf.getSourceLayout() == sourceFormatLayout)
							&& (mdf.getSourceInterpretation() == sourceFormatInterpretation))
					.collect(Collectors.toList());
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public String getIdScheme() {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getIdScheme();
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	@Override
	public String getIdNamespace() {
		if (isConfigurationLoaded()) {
			return this.oaiConfiguration.getIdNamespace();
		} else {
			throw new OaiPublisherRuntimeException("Configuration is not loaded");
		}
	}

	public OAIConfiguration getOaiConfiguration() {
		return this.oaiConfiguration;
	}

	public void setOaiConfiguration(final OAIConfiguration oaiConfiguration) {
		this.oaiConfiguration = oaiConfiguration;
	}

	public OAIConfigurationParser getConfigurationParser() {
		return this.configurationParser;
	}

	public void setConfigurationParser(final OAIConfigurationParser configurationParser) {
		this.configurationParser = configurationParser;
	}

}
