package it.unibz.inf.ontop.protege.core;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.StreamSupport;

import javax.annotation.Nonnull;

/*
 * #%L
 * ontop-protege
 * %%
 * Copyright (C) 2009 - 2013 KRDB Research Centre. Free University of Bozen Bolzano.
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import com.google.common.collect.ImmutableMap;
import it.unibz.inf.ontop.spec.mapping.PrefixManager;
import it.unibz.inf.ontop.spec.mapping.impl.AbstractPrefixManager;
import org.protege.editor.owl.model.entity.EntityCreationPreferences;
import org.protege.editor.owl.ui.prefix.PrefixUtilities;
import org.semanticweb.owlapi.formats.PrefixDocumentFormat;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyID;
import org.semanticweb.owlapi.rdf.rdfxml.renderer.OWLOntologyXMLNamespaceManager;

//import it.unibz.inf.ontop.protege.utils.OWLAPIAdapter;
import it.unibz.inf.ontop.spec.mapping.PrefixManager;
import it.unibz.inf.ontop.spec.mapping.impl.AbstractPrefixManager;


/**
 * This PrefixManager wraps Protege's prefix manager.
 * Any prefixes defined in Protege are transparently passed to all OBDA lib classes.
 */

public class OntologyPrefixManager extends AbstractPrefixManager {

	private final OWLOntology ontology;

	private final boolean hasExplicitDefaultPrefixNamespace;

	public OntologyPrefixManager(@Nonnull OWLOntology ontology) {
		this.ontology = ontology;

		OWLOntologyXMLNamespaceManager nsm = new OWLOntologyXMLNamespaceManager(
				ontology,
				getPrefixManager());

		if (StreamSupport.stream(nsm.getPrefixes().spliterator(), false)
				.anyMatch(p -> p.equals(""))) {
			String prefix = nsm.getNamespaceForPrefix("");
			hasExplicitDefaultPrefixNamespace = true;
			addPrefix(PrefixManager.DEFAULT_PREFIX, prefix);
		}
		else {
			hasExplicitDefaultPrefixNamespace = false;
			generateDefaultPrefixNamespaceIfPossible(ontology.getOntologyID());
		}
	}

	private PrefixDocumentFormat getPrefixManager() {
		return PrefixUtilities.getPrefixOWLOntologyFormat(ontology);
	}

	public void updateOntologyID(OWLOntologyID newID) {
		if (!hasExplicitDefaultPrefixNamespace)
			generateDefaultPrefixNamespaceIfPossible(newID);
	}

	public String generateUniquePrefixForBootstrapper(String baseIri) {
		String prefix = "g:";
		Map<String, String> map = getPrefixManager().getPrefixName2PrefixMap();
		while (map.containsKey(prefix))
			prefix = "g" + prefix;

		addPrefix(prefix, baseIri);
		return prefix;
	}


	private void generateDefaultPrefixNamespaceIfPossible(OWLOntologyID ontologyID) {
		
		//final IRI ontologyIri = OWLAPIAdapter.INSTANCE.getOntologyIRI(ontologyID).orNull();
		final IRI ontologyIri = ontologyID.getOntologyIRI().orNull();

		if (ontologyIri == null)
			return;

		String prefixUri = ontologyIri.toString();
		if (!prefixUri.endsWith("#") && !prefixUri.endsWith("/")) {
			String defaultSeparator = EntityCreationPreferences.getDefaultSeparator();
			if (!prefixUri.endsWith(defaultSeparator))  {
				prefixUri += defaultSeparator;
			}
		}
		addPrefix(PrefixManager.DEFAULT_PREFIX, prefixUri);
	}


	@Override
	protected Optional<String> getIriDefinition(String prefix) {
		return Optional.ofNullable(getPrefixManager().getPrefix(prefix));
	}

	@Override
	protected List<Map.Entry<String, String>> getOrderedMap() {
		return orderMap(getPrefixManager().getPrefixName2PrefixMap());
	}

	@Override
	public Map<String, String> getPrefixMap() {
		return ImmutableMap.copyOf(getPrefixManager().getPrefixName2PrefixMap());
	}

	public void addPrefix(String name, String uri) {
		getPrefixManager().setPrefix(name, uri);
	}
}
