org.drools.semantics.builder.model.inference.DelegateInferenceStrategy.java Source code

Java tutorial

Introduction

Here is the source code for org.drools.semantics.builder.model.inference.DelegateInferenceStrategy.java

Source

/*
 * Copyright 2011 JBoss Inc
 *
 * 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.
 */

package org.drools.semantics.builder.model.inference;

//import com.clarkparsia.pellet.owlapiv3.PelletReasonerFactory;

import org.apache.commons.collections15.map.MultiKeyMap;
import org.apache.log4j.Logger;
import org.drools.io.Resource;
import org.drools.runtime.ClassObjectFilter;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.semantics.builder.DLFactoryConfiguration;
import org.drools.semantics.builder.model.Concept;
import org.drools.semantics.builder.model.Individual;
import org.drools.semantics.builder.model.OntoModel;
import org.drools.semantics.builder.model.PropertyRelation;
import org.drools.semantics.builder.model.SubConceptOf;
import org.drools.semantics.utils.NameUtils;
import org.drools.semantics.utils.NamespaceUtils;
import org.drools.util.HierarchySorter;
import org.semanticweb.HermiT.Reasoner;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLCardinalityRestriction;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLClassExpressionVisitor;
import org.semanticweb.owlapi.model.OWLDataAllValuesFrom;
import org.semanticweb.owlapi.model.OWLDataExactCardinality;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataHasValue;
import org.semanticweb.owlapi.model.OWLDataMaxCardinality;
import org.semanticweb.owlapi.model.OWLDataMinCardinality;
import org.semanticweb.owlapi.model.OWLDataOneOf;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyExpression;
import org.semanticweb.owlapi.model.OWLDataPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLDataRange;
import org.semanticweb.owlapi.model.OWLDataSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLHasKeyAxiom;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLInverseObjectPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLNaryBooleanClassExpression;
import org.semanticweb.owlapi.model.OWLObjectAllValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectCardinalityRestriction;
import org.semanticweb.owlapi.model.OWLObjectComplementOf;
import org.semanticweb.owlapi.model.OWLObjectExactCardinality;
import org.semanticweb.owlapi.model.OWLObjectHasSelf;
import org.semanticweb.owlapi.model.OWLObjectHasValue;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectMaxCardinality;
import org.semanticweb.owlapi.model.OWLObjectMinCardinality;
import org.semanticweb.owlapi.model.OWLObjectOneOf;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectUnionOf;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLProperty;
import org.semanticweb.owlapi.model.OWLQuantifiedDataRestriction;
import org.semanticweb.owlapi.model.OWLQuantifiedObjectRestriction;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom;
import org.semanticweb.owlapi.model.RemoveAxiom;
import org.semanticweb.owlapi.reasoner.ConsoleProgressMonitor;
import org.semanticweb.owlapi.reasoner.InferenceType;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerConfiguration;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.reasoner.SimpleConfiguration;
import org.semanticweb.owlapi.util.InferredAxiomGenerator;
import org.semanticweb.owlapi.util.InferredOntologyGenerator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DelegateInferenceStrategy extends AbstractModelInferenceStrategy {

    private static Logger logger = Logger.getLogger(DelegateInferenceStrategy.class);

    private int counter = 0;

    public int minCounter = 0;
    public int maxCounter = 0;

    private Map<OWLClassExpression, OWLClassExpression> aliases;
    private Map<OWLClassExpression, Set<OWLClassExpression>> reverseAliases = new HashMap<OWLClassExpression, Set<OWLClassExpression>>();
    private Map<OWLClassExpression, OWLClass> anonNameAliases = new HashMap<OWLClassExpression, OWLClass>();

    private Map<String, Concept> conceptCache = new LinkedHashMap<String, Concept>();
    private Map<String, String> individualTypesCache = new HashMap<String, String>();
    private Map<OWLClassExpression, OWLClass> fillerCache = new HashMap<OWLClassExpression, OWLClass>();
    private Map<String, String> props = new HashMap<String, String>();

    private MultiKeyMap minCards = new MultiKeyMap();
    private MultiKeyMap maxCards = new MultiKeyMap();

    private static void register(String prim, String klass) {
        IRI i1 = IRI.create(prim);
        Concept con = new Concept(i1, klass, true);
        primitives.put(i1.toQuotedString(), con);
    }

    private static Map<String, Concept> primitives = new HashMap<String, Concept>();

    {

        register("http://www.w3.org/2001/XMLSchema#string", "xsd:string");

        register("http://www.w3.org/2001/XMLSchema#dateTime", "xsd:dateTime");

        register("http://www.w3.org/2001/XMLSchema#date", "xsd:date");

        register("http://www.w3.org/2001/XMLSchema#time", "xsd:time");

        register("http://www.w3.org/2001/XMLSchema#int", "xsd:int");

        register("http://www.w3.org/2001/XMLSchema#integer", "xsd:integer");

        register("http://www.w3.org/2001/XMLSchema#long", "xsd:long");

        register("http://www.w3.org/2001/XMLSchema#float", "xsd:float");

        register("http://www.w3.org/2001/XMLSchema#double", "xsd:double");

        register("http://www.w3.org/2001/XMLSchema#short", "xsd:short");

        register("http://www.w3.org/2000/01/rdf-schema#Literal", "xsd:anySimpleType");

        register("http://www.w3.org/2000/01/rdf-schema#XMLLiteral", "xsd:anySimpleType");

        register("http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral", "xsd:anySimpleType");

        register("http://www.w3.org/2001/XMLSchema#boolean", "xsd:boolean");

        register("http://www.w3.org/2001/XMLSchema#decimal", "xsd:decimal");

        register("http://www.w3.org/2001/XMLSchema#byte", "xsd:byte");

        register("http://www.w3.org/2001/XMLSchema#unsignedByte", "xsd:unsignedByte");

        register("http://www.w3.org/2001/XMLSchema#unsignedShort", "xsd:unsignedShort");

        register("http://www.w3.org/2001/XMLSchema#unsignedInt", "xsd:unsignedInt");

        register("http://www.w3.org/2001/XMLSchema#anyURI", "xsd:anyURI");
    }

    @Override
    protected OntoModel buildProperties(OWLOntology ontoDescr, StatefulKnowledgeSession kSession,
            Map<InferenceTask, Resource> theory, OntoModel hierarchicalModel, DLFactoryConfiguration conf) {

        OWLDataFactory factory = ontoDescr.getOWLOntologyManager().getOWLDataFactory();

        fillPropNamesInDataStructs(ontoDescr);

        // Complete missing domains and ranges for properties. Might be overridden later, if anything can be inferred
        createAndAddBasicProperties(ontoDescr, factory, hierarchicalModel);

        // Apply any cardinality / range restriction
        applyPropertyRestrictions(ontoDescr, hierarchicalModel, factory);

        // Compose property chains
        fixPropertyChains(ontoDescr, hierarchicalModel);

        // Manage inverse relations
        fixInverseRelations(ontoDescr, hierarchicalModel);

        // assign Key properties
        setKeys(ontoDescr, hierarchicalModel);

        fixRootHierarchy(hierarchicalModel);

        validate(hierarchicalModel);

        return hierarchicalModel;
    }

    @Override
    protected OntoModel buildIndividuals(OWLOntology ontoDescr, StatefulKnowledgeSession kSession,
            Map<InferenceTask, Resource> theory, OntoModel hierachicalModel, DLFactoryConfiguration conf) {

        for (OWLNamedIndividual individual : ontoDescr.getIndividualsInSignature(true)) {
            if (logger.isInfoEnabled()) {
                logger.info("Found Individual " + individual.getIRI());
            }
            ;

            IRI iri = individual.getIRI();

            String typeIri = individualTypesCache.get(iri.toQuotedString());
            Concept klass = hierachicalModel.getConcept(typeIri);
            if (klass == null) {
                logger.error("found individual with no class " + iri);
                System.exit(-1);
            }

            Individual ind = new Individual(iri.getFragment(), iri.toQuotedString(), klass.getFullyQualifiedName());

            for (OWLOntology onto : ontoDescr.getImportsClosure()) {
                for (OWLDataPropertyExpression prop : individual.getDataPropertyValues(onto).keySet()) {
                    if (!prop.isTopEntity()) {
                        PropertyRelation rel = hierachicalModel
                                .getProperty(prop.asOWLDataProperty().getIRI().toQuotedString());
                        String propName = rel.getName();
                        Set<OWLLiteral> propValues = individual.getDataPropertyValues(onto).get(prop);
                        Set<Individual.ValueTypePair> values = new HashSet<Individual.ValueTypePair>();
                        for (OWLLiteral tgt : propValues) {
                            String value = null;
                            String typeName = rel.getTarget().getFullyQualifiedName();
                            //TODO improve datatype checking
                            if (typeName.equals("xsd:string") || typeName.equals("xsd:dateTime")) {
                                value = "\"" + tgt.getLiteral() + "\"";
                            } else {
                                value = tgt.getLiteral();
                            }
                            Individual.ValueTypePair vtp = new Individual.ValueTypePair(value, typeName);
                            values.add(vtp);
                        }
                        ind.setPropertyValues(propName, values);
                    }
                }

                for (OWLObjectPropertyExpression prop : individual.getObjectPropertyValues(onto).keySet()) {
                    if (!prop.isTopEntity()) {
                        String propName = hierachicalModel
                                .getProperty(prop.asOWLObjectProperty().getIRI().toQuotedString()).getName();
                        Set<OWLIndividual> propValues = individual.getObjectPropertyValues(onto).get(prop);
                        Set<Individual.ValueTypePair> values = new HashSet<Individual.ValueTypePair>();
                        for (OWLIndividual tgt : propValues) {
                            if (tgt instanceof OWLNamedIndividual) {
                                values.add(new Individual.ValueTypePair(
                                        ((OWLNamedIndividual) tgt).getIRI().getFragment(), "object"));
                            }
                        }
                        ind.setPropertyValues(propName, values);
                    }
                }
            }
            hierachicalModel.addIndividual(ind);

        }

        return hierachicalModel;
    }

    private void fixInverseRelations(OWLOntology ontoDescr, OntoModel hierarchicalModel) {
        for (OWLInverseObjectPropertiesAxiom ax : ontoDescr.getAxioms(AxiomType.INVERSE_OBJECT_PROPERTIES)) {
            String fst = ax.getFirstProperty().asOWLObjectProperty().getIRI().toQuotedString();
            if (!ax.getSecondProperty().isAnonymous()) {
                String sec = ax.getSecondProperty().asOWLObjectProperty().getIRI().toQuotedString();

                PropertyRelation first = hierarchicalModel.getProperty(fst);
                PropertyRelation second = hierarchicalModel.getProperty(sec);

                if (first != null && second != null) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Marking " + first + " as Inverse");
                    }
                    ;
                    first.setInverse(true);
                }
            }
        }
    }

    private void setKeys(OWLOntology ontoDescr, OntoModel hierarchicalModel) {
        for (OWLHasKeyAxiom hasKey : ontoDescr.getAxioms(AxiomType.HAS_KEY)) {
            Concept con = conceptCache.get(hasKey.getClassExpression().asOWLClass().getIRI().toQuotedString());
            for (OWLDataPropertyExpression expr : hasKey.getDataPropertyExpressions()) {
                String propIri = expr.asOWLDataProperty().getIRI().toQuotedString();
                PropertyRelation keyRel = con.getProperties().get(propIri);
                //con.addKey( keyRel.getName() );
                con.addKey(propIri);
            }
            for (OWLObjectPropertyExpression expr : hasKey.getObjectPropertyExpressions()) {
                String propIri = expr.asOWLObjectProperty().getIRI().toQuotedString();
                PropertyRelation keyRel = con.getProperties().get(propIri);
                //                con.addKey( keyRel.getName() );
                con.addKey(propIri);
            }
        }
    }

    private void fixPropertyChains(OWLOntology ontoDescr, OntoModel hierarchicalModel) {
        ontoDescr.getClassesInSignature(true);
        for (OWLSubPropertyChainOfAxiom ax : ontoDescr.getAxioms(AxiomType.SUB_PROPERTY_CHAIN_OF)) {
            String propIri = ax.getSuperProperty().asOWLObjectProperty().getIRI().toQuotedString();
            PropertyRelation prop = hierarchicalModel.getProperty(propIri);
            List<PropertyRelation> chain = new ArrayList<PropertyRelation>();
            for (OWLObjectPropertyExpression link : ax.getPropertyChain()) {
                chain.add(hierarchicalModel.getProperty(link.asOWLObjectProperty().getIRI().toQuotedString()));
            }
            prop.addPropertyChain(chain);
        }
    }

    private void applyPropertyRestrictions(OWLOntology ontoDescr, OntoModel hierarchicalModel,
            OWLDataFactory factory) {

        for (PropertyRelation prop : hierarchicalModel.getProperties()) {
            if (prop.getTarget() == null) {
                logger.warn("Property without target concept " + prop.getName());
            }
        }

        Map<String, Set<OWLClassExpression>> supers = new HashMap<String, Set<OWLClassExpression>>();
        for (OWLClass klass : ontoDescr.getClassesInSignature(true)) {
            supers.put(klass.getIRI().toQuotedString(), new HashSet<OWLClassExpression>());
        }
        for (OWLClass klass : ontoDescr.getClassesInSignature(true)) {
            if (isDelegating(klass)) {
                OWLClassExpression delegate = aliases.get(klass);
                supers.get(delegate.asOWLClass().getIRI().toQuotedString())
                        .addAll(klass.getSuperClasses(ontoDescr));
            } else {
                Set<OWLClassExpression> sup = supers.get(klass.asOWLClass().getIRI().toQuotedString());
                Set<OWLClassExpression> ancestors = klass.getSuperClasses(ontoDescr);
                sup.addAll(ancestors);
                for (OWLClassExpression anc : ancestors) {
                    if (reverseAliases.containsKey(anc)) {
                        sup.addAll(reverseAliases.get(anc));
                    }
                }
            }
        }

        for (Concept con : hierarchicalModel.getConcepts()) { //use concepts as they're sorted!

            if (isDelegating(con.getIri())) {
                continue;
            }

            if (con == null) {
                logger.warn("Looking for superclasses of an undefined concept");
                continue;
            }

            LinkedList<OWLClassExpression> orderedSupers = new LinkedList<OWLClassExpression>();
            // cardinalities should be fixed last
            for (OWLClassExpression sup : supers.get(con.getIri())) {
                if (sup instanceof OWLCardinalityRestriction) {
                    orderedSupers.addLast(sup);
                } else {
                    orderedSupers.addFirst(sup);
                }
            }

            for (OWLClassExpression sup : orderedSupers) {
                if (sup.isClassExpressionLiteral()) {
                    continue;
                }

                processSuperClass(sup, con, hierarchicalModel, factory);
            }

            //            for ( PropertyRelation prop : con.getProperties().values() ) {
            //                if ( prop.isRestricted() && ( prop.getMaxCard() == null || prop.getMaxCard() > 1 ) ) {
            //                    prop.setName( prop.getName() + "s" );
            //                }
            //            }
        }

    }

    private void processSuperClass(OWLClassExpression sup, Concept con, OntoModel hierarchicalModel,
            OWLDataFactory factory) {
        String propIri;
        PropertyRelation rel;
        Concept tgt;
        switch (sup.getClassExpressionType()) {
        case DATA_SOME_VALUES_FROM:
            //check that it's a subclass of the domain. Should have already been done, or it would be an inconsistency
            break;
        case DATA_ALL_VALUES_FROM:
            OWLDataAllValuesFrom forall = (OWLDataAllValuesFrom) sup;
            propIri = forall.getProperty().asOWLDataProperty().getIRI().toQuotedString();
            tgt = primitives.get(dataRangeToDataType(forall.getFiller(), factory).getIRI().toQuotedString());
            if (tgt.equals("xsd:anySimpleType")) {
                break;
            }
            rel = extractProperty(con, propIri, tgt, null, null, true);
            if (rel != null) {
                //                    hierarchicalModel.addProperty( rel );
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case DATA_MIN_CARDINALITY:
            OWLDataMinCardinality min = (OWLDataMinCardinality) sup;
            propIri = min.getProperty().asOWLDataProperty().getIRI().toQuotedString();
            tgt = primitives.get(dataRangeToDataType(min.getFiller(), factory).getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, min.getCardinality(), null, false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case DATA_MAX_CARDINALITY:
            OWLDataMaxCardinality max = (OWLDataMaxCardinality) sup;
            propIri = max.getProperty().asOWLDataProperty().getIRI().toQuotedString();
            tgt = primitives.get(dataRangeToDataType(max.getFiller(), factory).getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, null, max.getCardinality(), false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case DATA_EXACT_CARDINALITY:
            OWLDataExactCardinality ex = (OWLDataExactCardinality) sup;
            propIri = ex.getProperty().asOWLDataProperty().getIRI().toQuotedString();
            tgt = primitives.get(dataRangeToDataType(ex.getFiller(), factory).getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, ex.getCardinality(), ex.getCardinality(), false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case OBJECT_SOME_VALUES_FROM:
            OWLObjectSomeValuesFrom someO = (OWLObjectSomeValuesFrom) sup;
            propIri = someO.getProperty().asOWLObjectProperty().getIRI().toQuotedString();
            if (filterAliases(someO.getFiller()).isAnonymous()) {
                logger.warn(": Complex unaliased restriction " + someO);
                break;
            }
            tgt = conceptCache.get(filterAliases(someO.getFiller()).asOWLClass().getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, 1, null, false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case OBJECT_ALL_VALUES_FROM:
            OWLObjectAllValuesFrom forallO = (OWLObjectAllValuesFrom) sup;
            propIri = forallO.getProperty().asOWLObjectProperty().getIRI().toQuotedString();
            if (filterAliases(forallO.getFiller()).isAnonymous()) {
                logger.warn(": Complex unaliased restriction " + forallO);
                break;
            }
            tgt = conceptCache.get(filterAliases(forallO.getFiller()).asOWLClass().getIRI().toQuotedString());
            if (tgt.equals("<http://www.w3.org/2002/07/owl#Thing>")) {
                break;
            }
            rel = extractProperty(con, propIri, tgt, null, null, true);
            if (rel != null) {
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case OBJECT_MIN_CARDINALITY:
            OWLObjectMinCardinality minO = (OWLObjectMinCardinality) sup;
            propIri = minO.getProperty().asOWLObjectProperty().getIRI().toQuotedString();
            tgt = conceptCache.get(filterAliases(minO.getFiller()).asOWLClass().getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, minO.getCardinality(), null, false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case OBJECT_MAX_CARDINALITY:
            OWLObjectMaxCardinality maxO = (OWLObjectMaxCardinality) sup;
            propIri = maxO.getProperty().asOWLObjectProperty().getIRI().toQuotedString();
            tgt = conceptCache.get(filterAliases(maxO.getFiller()).asOWLClass().getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, null, maxO.getCardinality(), false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case OBJECT_EXACT_CARDINALITY:
            OWLObjectExactCardinality exO = (OWLObjectExactCardinality) sup;
            propIri = exO.getProperty().asOWLObjectProperty().getIRI().toQuotedString();
            tgt = conceptCache.get(filterAliases(exO.getFiller()).asOWLClass().getIRI().toQuotedString());
            rel = extractProperty(con, propIri, tgt, exO.getCardinality(), exO.getCardinality(), false);
            if (rel != null) {
                hierarchicalModel.addProperty(rel);
            } else {
                logger.warn(" Could not find property " + propIri + " restricted in class " + con.getIri());
            }
            break;
        case OBJECT_INTERSECTION_OF:
            OWLObjectIntersectionOf and = (OWLObjectIntersectionOf) sup;
            for (OWLClassExpression arg : and.asConjunctSet()) {
                processSuperClass(arg, con, hierarchicalModel, factory);
            }
            break;
        case OWL_CLASS:
            break;
        default:
            logger.warn(" Cannot handle " + sup);
        }

    }

    private String createSuffix(String role, String name, boolean plural) {
        String type = NameUtils.map(name, true);
        if (type.indexOf(".") >= 0) {
            type = type.substring(type.lastIndexOf(".") + 1);
        }
        return type + (plural ? (type.endsWith("s") ? "es" : "s") : ""); // + "As" + role;
    }

    private PropertyRelation extractProperty(Concept con, String propIri, Concept target, Integer min, Integer max,
            boolean restrictTarget) {
        if (target == null) {
            logger.warn("Null target for property " + propIri);
        }

        String restrictedSuffix = createSuffix(con.getName(), target.getName(), true);
        String restrictedPropIri = propIri.replace(">", restrictedSuffix + ">");

        //        PropertyRelation rel = con.getProperties().get( propIri );
        //        if ( rel == null ) {
        //            rel = con.getProperties().get( restrictedPropIri );
        //        }
        //
        //        if ( rel == null ) {
        //            rel = inheritPropertyCopy( con, con, propIri );
        //            inherited = true;
        //        }

        boolean alreadyRestricted = false;
        PropertyRelation rel = con.getProperties().get(propIri);
        PropertyRelation originalProperty;

        if (rel != null) {
            originalProperty = rel;
            rel = cloneRel(originalProperty);
        } else {
            rel = con.getProperties().get(restrictedPropIri);

            if (rel != null) {
                originalProperty = rel;
                alreadyRestricted = true;
                rel = cloneRel(originalProperty);
            } else {
                PropertyRelation source = inheritPropertyCopy(con, con, restrictedPropIri);

                if (source != null) {
                    originalProperty = source;
                    alreadyRestricted = true;
                    rel = cloneRel(originalProperty);
                } else {
                    originalProperty = inheritPropertyCopy(con, con, propIri);
                    rel = cloneRel(originalProperty);
                }
            }
        }

        if (rel != null) {
            boolean tgtRestrictionApplied = restrictTarget && !rel.getTarget().equals(target);
            if (tgtRestrictionApplied) {
                rel.restrictTargetTo(target);
            }

            boolean dirty = false;
            if (target.getIri().equals("<http://www.w3.org/2002/07/owl#Thing>")
                    || target.getIri().equals("<http://www.w3.org/2000/01/rdf-schema#Literal>")
                    || target.getEquivalentConcepts()
                            .contains(conceptCache.get("<http://www.w3.org/2002/07/owl#Thing>"))) {
                target = rel.getTarget();
                restrictedSuffix = createSuffix(con.getName(), target.getName(), true);
                restrictedPropIri = propIri.replace(">", restrictedSuffix + ">");
                //                dirty = true;
            }
            if (!rel.getTarget().equals(target) && !restrictTarget) {
                //TODO FIXME : check that target is really restrictive!
                if (!target.getIri().equals("<http://www.w3.org/2002/07/owl#Thing>")
                        && !target.getIri().equals("<http://www.w3.org/2000/01/rdf-schema#Literal>")) {
                    rel.setTarget(target);
                    rel.setObject(target.getIri());
                    dirty = true;
                }
            }
            if (min != null && min > rel.getMinCard()) {
                rel.setMinCard(min);
                //                if ( min > 1 ) {
                dirty = true;
                //                }
            }
            if (max != null && (rel.getMaxCard() == null || max < rel.getMaxCard())) {
                rel.setMaxCard(max);
                if (max == 1) {
                    if (alreadyRestricted) {
                        con.removeProperty(restrictedPropIri);
                    }
                    restrictedSuffix = createSuffix(con.getName(), target.getName(), false);
                    restrictedPropIri = propIri.replace(">", restrictedSuffix + ">");
                }
                dirty = true;
            }
            //            if ( dirty ) {

            if (dirty) {
                if (!target.isPrimitive() || !rel.getDomain().equals(con)) {
                    rel.setRestricted(true);
                    rel.setName(originalProperty.getBaseProperty().getName() + restrictedSuffix);
                    rel.setProperty(restrictedPropIri);
                } else {
                    if (rel.getMaxCard() != null && rel.getMaxCard() <= 1) {
                        rel.setSimple(true);
                    }
                }

            }

            rel.setSubject(con.getIri());
            rel.setDomain(con);

            boolean inherited = false;
            for (Concept sup : con.getSuperConcepts()) {
                if (sup.getEffectiveProperties().contains(rel)) {
                    inherited = true;
                    rel.setInherited(inherited);
                    break;
                }
            }

            if (!rel.mirrors(rel.getBaseProperty())) {
                con.addProperty(rel.getProperty(), rel.getName(), rel);
            }

            if (dirty) {
                rel.setBaseProperty(originalProperty);
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("No real restriction detected II " + rel.getName());
                }
                rel = originalProperty;
            }

            rel.getDomain().addProperty(rel.getProperty(), rel.getName(), rel);

            return rel;

        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("No real restriction detected");
            }
            // rel is null and that is what will be returned
        }

        return rel;
    }

    private PropertyRelation inheritPropertyCopy(Concept original, Concept current, String propIri) {
        PropertyRelation rel;
        for (Concept sup : current.getSuperConcepts()) {
            //            String key = propIri.replace( "As"+current.getName(), "As"+sup.getName() );
            String key = propIri;
            rel = sup.getProperties().get(key);
            if (rel != null) {
                return rel;
            } else {
                rel = inheritPropertyCopy(original, sup, propIri);
                if (rel != null) {
                    return rel;
                }
            }
        }
        return null;

    }

    private PropertyRelation cloneRel(PropertyRelation rel) {
        PropertyRelation clonedRel = new PropertyRelation(rel.getSubject(), rel.getProperty(), rel.getObject(),
                rel.getName());
        clonedRel.setMinCard(rel.getMinCard());
        clonedRel.setMaxCard(rel.getMaxCard());
        clonedRel.setTarget(rel.getTarget());
        clonedRel.setDomain(rel.getDomain());
        clonedRel.setRestricted(rel.isRestricted());
        return clonedRel;

    }

    private void createAndAddBasicProperties(OWLOntology ontoDescr, OWLDataFactory factory,
            OntoModel hierarchicalModel) {
        int missDomain = 0;
        int missDataRange = 0;
        int missObjectRange = 0;

        for (OWLDataProperty dp : ontoDescr.getDataPropertiesInSignature(true)) {
            if (!dp.isOWLTopDataProperty() && !dp.isOWLBottomDataProperty()) {
                Set<OWLClassExpression> domains = dp.getDomains(ontoDescr.getImportsClosure());
                if (domains.isEmpty()) {
                    domains.add(factory.getOWLThing());
                    logger.warn("Added missing domain for" + dp);
                    missDomain++;
                }
                Set<OWLDataRange> ranges = dp.getRanges(ontoDescr.getImportsClosure());
                if (ranges.isEmpty()) {
                    ranges.add(factory.getRDFPlainLiteral());
                    logger.warn("Added missing range for" + dp);
                    missDataRange++;
                }

                for (OWLClassExpression domain : domains) {
                    for (OWLDataRange range : ranges) {
                        OWLClassExpression realDom = filterAliases(domain);
                        OWLDatatype dataRange = dataRangeToDataType(range, factory);
                        PropertyRelation rel = new PropertyRelation(realDom.asOWLClass().getIRI().toQuotedString(),
                                dp.getIRI().toQuotedString(), dataRange.getIRI().toQuotedString(),
                                props.get(dp.getIRI().toQuotedString()));

                        Concept con = conceptCache.get(rel.getSubject());
                        rel.setTarget(primitives.get(rel.getObject()));
                        rel.setDomain(con);

                        con.addProperty(rel.getProperty(), rel.getName(), rel);
                        hierarchicalModel.addProperty(rel);
                    }
                }
            }
        }

        for (OWLObjectProperty op : ontoDescr.getObjectPropertiesInSignature(true)) {
            if (!op.isOWLTopObjectProperty() && !op.isOWLBottomObjectProperty()) {
                Set<OWLClassExpression> domains = op.getDomains(ontoDescr.getImportsClosure());
                if (domains.isEmpty()) {
                    domains.add(factory.getOWLThing());
                    logger.warn("Added missing domain for " + op);
                    missDomain++;
                }
                Set<OWLClassExpression> ranges = op.getRanges(ontoDescr.getImportsClosure());
                if (ranges.isEmpty()) {
                    ranges.add(factory.getOWLThing());
                    logger.warn("Added missing range for " + op);
                    missObjectRange++;
                }

                for (OWLClassExpression domain : domains) {
                    for (OWLClassExpression range : ranges) {
                        OWLClassExpression realDom = filterAliases(domain);
                        OWLClassExpression realRan = filterAliases(range);

                        if (realDom.isAnonymous() || realRan.isAnonymous()) {
                            logger.error("Domain and Range should no be anonymous at this point : DOM " + realDom
                                    + " RAN : " + range);
                        }
                        PropertyRelation rel = new PropertyRelation(realDom.asOWLClass().getIRI().toQuotedString(),
                                op.getIRI().toQuotedString(), realRan.asOWLClass().getIRI().toQuotedString(),
                                props.get(op.getIRI().toQuotedString()));

                        Concept con = conceptCache.get(rel.getSubject());
                        rel.setTarget(conceptCache.get(rel.getObject()));
                        rel.setDomain(con);

                        con.addProperty(rel.getProperty(), rel.getName(), rel);
                        hierarchicalModel.addProperty(rel);
                    }
                }
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("Misses : ");
            logger.info(missDomain);
            logger.info(missDataRange);
            logger.info(missObjectRange);
        }
    }

    private OWLDatatype dataRangeToDataType(OWLDataRange range, OWLDataFactory factory) {
        if (range.isDatatype()) {
            return range.asOWLDatatype();
        }
        if (range instanceof OWLDataOneOf) {
            OWLDataOneOf oneOf = (OWLDataOneOf) range;
            Iterator<OWLLiteral> literals = oneOf.getValues().iterator();
            OWLDatatype type = literals.next().getDatatype();
            while (literals.hasNext()) {
                OWLDatatype x = literals.next().getDatatype();
                if (!type.equals(x)) {
                    return factory.getTopDatatype();
                }
            }
            return type;
        }
        return range.asOWLDatatype();
    }

    private Map<OWLClassExpression, OWLClassExpression> buildAliasesForEquivalentClasses(OWLOntology ontoDescr) {
        Map<OWLClassExpression, OWLClassExpression> aliases = new HashMap<OWLClassExpression, OWLClassExpression>();
        Set<OWLEquivalentClassesAxiom> pool = new HashSet<OWLEquivalentClassesAxiom>();
        Set<OWLEquivalentClassesAxiom> temp = new HashSet<OWLEquivalentClassesAxiom>();

        for (OWLClass klass : ontoDescr.getClassesInSignature(true)) {
            for (OWLEquivalentClassesAxiom klassEq : ontoDescr.getEquivalentClassesAxioms(klass)) {
                for (OWLEquivalentClassesAxiom eq2 : klassEq.asPairwiseAxioms()) {
                    pool.add(eq2);
                }
            }
        }

        boolean stable = false;
        while (!stable) {
            stable = true;
            temp.addAll(pool);
            for (OWLEquivalentClassesAxiom eq2 : pool) {

                List<OWLClassExpression> pair = eq2.getClassExpressionsAsList();
                OWLClassExpression first = pair.get(0);
                OWLClassExpression secnd = pair.get(1);
                OWLClassExpression removed = null;

                if (aliases.containsValue(first)) {
                    // add to existing eqSet, put reversed
                    // A->X,  add X->C          ==> A->X, C->X
                    removed = aliases.put(secnd, first);
                    if (removed != null) {
                        logger.warn("DUPLICATE KEY WHILE RESOLVING EQUALITIES" + removed + " for value " + eq2);
                    }

                    stable = false;
                    temp.remove(eq2);
                } else if (aliases.containsValue(secnd)) {
                    // add to existing eqSet, put as is
                    // A->X,  add C->X          ==> A->X, C->X
                    removed = aliases.put(first, secnd);
                    if (removed != null) {
                        logger.warn("DUPLICATE KEY WHILE RESOLVING EQUALITIES" + removed + " for value " + eq2);
                    }

                    stable = false;
                    temp.remove(eq2);
                } else if (aliases.containsKey(first)) {
                    // apply transitivity, reversed
                    // A->X,  add A->C          ==> A->X, C->X
                    removed = aliases.put(secnd, aliases.get(first));
                    if (removed != null) {
                        logger.warn("DUPLICATE KEY WHILE RESOLVING EQUALITIES" + removed + " for value " + eq2);
                    }

                    stable = false;
                    temp.remove(eq2);
                } else if (aliases.containsKey(secnd)) {
                    // apply transitivity, as is
                    // A->X,  add C->A          ==> A->X, C->X
                    removed = aliases.put(first, aliases.get(secnd));
                    if (removed != null) {
                        logger.warn("DUPLICATE KEY WHILE RESOLVING EQUALITIES" + removed + " for value " + eq2);
                    }

                    stable = false;
                    temp.remove(eq2);
                } else if (!first.isAnonymous()) {
                    removed = aliases.put(secnd, first);
                    if (removed != null) {
                        logger.warn("DUPLICATE KEY WHILE RESOLVING EQUALITIES" + removed + " for value " + eq2);
                    }

                    stable = false;
                    temp.remove(eq2);
                } else if (!secnd.isAnonymous()) {
                    removed = aliases.put(first, secnd);
                    if (removed != null) {
                        logger.warn("DUPLICATE KEY WHILE RESOLVING EQUALITIES" + removed + " for value " + eq2);
                    }

                    stable = false;
                    temp.remove(eq2);
                } else {
                    // both anonymous
                }

            }
            pool.clear();
            pool.addAll(temp);
        }

        if (!pool.isEmpty()) {
            logger.error("COULD NOT RESOLVE ANON=ANON EQUALITIES " + pool);
            for (OWLEquivalentClassesAxiom eq2 : pool) {
                List<OWLClassExpression> l = eq2.getClassExpressionsAsList();
                if (!(l.get(0).isAnonymous() && l.get(1).isAnonymous())) {
                    logger.error(" EQUALITY WAS NOT RESOLVED " + l);
                }
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info(
                    "----------------------------------------------------------------------- " + aliases.size());
            for (Map.Entry<OWLClassExpression, OWLClassExpression> entry : aliases.entrySet()) {
                logger.trace(entry.getKey() + " == " + entry.getValue());
            }
            logger.info("-----------------------------------------------------------------------");
        }

        for (Map.Entry<OWLClassExpression, OWLClassExpression> entry : aliases.entrySet()) {
            OWLClassExpression key = entry.getKey();
            OWLClassExpression val = entry.getValue();
            if (!reverseAliases.containsKey(val)) {
                reverseAliases.put(val, new HashSet<OWLClassExpression>());
            }
            reverseAliases.get(val).add(key);
        }
        return aliases;
    }

    private boolean isAbstract(OWLClassExpression clax) {
        return clax.asOWLClass().getIRI().toQuotedString().contains("Filler");
    }

    private boolean processComplexSuperClassesDomainAndRanges(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        dirty |= processComplexSuperclasses(ontoDescr, factory);
        dirty |= processComplexDataPropertyDomains(ontoDescr, factory);
        dirty |= processComplexObjectPropertyDomains(ontoDescr, factory);
        dirty |= processComplexObjectPropertyRanges(ontoDescr, factory);
        return dirty;
    }

    private boolean processComplexSuperclasses(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        for (OWLSubClassOfAxiom sub : ontoDescr.getAxioms(AxiomType.SUBCLASS_OF, true)) {

            if (sub.getSuperClass().isAnonymous()) {
                if (sub.getSuperClass() instanceof OWLObjectUnionOf) {
                    Iterator<OWLClassExpression> disjuncts = sub.getSuperClass().asDisjunctSet().iterator();

                    String orNames = asNamedClass(disjuncts.next(), factory, ontoDescr).getIRI().getFragment();
                    while (disjuncts.hasNext()) {
                        OWLClass disjunct = asNamedClass(disjuncts.next(), factory, ontoDescr);
                        orNames += "or" + disjunct.asOWLClass().getIRI().getFragment();
                    }

                    OWLClass unjon = factory.getOWLClass(IRI.create(
                            NameUtils.separatingName(ontoDescr.getOntologyID().getOntologyIRI().toURI().toString())
                                    + orNames));
                    ontoDescr.getOWLOntologyManager()
                            .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(unjon)));
                    ontoDescr.getOWLOntologyManager().applyChange(new AddAxiom(ontoDescr,
                            factory.getOWLEquivalentClassesAxiom(sub.getSuperClass(), unjon)));
                    dirty = true;
                }

            }

        }
        return dirty;
    }

    private OWLClass asNamedClass(OWLClassExpression owlClass, OWLDataFactory factory, OWLOntology ontoDescr) {
        if (!owlClass.isAnonymous()) {
            return owlClass.asOWLClass();
        }

        if (anonNameAliases.containsKey(owlClass)) {
            return anonNameAliases.get(owlClass);
        }

        OWLClass alias = factory.getOWLClass(
                IRI.create(NameUtils.separatingName(ontoDescr.getOntologyID().getOntologyIRI().toURI().toString())
                        + "Anon" + counter++));

        ontoDescr.getOWLOntologyManager()
                .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(alias)));
        ontoDescr.getOWLOntologyManager()
                .applyChange(new AddAxiom(ontoDescr, factory.getOWLEquivalentClassesAxiom(owlClass, alias)));

        anonNameAliases.put(owlClass, alias);
        return alias;
    }

    private boolean processComplexObjectPropertyDomains(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        for (OWLObjectProperty op : ontoDescr.getObjectPropertiesInSignature(true)) {
            String typeName = NameUtils.buildNameFromIri(op.getIRI().getStart(), op.getIRI().getFragment());

            Set<OWLObjectPropertyDomainAxiom> domains = ontoDescr.getObjectPropertyDomainAxioms(op);
            if (domains.size() > 1) {
                Set<OWLClassExpression> domainClasses = new HashSet<OWLClassExpression>();
                for (OWLObjectPropertyDomainAxiom dom : domains) {
                    domainClasses.add(dom.getDomain());
                }
                OWLObjectIntersectionOf and = factory.getOWLObjectIntersectionOf(domainClasses);

                for (OWLObjectPropertyDomainAxiom dom : domains) {
                    ontoDescr.getOWLOntologyManager().applyChange(new RemoveAxiom(ontoDescr, dom));
                }
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLObjectPropertyDomainAxiom(op, and)));
                dirty = true;
            }

            if (op.getDomains(ontoDescr).size() > 1) {
                logger.warn(
                        "Property " + op + " should have a single domain class, found " + op.getDomains(ontoDescr));
            }

            for (OWLClassExpression dom : op.getDomains(ontoDescr.getImportsClosure())) {
                if (dom.isAnonymous()) {
                    OWLClass domain = factory.getOWLClass(IRI.create(
                            NameUtils.separatingName(ontoDescr.getOntologyID().getOntologyIRI().toURI().toString())
                                    + NameUtils.capitalize(typeName) + "Domain"));
                    OWLAnnotationAssertionAxiom ann = factory.getOWLAnnotationAssertionAxiom(
                            factory.getOWLAnnotationProperty(
                                    IRI.create("http://www.w3.org/2000/01/rdf-schema#comment")),
                            domain.getIRI(), factory.getOWLStringLiteral("abstract"));
                    if (logger.isDebugEnabled()) {
                        logger.debug("REPLACED ANON DOMAIN " + op + " with " + domain + ", was " + dom);
                    }
                    logger.warn("REPLACED ANON DOMAIN " + op + " with " + domain + ", was " + dom);
                    ontoDescr.getOWLOntologyManager()
                            .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(domain)));
                    ontoDescr.getOWLOntologyManager().applyChange(
                            new AddAxiom(ontoDescr, factory.getOWLEquivalentClassesAxiom(domain, dom)));

                    OWLOntology defining = lookupDefiningOntology(ontoDescr, op);
                    ontoDescr.getOWLOntologyManager().applyChange(new RemoveAxiom(defining,
                            defining.getObjectPropertyDomainAxioms(op).iterator().next()));
                    ontoDescr.getOWLOntologyManager().applyChange(
                            new AddAxiom(ontoDescr, factory.getOWLObjectPropertyDomainAxiom(op, domain)));
                    ontoDescr.getOWLOntologyManager().applyChange(new AddAxiom(ontoDescr, ann));
                    dirty = true;
                }
            }

        }
        return dirty;
    }

    private OWLOntology lookupDefiningOntology(OWLOntology ontoDescr, OWLEntity axiom) {
        List<OWLOntology> imports = ontoDescr.getOWLOntologyManager().getSortedImportsClosure(ontoDescr);
        OWLOntology defining = ontoDescr;
        for (OWLOntology onto : imports) {
            if (onto.containsAxiom(
                    ontoDescr.getOWLOntologyManager().getOWLDataFactory().getOWLDeclarationAxiom(axiom), false)) {
                defining = onto;
                break;
            }
        }
        return defining;
    }

    private boolean processComplexDataPropertyDomains(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        for (OWLDataProperty dp : ontoDescr.getDataPropertiesInSignature(true)) {
            String typeName = NameUtils.buildNameFromIri(dp.getIRI().getStart(), dp.getIRI().getFragment());

            OWLOntology defining = lookupDefiningOntology(ontoDescr, dp);
            Set<OWLDataPropertyDomainAxiom> domains = defining.getDataPropertyDomainAxioms(dp);
            if (domains.size() > 1) {
                Set<OWLClassExpression> domainClasses = new HashSet<OWLClassExpression>();
                for (OWLDataPropertyDomainAxiom dom : domains) {
                    domainClasses.add(dom.getDomain());
                }
                OWLObjectIntersectionOf and = factory.getOWLObjectIntersectionOf(domainClasses);

                for (OWLDataPropertyDomainAxiom dom : domains) {
                    defining.getOWLOntologyManager().applyChange(new RemoveAxiom(defining, dom));
                }
                defining.getOWLOntologyManager()
                        .applyChange(new AddAxiom(defining, factory.getOWLDataPropertyDomainAxiom(dp, and)));
                dirty = true;
            }

            if (dp.getDomains(ontoDescr).size() > 1) {
                logger.warn(
                        "Property " + dp + " should have a single domain class, found " + dp.getDomains(ontoDescr));
            }

            for (OWLClassExpression dom : dp.getDomains(defining)) {
                if (dom.isAnonymous()) {
                    OWLClass domain = factory.getOWLClass(IRI.create(
                            NameUtils.separatingName(ontoDescr.getOntologyID().getOntologyIRI().toURI().toString())
                                    + NameUtils.capitalize(typeName) + "Domain"));
                    OWLAnnotationAssertionAxiom ann = factory.getOWLAnnotationAssertionAxiom(
                            factory.getOWLAnnotationProperty(
                                    IRI.create("http://www.w3.org/2000/01/rdf-schema#comment")),
                            domain.getIRI(), factory.getOWLStringLiteral("abstract"));
                    if (logger.isDebugEnabled()) {
                        logger.debug("INFO : REPLACED ANON DOMAIN " + dp + " with " + domain + ", was " + dom);
                    }
                    defining.getOWLOntologyManager()
                            .applyChange(new AddAxiom(defining, factory.getOWLDeclarationAxiom(domain)));
                    defining.getOWLOntologyManager()
                            .applyChange(new AddAxiom(defining, factory.getOWLEquivalentClassesAxiom(domain, dom)));

                    defining.getOWLOntologyManager().applyChange(
                            new RemoveAxiom(defining, defining.getDataPropertyDomainAxioms(dp).iterator().next()));
                    defining.getOWLOntologyManager()
                            .applyChange(new AddAxiom(defining, factory.getOWLDataPropertyDomainAxiom(dp, domain)));
                    defining.getOWLOntologyManager().applyChange(new AddAxiom(defining, ann));
                    dirty = true;
                }
            }

        }
        return dirty;
    }

    private boolean processComplexObjectPropertyRanges(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        for (OWLObjectProperty op : ontoDescr.getObjectPropertiesInSignature(true)) {
            String typeName = NameUtils.buildNameFromIri(op.getIRI().getStart(), op.getIRI().getFragment());

            Set<OWLObjectPropertyRangeAxiom> ranges = ontoDescr.getObjectPropertyRangeAxioms(op);
            if (ranges.size() > 1) {
                Set<OWLClassExpression> rangeClasses = new HashSet<OWLClassExpression>();
                for (OWLObjectPropertyRangeAxiom dom : ranges) {
                    rangeClasses.add(dom.getRange());
                }
                OWLObjectIntersectionOf and = factory.getOWLObjectIntersectionOf(rangeClasses);

                for (OWLObjectPropertyRangeAxiom ran : ranges) {
                    ontoDescr.getOWLOntologyManager().applyChange(new RemoveAxiom(ontoDescr, ran));
                }
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLObjectPropertyRangeAxiom(op, and)));
                dirty = true;
            }

            if (op.getRanges(ontoDescr).size() > 1) {
                logger.warn(" WARNING : Property " + op + " should have a single range class, found "
                        + op.getRanges(ontoDescr));
            }

            for (OWLClassExpression ran : op.getRanges(ontoDescr.getImportsClosure())) {
                if (ran.isAnonymous()) {
                    OWLClass range = factory.getOWLClass(IRI.create(
                            NameUtils.separatingName(ontoDescr.getOntologyID().getOntologyIRI().toURI().toString())
                                    + NameUtils.capitalize(typeName) + "Range"));
                    OWLAnnotationAssertionAxiom ann = factory.getOWLAnnotationAssertionAxiom(
                            factory.getOWLAnnotationProperty(
                                    IRI.create("http://www.w3.org/2000/01/rdf-schema#comment")),
                            range.getIRI(), factory.getOWLLiteral("abstract"));
                    if (logger.isDebugEnabled()) {
                        logger.debug(" REPLACED ANON RANGE " + op + " with " + range + ", was " + ran);
                    }
                    ontoDescr.getOWLOntologyManager()
                            .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(range)));
                    ontoDescr.getOWLOntologyManager()
                            .applyChange(new AddAxiom(ontoDescr, factory.getOWLEquivalentClassesAxiom(range, ran)));

                    OWLObjectPropertyRangeAxiom rangx = null;
                    Set<OWLOntology> ontologies = ontoDescr.getImportsClosure();
                    for (OWLOntology onto : ontologies) {
                        Set<OWLObjectPropertyRangeAxiom> assertedRanges = onto.getObjectPropertyRangeAxioms(op);
                        if (!assertedRanges.isEmpty()) {
                            rangx = assertedRanges.iterator().next();
                            ontoDescr.getOWLOntologyManager().applyChange(new RemoveAxiom(ontoDescr, rangx));
                        }
                    }
                    ontoDescr.getOWLOntologyManager().applyChange(
                            new AddAxiom(ontoDescr, factory.getOWLObjectPropertyRangeAxiom(op, range)));
                    ontoDescr.getOWLOntologyManager().applyChange(new AddAxiom(ontoDescr, ann));
                    dirty = true;
                }
            }

        }
        return dirty;
    }

    private boolean preProcessIndividuals(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        for (OWLNamedIndividual ind : ontoDescr.getIndividualsInSignature(true)) {

            OWLOntology defining = lookupDefiningOntology(ontoDescr, ind);

            declareAnonymousIndividualSupertypes(defining, factory, ind);

            logger.info("Defining ontology :  " + defining);
            for (OWLAxiom ax : defining.getAxioms(AxiomType.CLASS_ASSERTION)) {
                logger.trace(ax);
            }

            logger.info("Getting types for individual " + ind.getIRI());
            Set<OWLClassExpression> types = ind.getTypes(defining);
            logger.info("Found types in defining ontology" + types);
            if (types.isEmpty()) {
                ind.getTypes(ontoDescr.getImportsClosure());
                logger.info("Found types in all ontologies " + ontoDescr.getImportsClosure() + " >> " + types);
            }

            types = simplify(types, defining);
            if (types.size() > 1) {
                OWLObjectIntersectionOf and = factory.getOWLObjectIntersectionOf(types);

                dirty = true;
                logger.warn(" Individual " + ind + " got a new combined type " + and);
                OWLClass type = factory.getOWLClass(IRI.create(
                        ind.getIRI().getStart() + NameUtils.compactUpperCase(ind.getIRI().getFragment()) + "Type"));
                defining.getOWLOntologyManager()
                        .applyChange(new AddAxiom(defining, factory.getOWLDeclarationAxiom(type)));
                defining.getOWLOntologyManager()
                        .applyChange(new AddAxiom(defining, factory.getOWLSubClassOfAxiom(type, and)));
                defining.getOWLOntologyManager()
                        .applyChange(new AddAxiom(defining, factory.getOWLClassAssertionAxiom(type, ind)));

                individualTypesCache.put(ind.getIRI().toQuotedString(), type.getIRI().toQuotedString());
            } else {
                if (types.iterator().hasNext()) {
                    individualTypesCache.put(ind.getIRI().toQuotedString(),
                            types.iterator().next().asOWLClass().getIRI().toQuotedString());
                } else {

                    logger.warn("WARNING no type detected for individual " + ind.getIRI().toQuotedString());
                }
            }

        }

        return dirty;
    }

    private void declareAnonymousIndividualSupertypes(OWLOntology ontoDescr, OWLDataFactory factory,
            OWLNamedIndividual ind) {
        Set<OWLClassExpression> types = ind.getTypes(ontoDescr);
        int j = 0;
        for (OWLClassExpression type : types) {
            j++;
            if (type.isAnonymous()) {
                OWLClass temp = factory.getOWLClass(IRI.create(ind.getIRI().getStart()
                        + NameUtils.compactUpperCase(ind.getIRI().getFragment()) + "RestrictedType" + j));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new RemoveAxiom(ontoDescr, factory.getOWLClassAssertionAxiom(type, ind)));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(temp)));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLEquivalentClassesAxiom(temp, type)));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLClassAssertionAxiom(temp, ind)));
            }
        }

    }

    private Set<OWLClassExpression> simplify(Set<OWLClassExpression> types, OWLOntology ontoDescr) {
        if (types.size() == 1) {
            return types;
        }
        Set<OWLClassExpression> ans = new HashSet<OWLClassExpression>(types);

        for (OWLClassExpression klass1 : types) {
            for (OWLClassExpression klass2 : types) {
                if (isSuperClass(ontoDescr, klass1, klass2)) {
                    ans.remove(klass1);
                }
            }
        }

        return ans;
    }

    private boolean isSuperClass(OWLOntology ontoDescr, Set<OWLClassExpression> supers, OWLClassExpression klass2) {
        OWLClass k = klass2.asOWLClass();
        OWLOntology defining = lookupDefiningOntology(ontoDescr, k);
        Set<OWLSubClassOfAxiom> subKlassOfs = defining.getSubClassAxiomsForSubClass(k);
        for (OWLSubClassOfAxiom sub : subKlassOfs) {
            if (supers.contains(sub.getSuperClass())) {
                return true;
            } else {
                if (!sub.getSuperClass().isAnonymous() && isSuperClass(ontoDescr, supers, sub.getSuperClass())) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isSuperClass(OWLOntology ontoDescr, OWLClassExpression klass1, OWLClassExpression klass2) {
        Set<OWLSubClassOfAxiom> subKlassOfs = ontoDescr.getSubClassAxiomsForSuperClass(klass1.asOWLClass());
        for (OWLSubClassOfAxiom sub : subKlassOfs) {
            if (sub.getSubClass().equals(klass2)) {
                return true;
            } else {
                if (isSuperClass(ontoDescr, sub.getSubClass(), klass2)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean processQuantifiedRestrictions(OWLOntology ontoDescr, OWLDataFactory factory) {
        boolean dirty = false;
        // infer domain / range from quantified restrictions...
        for (OWLClass klassAx : ontoDescr.getClassesInSignature(true)) {
            OWLClass klass = klassAx;

            for (OWLClassExpression clax : klass.getSuperClasses(ontoDescr)) {
                clax = clax.getNNF();
                dirty |= processQuantifiedRestrictionsInClass(klass, clax, ontoDescr, factory);
            }

            for (OWLClassExpression clax : klass.getEquivalentClasses(ontoDescr)) {
                clax = clax.getNNF();
                dirty |= processQuantifiedRestrictionsInClass(klass, clax, ontoDescr, factory);
            }
        }
        return dirty;
    }

    private boolean processQuantifiedRestrictionsInClass(OWLClass klass, OWLClassExpression clax,
            OWLOntology ontology, OWLDataFactory fac) {
        final boolean[] dirty = { false };
        final OWLClass inKlass = klass;
        final OWLDataFactory factory = fac;
        final OWLOntology ontoDescr = ontology;

        clax.accept(new OWLClassExpressionVisitor() {

            private void process(OWLClassExpression expr) {

                if (expr instanceof OWLNaryBooleanClassExpression) {
                    for (OWLClassExpression clax : ((OWLNaryBooleanClassExpression) expr).getOperandsAsList()) {
                        process(clax);
                    }
                } else if (expr instanceof OWLQuantifiedObjectRestriction) {
                    OWLQuantifiedObjectRestriction rest = (OWLQuantifiedObjectRestriction) expr;
                    //
                    OWLObjectProperty prop = rest.getProperty().asOWLObjectProperty();
                    OWLClassExpression fil = rest.getFiller();

                    boolean inDomain = checkIsPropertyInDomain(prop, inKlass, expr, ontoDescr);
                    if (!inDomain) {
                        rewirePropertyDomain(prop, expr, ontoDescr);
                    }
                    reifyFiller(prop, fil);

                    process(fil);
                } else if (expr instanceof OWLObjectCardinalityRestriction) {
                    OWLObjectCardinalityRestriction rest = (OWLObjectCardinalityRestriction) expr;
                    //
                    OWLObjectProperty prop = rest.getProperty().asOWLObjectProperty();
                    OWLClassExpression fil = rest.getFiller();

                    boolean inDomain = checkIsPropertyInDomain(prop, inKlass, expr, ontoDescr);
                    if (!inDomain) {
                        rewirePropertyDomain(prop, expr, ontoDescr);
                    }
                    reifyFiller(prop, fil);

                    process(fil);
                } else if (expr instanceof OWLQuantifiedDataRestriction) {

                } else if (expr instanceof OWLCardinalityRestriction) {
                    if (expr instanceof OWLDataMinCardinality) {
                        minCards.put(
                                inKlass.getIRI().toQuotedString(), ((OWLDataMinCardinality) expr).getProperty()
                                        .asOWLDataProperty().getIRI().toQuotedString(),
                                ((OWLDataMinCardinality) expr).getCardinality());
                        minCounter++;
                    } else if (expr instanceof OWLDataMaxCardinality) {
                        maxCards.put(
                                inKlass.getIRI().toQuotedString(), ((OWLDataMaxCardinality) expr).getProperty()
                                        .asOWLDataProperty().getIRI().toQuotedString(),
                                ((OWLDataMaxCardinality) expr).getCardinality());
                        maxCounter++;
                    } else if (expr instanceof OWLObjectMaxCardinality) {
                        maxCards.put(
                                inKlass.getIRI().toQuotedString(), ((OWLObjectMaxCardinality) expr).getProperty()
                                        .asOWLObjectProperty().getIRI().toQuotedString(),
                                ((OWLObjectMaxCardinality) expr).getCardinality());
                        process(((OWLObjectMaxCardinality) expr).getFiller());
                        maxCounter++;
                    } else if (expr instanceof OWLObjectMinCardinality) {
                        minCards.put(
                                inKlass.getIRI().toQuotedString(), ((OWLObjectMinCardinality) expr).getProperty()
                                        .asOWLObjectProperty().getIRI().toQuotedString(),
                                ((OWLObjectMinCardinality) expr).getCardinality());
                        process(((OWLObjectMinCardinality) expr).getFiller());
                        minCounter++;
                    }
                } else
                    return;
            }

            private void rewirePropertyDomain(OWLObjectProperty prop, OWLClassExpression expr,
                    OWLOntology ontoDescr) {
                OWLOntology defining = lookupDefiningOntology(ontoDescr, prop);
                Set<OWLObjectPropertyDomainAxiom> domains = defining.getObjectPropertyDomainAxioms(prop);

                OWLClassExpression propDomain = null;
                for (OWLObjectPropertyDomainAxiom dox : domains) {
                    if (!dox.getDomain().isAnonymous()) {
                        propDomain = dox.getDomain();
                    }
                    ontoDescr.getOWLOntologyManager().applyChange(new RemoveAxiom(ontoDescr, dox));
                }
                OWLClass extDomain = factory.getOWLClass(IRI.create(prop.getIRI().getStart(),
                        NameUtils.capitalize(prop.getIRI().getFragment()) + "ExtraDomain" + counter++));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(extDomain)));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLSubClassOfAxiom(propDomain, extDomain)));
                ontoDescr.getOWLOntologyManager()
                        .applyChange(new AddAxiom(ontoDescr, factory.getOWLSubClassOfAxiom(extDomain,
                                ontoDescr.getOWLOntologyManager().getOWLDataFactory().getOWLThing())));
                ontoDescr.getOWLOntologyManager().applyChange(
                        new AddAxiom(ontoDescr, factory.getOWLObjectPropertyDomainAxiom(prop, extDomain)));

                Set<OWLClassExpression> aliases = new HashSet<OWLClassExpression>();
                for (OWLEquivalentClassesAxiom eq : ontoDescr.getAxioms(AxiomType.EQUIVALENT_CLASSES)) {
                    if (eq.contains(expr)) {
                        aliases.addAll(eq.getClassExpressions());
                    }
                }

                for (OWLSubClassOfAxiom sub : ontoDescr.getAxioms(AxiomType.SUBCLASS_OF)) {
                    if (aliases.contains(sub.getSuperClass()) && !sub.getSubClass().equals(extDomain)) {
                        ontoDescr.getOWLOntologyManager().applyChange(new RemoveAxiom(ontoDescr, sub));
                        ontoDescr.getOWLOntologyManager().applyChange(new AddAxiom(ontoDescr,
                                factory.getOWLSubClassOfAxiom(sub.getSubClass(), extDomain)));
                    }
                }
                dirty[0] = true;
            }

            private boolean checkIsPropertyInDomain(OWLObjectProperty prop, OWLClass inKlass,
                    OWLClassExpression expr, OWLOntology ontoDescr) {
                Set<OWLClassExpression> domains = new HashSet<OWLClassExpression>();
                OWLOntology defining = lookupDefiningOntology(ontoDescr, prop);
                for (OWLObjectPropertyDomainAxiom dom : defining.getObjectPropertyDomainAxioms(prop)) {
                    domains.add(dom.getDomain());
                }
                if (domains.size() == 0) {
                    // this property will become part of (Root)Thing
                    return true;
                }
                if (domains.contains(inKlass)) {
                    return true;
                }
                if (isSuperClass(ontoDescr, domains, inKlass)) {
                    return true;
                }

                defining = lookupDefiningOntology(ontoDescr, inKlass);
                for (OWLEquivalentClassesAxiom eq : defining.getEquivalentClassesAxioms(inKlass)) {
                    for (OWLClassExpression x : eq.getClassExpressions()) {
                        if (!x.isAnonymous()) {
                            if (isSuperClass(ontoDescr, domains, x)) {
                                return true;
                            }
                        }
                    }
                }

                return false;
            }

            private void reifyFiller(OWLObjectProperty prop, OWLClassExpression fil) {
                if (fil.isAnonymous()) {
                    OWLClass filler = fillerCache.get(fil);

                    if (filler == null) {
                        String fillerName = NameUtils
                                .separatingName(ontoDescr.getOntologyID().getOntologyIRI().toString())
                                + NameUtils.capitalize(inKlass.getIRI().getFragment())
                                + NameUtils.capitalize(prop.getIRI().getFragment()) + "Filler" + (counter++);
                        filler = factory.getOWLClass(IRI.create(fillerName));
                        // On a second thought, fillers could stay real...
                        //                            OWLAnnotationAssertionAxiom ann = factory.getOWLAnnotationAssertionAxiom( factory.getOWLAnnotationProperty( IRI.create( "http://www.w3.org/2000/01/rdf-schema#comment" ) ),
                        //                                    filler.getIRI(),
                        //                                    factory.getOWLStringLiteral("abstract") );
                        //                            ontoDescr.getOWLOntologyManager().applyChange( new AddAxiom( ontoDescr, ann ) );

                        fillerCache.put(fil, filler);
                    } else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("REUSED FILLER FOR" + fil);
                        }
                    }

                    dirty[0] = true;
                    ontoDescr.getOWLOntologyManager()
                            .applyChange(new AddAxiom(ontoDescr, factory.getOWLDeclarationAxiom(filler)));
                    ontoDescr.getOWLOntologyManager().applyChange(
                            new AddAxiom(ontoDescr, factory.getOWLEquivalentClassesAxiom(filler, fil)));

                }
            }

            public void visit(OWLClass ce) {
                process(ce);
            }

            public void visit(OWLObjectIntersectionOf ce) {
                process(ce);
            }

            public void visit(OWLObjectUnionOf ce) {
                process(ce);
            }

            public void visit(OWLObjectComplementOf ce) {
                process(ce);
            }

            public void visit(OWLObjectSomeValuesFrom ce) {
                process(ce);
            }

            public void visit(OWLObjectAllValuesFrom ce) {
                process(ce);
            }

            public void visit(OWLObjectHasValue ce) {
                process(ce);
            }

            public void visit(OWLObjectMinCardinality ce) {
                //                        minCards.put(inKlass, ce.getProperty().asOWLObjectProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        minCounter++;
                process(ce);
            }

            public void visit(OWLObjectExactCardinality ce) {
                //                        maxCards.put(inKlass, ce.getProperty().asOWLObjectProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        minCards.put(inKlass, ce.getProperty().asOWLObjectProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        minCounter++;
                //                        maxCounter++;
                process(ce);
            }

            public void visit(OWLObjectMaxCardinality ce) {
                //                        maxCards.put(inKlass, ce.getProperty().asOWLObjectProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        maxCounter++;
                process(ce);
            }

            public void visit(OWLObjectHasSelf ce) {
                throw new UnsupportedOperationException();
            }

            public void visit(OWLObjectOneOf ce) {
                //                throw new UnsupportedOperationException();
            }

            public void visit(OWLDataSomeValuesFrom ce) {
                process(ce);
            }

            public void visit(OWLDataAllValuesFrom ce) {
                process(ce);
            }

            public void visit(OWLDataHasValue ce) {
                process(ce);
            }

            public void visit(OWLDataMinCardinality ce) {
                //                        minCards.put(inKlass, ce.getProperty().asOWLDataProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        minCounter++;
                process(ce);
            }

            public void visit(OWLDataExactCardinality ce) {
                //                        minCards.put(inKlass, ce.getProperty().asOWLDataProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        maxCards.put(inKlass, ce.getProperty().asOWLDataProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        maxCounter++;
                //                        minCounter++;
                process(ce);
            }

            public void visit(OWLDataMaxCardinality ce) {
                //                        maxCards.put(inKlass, ce.getProperty().asOWLDataProperty().getIRI().toQuotedString(), ce.getCardinality());
                //                        maxCounter++;
                process(ce);
            }
        });

        return dirty[0];
    }

    private void fillPropNamesInDataStructs(OWLOntology ontoDescr) {
        for (OWLDataProperty dp : ontoDescr.getDataPropertiesInSignature(true)) {
            if (!dp.isTopEntity() && !dp.isBottomEntity()) {
                String propIri = dp.getIRI().toQuotedString();
                String propName = NameUtils.buildLowCaseNameFromIri(dp.getIRI().getFragment());
                if (propName == null) {
                    propName = NameUtils.buildLowCaseNameFromIri(dp.getIRI().getStart());
                }
                props.put(propIri, propName);
            }
        }

        for (OWLObjectProperty op : ontoDescr.getObjectPropertiesInSignature(true)) {
            if (!op.isTopEntity() && !op.isBottomEntity()) {
                String propIri = op.getIRI().toQuotedString();
                String propName = NameUtils.buildLowCaseNameFromIri(op.getIRI().getFragment());
                if (propName == null) {
                    propName = NameUtils.buildLowCaseNameFromIri(op.getIRI().getStart());
                }
                props.put(propIri, propName);
            }
        }

    }

    private String reportStats(OWLOntology ontoDescr) {
        StringBuilder sb = new StringBuilder();

        sb.append(" *** Stats for ontology  : " + ontoDescr.getOntologyID());

        sb.append(" Number of classes " + ontoDescr.getClassesInSignature(true).size());
        sb.append(" \t Number of classes " + ontoDescr.getClassesInSignature(true).size());

        sb.append(" Number of datatypes " + ontoDescr.getDatatypesInSignature().size());

        sb.append(" Number of dataProps " + ontoDescr.getDataPropertiesInSignature(true).size());
        sb.append("\t Number of dataProp domains " + ontoDescr.getAxiomCount(AxiomType.DATA_PROPERTY_DOMAIN));
        for (OWLDataProperty p : ontoDescr.getDataPropertiesInSignature(true)) {
            int num = ontoDescr.getDataPropertyDomainAxioms(p).size();
            if (num != 1) {
                sb.append("\t\t Domain" + p + " --> " + num);
            } else {
                OWLDataPropertyDomainAxiom dom = ontoDescr.getDataPropertyDomainAxioms(p).iterator().next();
                if (!(dom.getDomain() instanceof OWLClass)) {
                    sb.append("\t\t Complex Domain" + p + " --> " + dom.getDomain());
                }
            }
        }
        sb.append("\t Number of dataProp ranges " + ontoDescr.getAxiomCount(AxiomType.DATA_PROPERTY_RANGE));
        for (OWLDataProperty p : ontoDescr.getDataPropertiesInSignature(true)) {
            int num = ontoDescr.getDataPropertyRangeAxioms(p).size();
            if (num != 1) {
                sb.append("\t\t Range" + p + " --> " + num);
            } else {
                OWLDataPropertyRangeAxiom range = ontoDescr.getDataPropertyRangeAxioms(p).iterator().next();
                if (!(range.getRange() instanceof OWLDatatype)) {
                    sb.append("\t\t Complex Range" + p + " --> " + range.getRange());
                }
            }
        }

        sb.append(" Number of objProps " + ontoDescr.getObjectPropertiesInSignature(true).size());
        sb.append("\t Number of objProp domains " + ontoDescr.getAxiomCount(AxiomType.OBJECT_PROPERTY_DOMAIN));
        for (OWLObjectProperty p : ontoDescr.getObjectPropertiesInSignature(true)) {
            int num = ontoDescr.getObjectPropertyDomainAxioms(p).size();
            if (num != 1) {
                sb.append("\t\t Domain" + p + " --> " + num);
            } else {
                OWLObjectPropertyDomainAxiom dom = ontoDescr.getObjectPropertyDomainAxioms(p).iterator().next();
                if (!(dom.getDomain() instanceof OWLClass)) {
                    sb.append("\t\t Complex Domain" + p + " --> " + dom.getDomain());
                }
            }
        }
        sb.append("\t Number of objProp ranges " + ontoDescr.getAxiomCount(AxiomType.OBJECT_PROPERTY_RANGE));
        for (OWLObjectProperty p : ontoDescr.getObjectPropertiesInSignature(true)) {
            int num = ontoDescr.getObjectPropertyRangeAxioms(p).size();
            if (num != 1) {
                sb.append("\t\t Range" + p + " --> " + num);
            } else {
                OWLObjectPropertyRangeAxiom range = ontoDescr.getObjectPropertyRangeAxioms(p).iterator().next();
                if (!(range.getRange() instanceof OWLClass)) {
                    sb.append("\t\t Complex Domain" + p + " --> " + range.getRange());
                }
            }
        }

        return sb.toString();
    }

    private OWLProperty lookupDataProperty(String propId, Set<OWLDataProperty> set) {
        for (OWLDataProperty prop : set) {
            if (prop.getIRI().toQuotedString().equals(propId)) {
                return prop;
            }
        }
        return null;
    }

    private OWLProperty lookupObjectProperty(String propId, Set<OWLObjectProperty> set) {
        for (OWLObjectProperty prop : set) {
            if (prop.getIRI().toQuotedString().equals(propId)) {
                return prop;
            }
        }
        return null;
    }

    protected OntoModel buildClassLattice(OWLOntology ontoDescr, StatefulKnowledgeSession kSession,
            Map<InferenceTask, Resource> theory, OntoModel baseModel, DLFactoryConfiguration conf) {

        boolean dirty = true;
        OWLDataFactory factory = ontoDescr.getOWLOntologyManager().getOWLDataFactory();

        launchReasoner(dirty, kSession, ontoDescr, conf.getAxiomGens());

        // reify complex superclasses, domains and ranges
        dirty |= processComplexSuperClassesDomainAndRanges(ontoDescr, factory);

        /************************************************************************************************************************************/

        // check individuals for multiple inheritance
        dirty |= preProcessIndividuals(ontoDescr, ontoDescr.getOWLOntologyManager().getOWLDataFactory());

        /************************************************************************************************************************************/

        // new classes have been added, classify the
        launchReasoner(dirty, kSession, ontoDescr, conf.getAxiomGens());

        /************************************************************************************************************************************/

        // reify complex restriction fillers
        dirty = processQuantifiedRestrictions(ontoDescr, factory);

        /************************************************************************************************************************************/

        // new classes have been added, classify the
        if (!conf.isDisableFullReasoner()) {
            launchReasoner(dirty, kSession, ontoDescr, conf.getAxiomGens());
        }

        /************************************************************************************************************************************/

        // resolve aliases, choosing delegators
        aliases = buildAliasesForEquivalentClasses(ontoDescr);

        /************************************************************************************************************************************/

        if (logger.isInfoEnabled()) {
            logger.info(reportStats(ontoDescr));
        }

        // classes are stable now
        addConceptsToModel(kSession, ontoDescr, baseModel);

        // lattice is too. applies aliasing
        addSubConceptsToModel(ontoDescr, baseModel);

        kSession.fireAllRules();

        return baseModel;
    }

    private void fixRootHierarchy(OntoModel model) {
        Concept thing = model.getConcept(
                IRI.create(NamespaceUtils.getNamespaceByPrefix("owl").getURI() + "#Thing").toQuotedString());
        if (thing.getProperties().size() > 0) {
            Concept localRoot = new Concept(
                    IRI.create(NameUtils.separatingName(model.getDefaultNamespace()) + "RootThing"), "RootThing",
                    false);
            model.addConcept(localRoot);

            localRoot.addSuperConcept(thing);
            thing.getSubConcepts().add(localRoot);

            for (String propIri : thing.getProperties().keySet()) {
                PropertyRelation rel = thing.getProperty(propIri);
                rel.setDomain(localRoot);
                localRoot.addProperty(propIri, rel.getName(), rel);
            }
            thing.getProperties().clear();

            for (Concept con : model.getConcepts()) {
                if (con == localRoot) {
                    continue;
                }
                if (con.getSuperConcepts().contains(thing)) {
                    con.getSuperConcepts().remove(thing);
                    con.getSuperConcepts().add(localRoot);
                }
                if (thing.getSubConcepts().contains(con)) {
                    thing.getSubConcepts().remove(con);
                    localRoot.getSubConcepts().add(con);
                }
            }

            for (PropertyRelation prop : model.getProperties()) {
                fixProperty(prop, thing, localRoot);
            }
        }
    }

    private void fixProperty(PropertyRelation prop, Concept thing, Concept localRoot) {
        if (prop.getDomain() == thing) {
            prop.setDomain(localRoot);
        }
        if (prop.getTarget() == thing) {
            prop.setTarget(localRoot);
        }
        for (PropertyRelation sub : prop.getRestrictedProperties()) {
            fixProperty(sub, thing, localRoot);
        }
    }

    private void processSubConceptAxiom(OWLClassExpression subClass, OWLClassExpression superClass,
            Map<String, Collection<String>> supers, String thing) {
        if (!superClass.isAnonymous() || superClass instanceof OWLObjectUnionOf) {

            String sub = filterAliases(subClass).asOWLClass().getIRI().toQuotedString();
            String sup = isDelegating(superClass) ? thing
                    : filterAliases(superClass).asOWLClass().getIRI().toQuotedString();

            addSuper(sub, sup, supers);
        } else if (superClass instanceof OWLObjectIntersectionOf) {
            OWLObjectIntersectionOf and = (OWLObjectIntersectionOf) superClass;
            for (OWLClassExpression ex : and.asConjunctSet()) {
                processSubConceptAxiom(subClass, ex, supers, thing);
            }
        }
    }

    private void addSuper(String sub, String sup, Map<String, Collection<String>> supers) {
        if (sub.equals(sup)) {
            return;
        }
        Collection<String> ancestors = supers.get(sub);
        if (ancestors == null) {
            ancestors = new HashSet<String>();
            supers.put(sub, ancestors);
        }
        ancestors.add(sup);
    }

    private void addSubConceptsToModel(OWLOntology ontoDescr, OntoModel model) {

        Map<String, Collection<String>> supers = new HashMap<String, Collection<String>>();

        String thing = ontoDescr.getOWLOntologyManager().getOWLDataFactory().getOWLThing().getIRI()
                .toQuotedString();
        supers.put(thing, Collections.EMPTY_SET);

        for (OWLSubClassOfAxiom ax : ontoDescr.getAxioms(AxiomType.SUBCLASS_OF)) {
            processSubConceptAxiom(ax.getSubClass(), ax.getSuperClass(), supers, thing);
        }
        for (OWLEquivalentClassesAxiom ax : ontoDescr.getAxioms(AxiomType.EQUIVALENT_CLASSES)) {
            processSubConceptAxiom(ax.getClassExpressionsAsList().get(0),
                    filterAliases(ax.getClassExpressionsAsList().get(1)), supers, thing);
        }

        for (OWLClassExpression delegator : aliases.keySet()) {
            if (!delegator.isAnonymous()) {
                addSuper(delegator.asOWLClass().getIRI().toQuotedString(), thing, supers);
            }
        }

        for (OWLClassExpression delegator : aliases.keySet()) {
            if (!delegator.isAnonymous()) {
                OWLClassExpression delegate = aliases.get(delegator);
                String sub = delegate.asOWLClass().getIRI().toQuotedString();
                String sup = delegator.asOWLClass().getIRI().toQuotedString();
                conceptCache.get(sub).getEquivalentConcepts().add(conceptCache.get(sup));
                addSuper(sub, sup, supers);
            }
        }

        HierarchySorter<String> sorter = new HierarchySorter<String>();
        List<String> sortedCons = sorter.sort(supers);

        ArrayList missing = new ArrayList(conceptCache.keySet());
        missing.removeAll(supers.keySet());

        LinkedHashMap<String, Concept> sortedCache = new LinkedHashMap<String, Concept>();
        for (String con : sortedCons) {
            sortedCache.put(con, conceptCache.get(con));
        }
        conceptCache.clear();
        conceptCache = sortedCache;

        reduceTransitiveInheritance(sortedCache, supers);

        for (String con : supers.keySet()) {
            Collection<String> parents = supers.get(con);
            for (String sup : parents) {
                SubConceptOf subConceptOf = new SubConceptOf(con, sup);
                model.addSubConceptOf(subConceptOf);
                conceptCache.get(subConceptOf.getSubject())
                        .addSuperConcept(conceptCache.get(subConceptOf.getObject()));
            }
        }
    }

    private void reduceTransitiveInheritance(LinkedHashMap<String, Concept> sortedCache,
            Map<String, Collection<String>> supers) {
        Map<String, Collection<String>> taboos = new HashMap<String, Collection<String>>();
        for (String con : sortedCache.keySet()) {
            Collection<String> ancestors = supers.get(con);
            Set<String> taboo = new HashSet<String>();
            for (String anc : ancestors) {
                if (taboos.containsKey(anc)) {
                    taboo.addAll(taboos.get(anc));
                }
            }
            ancestors.removeAll(taboo);
            taboo.addAll(ancestors);
            taboos.put(con, taboo);
        }
    }

    private boolean isDelegating(OWLClassExpression superClass) {
        return aliases.containsKey(superClass);
    }

    private boolean isDelegating(String classIri) {
        for (OWLClassExpression klass : aliases.keySet()) {
            if (!klass.isAnonymous() && klass.asOWLClass().getIRI().toQuotedString().equals(classIri)) {
                return true;
            }
        }
        return false;
    }

    private OWLClassExpression filterAliases(OWLClassExpression klass) {
        if (aliases.containsKey(klass)) {
            return aliases.get(klass);
        } else
            return klass;
    }

    private void addConceptsToModel(StatefulKnowledgeSession kSession, OWLOntology ontoDescr, OntoModel baseModel) {
        Set<OWLClass> kis = ontoDescr.getClassesInSignature(true);
        Set dek = ontoDescr.getAxioms(AxiomType.DECLARATION);

        for (OWLClass con : ontoDescr.getClassesInSignature(true)) {
            if (baseModel.getConcept(con.getIRI().toQuotedString()) == null) {
                Concept concept = new Concept(con.getIRI(),
                        NameUtils.buildNameFromIri(con.getIRI().getStart(), con.getIRI().getFragment()),
                        con.isOWLDatatype());

                for (OWLAnnotation ann : con.getAnnotations(ontoDescr)) {
                    if (ann.getProperty().isComment() && ann.getValue() instanceof OWLLiteral) {
                        OWLLiteral lit = (OWLLiteral) ann.getValue();
                        if (lit.getLiteral().trim().equals("abstract")) {
                            concept.setAbstrakt(true);
                        }
                    }
                }

                if (concept.getName().endsWith("Range") || concept.getName().endsWith("Domain")
                        || concept.getName().matches("\\S*Filler\\d+")) {
                    concept.setAnonymous(true);
                }

                baseModel.addConcept(concept);
                kSession.insert(concept);
                conceptCache.put(con.getIRI().toQuotedString(), concept);
            }
        }
    }

    private void addDataRange(Map<OWLProperty, Set<OWLDataRange>> dataRanges, OWLDataProperty dp,
            OWLDataRange owlData, OWLDataFactory factory) {
        Set<OWLDataRange> set = dataRanges.get(dp);
        if (set == null) {
            set = new HashSet<OWLDataRange>();
            dataRanges.put(dp, set);
        }
        set.add(owlData);
        if (set.size() >= 2 && set.contains(factory.getTopDatatype())) {
            set.remove(factory.getTopDatatype());
        }
    }

    private void addRange(Map<OWLProperty, Set<OWLClassExpression>> ranges, OWLProperty rp,
            OWLClassExpression owlKlass, OWLDataFactory factory) {
        Set<OWLClassExpression> set = ranges.get(rp);
        if (set == null) {
            set = new HashSet<OWLClassExpression>();
            ranges.put(rp, set);
        }
        set.add(owlKlass);
        if (set.size() >= 2 && set.contains(factory.getOWLThing())) {
            set.remove(factory.getOWLThing());
        }

    }

    private void addDomain(Map<OWLProperty, Set<OWLClassExpression>> domains, OWLProperty dp,
            OWLClassExpression owlKlass, OWLDataFactory factory) {
        Set<OWLClassExpression> set = domains.get(dp);
        if (set == null) {
            set = new HashSet<OWLClassExpression>();
            domains.put(dp, set);
        }

        set.add(owlKlass);
        if (set.size() >= 2 && set.contains(factory.getOWLThing())) {
            set.remove(factory.getOWLThing());
        }
    }

    private void setDomain(Map<OWLProperty, Set<OWLClassExpression>> domains, OWLProperty dp,
            OWLClassExpression owlKlass, OWLDataFactory factory) {
        Set<OWLClassExpression> set = domains.get(dp);
        if (set == null) {
            set = new HashSet<OWLClassExpression>();
            domains.put(dp, set);
        } else {
            set.clear();
            set.add(owlKlass);
        }
    }

    private void setRange(Map<OWLProperty, Set<OWLClassExpression>> ranges, OWLProperty rp,
            OWLClassExpression owlKlass, OWLDataFactory factory) {
        Set<OWLClassExpression> set = ranges.get(rp);
        if (set == null) {
            set = new HashSet<OWLClassExpression>();
            ranges.put(rp, set);
        } else {
            set.clear();
            set.add(owlKlass);
        }

    }

    private boolean validate(OntoModel model) {

        for (PropertyRelation rel : model.getProperties()) {
            if (!rel.isRestricted()) {
                if (rel != rel.getBaseProperty()) {
                    throw new IllegalStateException("Property is not restricted, but not a base property either "
                            + rel + " >> base " + rel.getBaseProperty());
                }
            }
            for (PropertyRelation rest : rel.getRestrictedProperties()) {
                checkForRestriction(rest, rel, rel.getBaseProperty());
            }
        }
        return true;
    }

    private void checkForRestriction(PropertyRelation restricted, PropertyRelation parent, PropertyRelation base) {
        if (restricted.getBaseProperty() != base) {
            throw new IllegalStateException("Inconsistent base property for" + restricted + " >> base "
                    + restricted.getBaseProperty() + " , expected " + base);
        }
        if (restricted.getImmediateBaseProperty() != parent) {
            throw new IllegalStateException("Inconsistent parent property for" + restricted + " >> parent  "
                    + restricted.getImmediateBaseProperty() + " , expected " + parent);
        }
        int diff = diff(restricted, parent);
        if (0 == diff) {
            throw new IllegalStateException("Inconsistent restriction for " + restricted + " >> parent  " + parent);
        }
        for (PropertyRelation subRestr : restricted.getRestrictedProperties()) {
            checkForRestriction(subRestr, restricted, base);
        }
    }

    private enum DIFF_BY {
        DOMAIN((byte) 1), RANGE((byte) 2), MIN((byte) 4), MAX((byte) 8);

        DIFF_BY(byte x) {
            bit = x;
        }

        private byte bit;

        public byte getBit() {
            return bit;
        }
    }

    private int diff(PropertyRelation restricted, PropertyRelation parent) {
        int diff = 0;
        if (!restricted.getDomain().equals(parent.getDomain())) {
            diff |= DIFF_BY.DOMAIN.getBit();
        }
        if (!restricted.getTarget().equals(parent.getTarget())) {
            diff |= DIFF_BY.RANGE.getBit();
        }
        if (restricted.getMinCard() == null && parent.getMinCard() != null
                || !restricted.getMinCard().equals(parent.getMinCard())) {
            diff |= DIFF_BY.MIN.getBit();
        }
        if (restricted.getMaxCard() == null && parent.getMaxCard() != null
                || restricted.getMaxCard() != null && parent.getMaxCard() == null
                || (restricted.getMaxCard() != null && !restricted.getMaxCard().equals(parent.getMaxCard()))) {
            diff |= DIFF_BY.MAX.getBit();
        }
        return diff;
    }

    private void launchReasoner(boolean dirty, StatefulKnowledgeSession kSession, OWLOntology ontoDescr,
            List<InferredAxiomGenerator<? extends OWLAxiom>> axiomGenerators) {
        if (dirty) {
            long now = new Date().getTime();
            if (logger.isInfoEnabled()) {
                logger.info(" START REASONER ");
            }

            InferredOntologyGenerator reasoner = initReasoner(kSession, ontoDescr, axiomGenerators);

            reasoner.fillOntology(ontoDescr.getOWLOntologyManager(), ontoDescr);

            if (logger.isInfoEnabled()) {
                logger.info(" STOP REASONER : time elapsed >> " + (new Date().getTime() - now));
            }

        } else {
            if (logger.isInfoEnabled()) {
                logger.info(" REASONER NOT NEEDED");
            }
        }

    }

    protected InferredOntologyGenerator initReasoner(StatefulKnowledgeSession kSession, OWLOntology ontoDescr,
            List<InferredAxiomGenerator<? extends OWLAxiom>> axiomGenerators) {

        ConsoleProgressMonitor progressMonitor = new ConsoleProgressMonitor();
        OWLReasonerConfiguration config = new SimpleConfiguration(progressMonitor);

        OWLReasonerFactory reasonerFactory = new Reasoner.ReasonerFactory();
        //                if ( owler == null ) {
        OWLReasoner owler = reasonerFactory.createReasoner(ontoDescr, config);
        owler.precomputeInferences(InferenceType.CLASS_HIERARCHY, InferenceType.CLASS_ASSERTIONS,

                InferenceType.OBJECT_PROPERTY_ASSERTIONS, InferenceType.DATA_PROPERTY_ASSERTIONS,

                InferenceType.DIFFERENT_INDIVIDUALS, InferenceType.SAME_INDIVIDUAL,

                InferenceType.DISJOINT_CLASSES,

                //                                        InferenceType.DATA_PROPERTY_HIERARCHY,
                InferenceType.OBJECT_PROPERTY_HIERARCHY);

        if (!owler.isConsistent()) {
            throw new RuntimeException("Inconsistent ontology ");
        }

        return new InferredOntologyGenerator(owler, axiomGenerators);

    }

}