content: package ch.uzh.ifi.attempto.acewiki.gf;
  
  import java.util.HashSet;
  import java.util.Set;
  
  import org.semanticweb.owlapi.apibinding.OWLManager;
  import org.semanticweb.owlapi.io.StringDocumentSource;
  import org.semanticweb.owlapi.model.OWLAxiom;
  import org.semanticweb.owlapi.model.OWLOntology;
  import org.semanticweb.owlapi.model.OWLOntologyCreationException;
  import org.semanticweb.owlapi.model.OWLOntologyManager;
  import org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom;
  import org.semanticweb.owlapi.model.OWLTransitiveObjectPropertyAxiom;
  import org.semanticweb.owlapi.profiles.OWLProfile;
  import org.semanticweb.owlapi.profiles.OWLProfileReport;
  import org.semanticweb.owlapi.profiles.OWLProfileViolation;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import com.google.common.collect.Sets;
  
  import ch.uzh.ifi.attempto.acewiki.owl.AceWikiOWLReasoner2;
  import ch.uzh.ifi.attempto.ape.ACEParserResult;
  import ch.uzh.ifi.attempto.ape.ACEText;
  import ch.uzh.ifi.attempto.ape.OutputType;
  
  
  /**
   * Some static methods for the OWL conversion of GF-based wiki entries.
   *
   * TODO: work in progress
   *
   * @author Kaarel Kaljurand
   */
  public class GfOwlConverter {
  
  	private static final OWLOntologyManager OWL_ONTOLOGY_MANAGER = OWLManager.createOWLOntologyManager();
  
  	// TODO: It might be better to use OWLFSSPP as it is smaller in size and
  	// might be faster to parse. Currently the problem is that OWLFSSPP uses
  	// anonymous individuals, but these cannot be always reasoned with in OWL2, e.g. in
  	// the SameIndividual axiom. The OWLXML output has already mapped such individuals
  	// to globally unique named individuals.
  	private static final OutputType OWL_SERIALIZATION_TYPE = OutputType.OWLXML;
  
  	private static final Logger mLogger = LoggerFactory.getLogger(GfOwlConverter.class);
  
  
  	/**
  	 * Converts the given GF wiki entry into OWL.
  	 * This succeeds if the entry is compatible with ACE and OWL, i.e.
  	 * at least one of the trees can be mapped to OWL.
  	 */
  	public static Set<Set<OWLAxiom>> convert(GfGrammar gfGrammar, String uri, GfWikiEntry gfWikiEntry) throws OWLOntologyCreationException {
  		if (! gfGrammar.isAceCompatible()) {
  			// TODO: throw exception instead
  			return null;
  		}
  
  		// Convert all trees to ACE texts
  		Set<ACEText> acetexts = new HashSet<ACEText>();
  		for (String tree : gfWikiEntry.getTrees().getTrees()) {
  			try {
  				ACEText acetext = GfWikiUtils.getACEText(gfGrammar, tree);
  				if (acetext != null) {
  					acetexts.add(acetext);
  				}
  			} catch (Exception e) {
  				// TODO do not ignore exception
  			}
  		}
  
  		// Stop if no tree mapped to an ACE text
  		if (acetexts.isEmpty()) {
  			// TODO: throw exception instead
  			return null;
  		}
  
  		// Set of axioms from each reading
  		Set<Set<OWLAxiom>> setOfSetOfAxiom = Sets.newHashSet();
  
  		for (ACEText acetext : acetexts) {
  			ACEParserResult parserResult = GfWikiUtils.parse(acetext, uri, OWL_SERIALIZATION_TYPE);
  			Set<OWLAxiom> axioms = getOwlAxiomsFromString(parserResult.get(OWL_SERIALIZATION_TYPE));
  
  			if (axioms.isEmpty()) {
  				// One of the readings did not result in any axioms
  				// TODO: not sure what to do here, maybe just ignore?
  			} else {
  				setOfSetOfAxiom.add(axioms);
  			}
  		}
  
  		return setOfSetOfAxiom;
  	}
  
  
  	/**
  	 * TODO: move to its own class
  	 *
  	 * Given a set of sets of axioms, choose a single set and return it.
  	 * 
  	 * TODO: there can be many disambiguation techniques and the user might want to
  	 * configure which one to use:
  	 * 
  	 * 1. choose the first reading
  	 * 2. combine the readings into a disjunction
  	 * 3. prune the readings by checking which are consistent and redundant with respect to the KB, then choose by 1. or 2.
  	 * 4. ...
  	 */
  	public static Set<OWLAxiom> disambiguate(Set<Set<OWLAxiom>> setOfSetOfAxiom) {
  		// We have now a set of axiom sets.
  
  		if (setOfSetOfAxiom.isEmpty()) {
  			throw new IllegalArgumentException("Set of OWL axioms must not be empty");
  		}
  
  		if (setOfSetOfAxiom.size() == 1) {
  			// If this set contain a single element, then select this element.
  			return setOfSetOfAxiom.iterator().next();
  		}
  
  		// If this set contains multiple elements (i.e. is ambiguous), then resolve it somehow,
  		// selecting only a single element.
  		// TODO
  		return setOfSetOfAxiom.iterator().next();
  	}
  
  
  	/**
  	 * <p>Return {@code true} iff the given axioms are reasonable for the given reasoner.</p>
  	 */
  	public static boolean isReasonable(AceWikiOWLReasoner2 reasoner, Set<OWLAxiom> axioms) {
  		// If the reasoner policy does not allow property chains, then
  		// check if the axioms contain such chains and if so, then return false.
  		if ("no_chains".equals(reasoner.getGlobalRestrictionsPolicy())) {
  			for (OWLAxiom ax : axioms) {
  				if (ax instanceof OWLTransitiveObjectPropertyAxiom || ax instanceof OWLSubPropertyChainOfAxiom) {
  					mLogger.info("Reasoner policy ({}) violated: {}", reasoner.getGlobalRestrictionsPolicy(), ax);
  					return false;
  				}
  			}
  		}
  
  		// If the reasoner profile does not allow the given axioms then return false.
  		// TODO: make it more efficient: we probably do not need to create a new ontology
  		boolean isReasonable = true;
  		OWLProfile owlProfile = reasoner.getOWLProfile();
  		if (owlProfile == null) {
  			// Using the default and most permissive profile
  		} else {
  			OWLOntology owlOntology;
  			try {
  				owlOntology = OWL_ONTOLOGY_MANAGER.createOntology(axioms);
  			} catch (OWLOntologyCreationException e) {
  				return false;
  			}
  			if (owlOntology != null) {
  				OWLProfileReport r = owlProfile.checkOntology(owlOntology);
  				for (OWLProfileViolation v : r.getViolations()) {
  					// We do not care about undeclared entities
  					if (!v.toString().startsWith("Use of undeclared")) {
  						isReasonable = false;
  						mLogger.info("Reasoner profile ({}) violation: {}", owlProfile.getName(), v);
  						break;
  					}
  				}
  			}
  			OWL_ONTOLOGY_MANAGER.removeOntology(owlOntology);
  		}
  		return isReasonable;
  	}
  
  
  	/**
  	 * <p>Interprets the given string as a serialization of an OWL ontology,
  	 * maps it to a set of OWL axioms and returns those.</p>
  	 *
  	 * @param str serialization of an OWL ontology e.g. in the OWLFSSPP format
  	 * @return set of OWL axioms
  	 * @throws OWLOntologyCreationException
  	 *
  	 * TODO: not sure if this is the most efficient way to do this
  	 */
  	public static Set<OWLAxiom> getOwlAxiomsFromString(String str) throws OWLOntologyCreationException {
  		OWLOntology owlOntology = OWL_ONTOLOGY_MANAGER.loadOntologyFromOntologyDocument(new StringDocumentSource(str));
  		OWL_ONTOLOGY_MANAGER.removeOntology(owlOntology);
  		return owlOntology.getAxioms();
  	}
  }