public class Ontology {
    
    /**
     * The id of the ontology.
     */
    protected final String id;
    
    /**
     * The version of the ontology.
     */
    protected final String version;
    
    /**
     * The collection of stated axioms that form the ontology.
     */
    protected final Collection<Axiom> statedAxioms;
    
    /**
     * The collection of inferred axioms that form the ontology.
     */
    protected final Collection<Axiom> inferredAxioms = new ArrayList<Axiom>();
    
    /**
     * A map that contains references to all the nodes in the taxonomy indexed
     * by id.
     */
    protected final Map<String, Node> nodeMap = new HashMap<String, Node>();
    
    /**
     * Set of {@link Node}s potentially affected by the last incremental
     * classification.
     */
    protected final Set<Node> lastAffectedNodes = new HashSet<Node>();
    
    /**
     * Builds a new ontology.
     * 
     * @param id
     * @param version
     * @param statedAxioms
     * @param nodeMap
     * @param lastAffectedNodes
     */
    public Ontology(String id, String version, Collection<Axiom> statedAxioms, Map<String, Node> nodeMap, 
            Set<Node> lastAffectedNodes) {
        this.id = id;
        this.version = version;
        if(statedAxioms == null) {
            this.statedAxioms = new ArrayList<Axiom>();
        } else {
            this.statedAxioms = statedAxioms;
        }
        if(nodeMap != null)
            this.nodeMap.putAll(nodeMap);
        if(lastAffectedNodes != null)
            this.lastAffectedNodes.addAll(lastAffectedNodes);
    }
    
    /**
     * Builds a new ontology.
     * 
     * @param statedAxioms
     * @param nodeMap
     */
    public Ontology(String id, String version, Collection<Axiom> statedAxioms, Map<String, Node> nodeMap) {
    	this(id, version, statedAxioms, nodeMap, null);
    }
    
    public Collection<Axiom> getStatedAxioms() {
        return statedAxioms;
    }

    public Collection<Axiom> getInferredAxioms() {
        return inferredAxioms;
    }
    
    public Node getNode(String id) {
        return nodeMap.get(id);
    }

    public Iterator<Node> nodeIterator() {
        Set<Node> set = new HashSet<Node>(nodeMap.values());
        return set.iterator();
    }
    
    public Map<String, Node> getNodeMap() {
        return nodeMap;
    }

    public Node getTopNode() {
        return getNode(NamedConcept.TOP);
    }
    
    public Node getBottomNode() {
        return getNode(NamedConcept.BOTTOM);
    }
    
    public void setNodeMap(Map<String, Node> nodeMap) {
        this.nodeMap.clear();
        this.nodeMap.putAll(nodeMap);
    }

    public Set<Node> getAffectedNodes() {
        return lastAffectedNodes;
    }
    
    public void setAffectedNodes(Set<Node> nodes) {
        lastAffectedNodes.clear();
        lastAffectedNodes.addAll(nodes);
    }
    
    public String getId() {
        return id;
    }

    public String getVersion() {
        return version;
    }
    
} public abstract class BaseImporter implements IImporter {
    
    protected class Module {
        private final String moduleId;
        private final String moduleVersion;
        
        public Module(String moduleId, String moduleVersion) {
            super();
            this.moduleId = moduleId;
            this.moduleVersion = moduleVersion;
        }
        
        public String getModuleId() {
            return moduleId;
        }
        
        public String getModuleVersion() {
            return moduleVersion;
        }
        
    }
    
    protected class ImportEntry {
        private final String rootModuleId;
        private final String rootModuleVersion;
        private final Map<String, String> metadata;
        private final Set<Module> modules;
        private final Input input;
        
        public ImportEntry(String rootModuleId, String rootModuleVersion,
                Map<String, String> metadata, Set<Module> modules, Input input) {
            this.rootModuleId = rootModuleId;
            this.rootModuleVersion = rootModuleVersion;
            this.metadata = metadata;
            this.modules = modules;
            this.input = input;
        }
        
        public String getRootModuleId() {
            return rootModuleId;
        }
        
        public String getRootModuleVersion() {
            return rootModuleVersion;
        }
        
        public Map<String, String> getMetadata() {
            return metadata;
        }
        
        public Set<Module> getModules() {
            return modules;
        }

        public Input getInput() {
            return input;
        }
        
    }
    
} public class ImportException extends Exception {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /**
     * @param arg0
     */
    public ImportException(String arg0) {
        super(arg0);
    }

    /**
     * @param arg0
     * @param arg1
     */
    public ImportException(String arg0, Throwable arg1) {
        super(arg0, arg1);
    }

} public abstract class Axiom implements Comparable<Axiom> {

}
 @XmlRootElement
public class BigIntegerLiteral extends Literal {

    private static final long serialVersionUID = 1L;
    
    private BigInteger value;
    
    /**
     * 
     */
    public BigIntegerLiteral() {
        
    }
    
    /**
     * 
     * @param type
     * @param value
     */
    public BigIntegerLiteral(BigInteger value) {
        this.value = value;
    }
    
    /**
     * 
     * @param value
     */
    public BigIntegerLiteral(long value) {
        this.value = BigInteger.valueOf(value);
    }

    /**
     * @return the value
     */
    public BigInteger getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(BigInteger value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        BigIntegerLiteral other = (BigIntegerLiteral) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }

    public int compareTo(Literal o) {
        return value.compareTo(((BigIntegerLiteral) o).value);
    }

}
 public abstract class Concept implements Comparable<Concept>, Serializable {
    
    private static final long serialVersionUID = 1L;

    public abstract String toString();

    public abstract int hashCode();

    public abstract boolean equals(Object o);
    
} @XmlRootElement
public class ConceptInclusion extends Axiom {
    
    /**
     * The left hand side of the expression.
     */
    private Concept lhs;
    
    /**
     * The right hand side of the expression.
     */
    private Concept rhs;
    
    /**
     * 
     */
    public ConceptInclusion() {
        
    }
    
    /**
     * Creates a new ConceptInclusion.
     * 
     * @param lhs
     * @param rhs
     */
    public ConceptInclusion(final Concept lhs, final Concept rhs) {
        if (null == lhs) {
            throw new IllegalArgumentException("LHS cannot be null (RHS = " + rhs + ")");
        }
        this.lhs = lhs;
        if (null == rhs) {
            throw new IllegalArgumentException("RHS cannot be null (LHS = " + lhs + ")");
        }
        this.rhs = rhs;
    }
    
    

    @Override
    public String toString() {
        return lhs + " \u2291 " + rhs;
    }

    /**
     * @return the lhs
     */
    public Concept getLhs() {
        return lhs;
    }

    /**
     * @param lhs the lhs to set
     */
    public void setLhs(Concept lhs) {
        this.lhs = lhs;
    }

    /**
     * @return the rhs
     */
    public Concept getRhs() {
        return rhs;
    }

    /**
     * @param rhs the rhs to set
     */
    public void setRhs(Concept rhs) {
        this.rhs = rhs;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((lhs == null) ? 0 : lhs.hashCode());
        result = prime * result + ((rhs == null) ? 0 : rhs.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ConceptInclusion other = (ConceptInclusion) obj;
        if (lhs == null) {
            if (other.lhs != null)
                return false;
        } else if (!lhs.equals(other.lhs))
            return false;
        if (rhs == null) {
            if (other.rhs != null)
                return false;
        } else if (!rhs.equals(other.rhs))
            return false;
        return true;
    }

    public int compareTo(Axiom o) {
        if(!(o instanceof ConceptInclusion)) {
            return -1;
        } else {
            ConceptInclusion otherCi = (ConceptInclusion) o;
            int lhsRes = lhs.compareTo(otherCi.getLhs());
            int rhsRes = rhs.compareTo(otherCi.getRhs());
            if(lhsRes == 0 && rhsRes == 0)
                return 0;
            else if(lhsRes != 0)
                return lhsRes;
            else
                return rhsRes;
        }
    }
    
} @XmlRootElement
public class Conjunction extends Concept {

    private static final long serialVersionUID = 1L;

    private Concept[] concepts;

    private int hashCode;

    /**
     *
     */
    @SuppressWarnings("unchecked")
    public Conjunction() {
        this(Collections.EMPTY_SET);
    }

    /**
     *
     * @param concepts
     */
    public Conjunction(final Concept[] concepts) {
        setConcepts(concepts);
    }

    public Conjunction(final Collection<? extends Concept> concepts) {
        // Store the concepts in hashCode order so that equals() is order
        // independent, i.e. conjunctions are reflexive (should also be
        // transitive, but Agile says STTCPW)

        final SortedSet<Concept> sorted = new TreeSet<>(concepts);
        this.concepts = sorted.toArray(new Concept[sorted.size()]);
        hashCode = sorted.hashCode();
    }

    public Concept[] getConcepts() {
        return concepts;
    }

    /**
     * @param concepts the concepts to set
     */
    public void setConcepts(Concept[] concepts) {
        final SortedSet<Concept> sorted = new TreeSet<>();
        for (Concept concept : concepts) {
            sorted.add(concept);
        }
        this.concepts = sorted.toArray(new Concept[sorted.size()]);
        hashCode = sorted.hashCode();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        if (concepts.length > 0) {
            sb.append(concepts[0]);
            for (int i = 1; i < concepts.length; i++) {
                sb.append(" + ");
                sb.append(concepts[i]);
            }
        }
        sb.append(")");
        return sb.toString();
    }

    @Override
    public int hashCode() {
        return hashCode;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final Conjunction other = (Conjunction) obj;
        return hashCode == other.hashCode
                && Arrays.equals(concepts, other.concepts);
    }

    @Override
    public int compareTo(Concept o) {
        Class<? extends Conjunction> thisClass = this.getClass();
        Class<? extends Concept> otherClass = o.getClass();
        if(thisClass.equals(otherClass)) {
            Conjunction other = (Conjunction)o;
            // Equal if all concepts equal
            // Otherwise order depends on the length and then on the order of
            // first different concept

            int res = 0;
            res = concepts.length - other.concepts.length;
            if(res != 0) return res;

            for(int i = 0; i < concepts.length; i++) {
                try {
                    res = concepts[i].compareTo(other.concepts[i]);
                } catch(ClassCastException e) {
                    // Need to catch this because elements in the conjunction
                    // might be of different types
                    res = concepts[i].getClass().toString().compareTo(
                            other.concepts[i].getClass().toString());
                }

                if(res != 0) return res;
            }

            return 0;
        } else {
            return thisClass.toString().compareTo(otherClass.toString());
        }
    }

} @XmlRootElement
public class Datatype extends Concept {

    private static final long serialVersionUID = 1L;
    
    private Feature feature;
    
    private Operator operator;
    
    private Literal literal;
    
    /**
     * 
     */
    public Datatype() {
        
    }
    
    /**
     * 
     * @param feature
     * @param operator
     * @param literal
     */
    public Datatype(Feature feature, Operator operator, Literal literal) {
        this.feature = feature;
        this.operator = operator;
        this.literal = literal;
    }

    public Feature getFeature() {
        return feature;
    }

    public Operator getOperator() {
        return operator;
    }

    public Literal getLiteral() {
        return literal;
    }

    /**
     * @param feature the feature to set
     */
    public void setFeature(Feature feature) {
        this.feature = feature;
    }

    /**
     * @param operator the operator to set
     */
    public void setOperator(Operator operator) {
        this.operator = operator;
    }

    /**
     * @param literal the literal to set
     */
    public void setLiteral(Literal literal) {
        this.literal = literal;
    }

    @Override
    public String toString() {
        return feature + ".(" + operator + "," + literal + ")";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((feature == null) ? 0 : feature.hashCode());
        result = prime * result + ((literal == null) ? 0 : literal.hashCode());
        result = prime * result + ((operator == null) ? 0 : operator.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Datatype other = (Datatype) obj;
        if (feature == null) {
            if (other.feature != null)
                return false;
        } else if (!feature.equals(other.feature))
            return false;
        if (literal == null) {
            if (other.literal != null)
                return false;
        } else if (!literal.equals(other.literal))
            return false;
        if (operator != other.operator)
            return false;
        return true;
    }

    @SuppressWarnings({ "rawtypes" })
    public int compareTo(Concept o) {
        Class thisClass = this.getClass();
        Class otherClass = o.getClass();
        if(thisClass.equals(otherClass)) {
            Datatype other = (Datatype)o;
            int res = 0;
            res = feature.compareTo(other.feature);
            if(res != 0) return res;
            res = operator.compareTo(other.operator);
            if(res != 0) return res;
            res = literal.compareTo(other.literal);
            return res;
        } else {
            return thisClass.toString().compareTo(otherClass.toString());
        }
    }

} @XmlRootElement
public class DateLiteral extends Literal {

    private static final long serialVersionUID = 1L;
    
    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    
    private Calendar value;
    
    /**
     * 
     */
    public DateLiteral() {
        
    }
    
    /**
     * 
     * @param value
     */
    public DateLiteral(Calendar value) {
        this.value = value;
    }

    /**
     * @return the value
     */
    public Calendar getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(Calendar value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DateLiteral other = (DateLiteral) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return sdf.format(value.getTime());
    }

    public int compareTo(Literal o) {
        DateLiteral dl = (DateLiteral) o;
        Calendar otherValue = dl.value;
        return value.compareTo(otherValue);
    }

} @XmlRootElement
public class DecimalLiteral extends Literal {

    private static final long serialVersionUID = 1L;
    
    private BigDecimal value;
    
    /**
     * 
     */
    public DecimalLiteral() {
        
    }
    
    /**
     * 
     * @param type
     * @param value
     */
    public DecimalLiteral(BigDecimal value) {
        this.value = value;
    }
    
    /**
     * 
     * @param value
     */
    public DecimalLiteral(double value) {
        this.value = BigDecimal.valueOf(value);
    }

    /**
     * @return the value
     */
    public BigDecimal getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(BigDecimal value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DecimalLiteral other = (DecimalLiteral) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }

    public int compareTo(Literal o) {
        return value.compareTo(((DecimalLiteral) o).value);
    }

}
 @XmlRootElement
public class Existential extends Concept {

    private static final long serialVersionUID = 1L;
    
    private Role role;
    
    private Concept concept;
    
    /**
     * 
     */
    public Existential() {
        
    }
    
    /**
     * 
     * @param role
     * @param concept
     */
    public Existential(Role role, Concept concept) {
        this.role = role;
        this.concept = concept;
    }

    @Override
    public String toString() {
        return role + "." + concept;
    }
    
    public Role getRole() {
        return role;
    }
    
    public Concept getConcept() {
        return concept;
    }

    /**
     * @param role the role to set
     */
    public void setRole(Role role) {
        this.role = role;
    }

    /**
     * @param concept the concept to set
     */
    public void setConcept(Concept concept) {
        this.concept = concept;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((concept == null) ? 0 : concept.hashCode());
        result = prime * result + ((role == null) ? 0 : role.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Existential other = (Existential) obj;
        if (concept == null) {
            if (other.concept != null)
                return false;
        } else if (!concept.equals(other.concept))
            return false;
        if (role == null) {
            if (other.role != null)
                return false;
        } else if (!role.equals(other.role))
            return false;
        return true;
    }

    @SuppressWarnings({ "rawtypes" })
    public int compareTo(Concept o) {
        Class thisClass = this.getClass();
        Class otherClass = o.getClass();
        if(thisClass.equals(otherClass)) {
            Existential other = (Existential)o;
            int res = 0;
            res = role.compareTo(other.role);
            if(res != 0) return res;
            try {
                res = concept.compareTo(other.concept);
            } catch(ClassCastException e) {
                // Need to catch this because elements in the conjunction might
                // be of different types
                res = concept.getClass().toString().compareTo(
                        other.concept.getClass().toString());
            }
            if(res != 0) return res;
            return 0;
        } else {
            return thisClass.toString().compareTo(otherClass.toString());
        }
    }

} @XmlRootElement
public class FloatLiteral extends Literal {

    private static final long serialVersionUID = 1L;
    
    private float value;
    
    /**
     * 
     */
    public FloatLiteral() {
        
    }
    
    /**
     * 
     * @param type
     */
    public FloatLiteral(float value) {
        this.value = value;
    }

    /**
     * @return the value
     */
    public float getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(float value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Float.floatToIntBits(value);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        FloatLiteral other = (FloatLiteral) obj;
        if (Float.floatToIntBits(value) != Float.floatToIntBits(other.value))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
    
    @Override
    public int compareTo(Literal o) {
        FloatLiteral fl = (FloatLiteral) o;
        float otherValue = fl.value;
        return Float.compare(value, otherValue);
    }

} public class FunctionalFeature extends Axiom {

    private Feature feature;

    public FunctionalFeature() {
    }

    public FunctionalFeature(Feature feature) {
        this.feature = feature;
    }

    public void setFeature(Feature feature) {
        this.feature = feature;
    }

    public Feature getFeature() {
        return feature;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((feature == null) ? 0 : feature.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        FunctionalFeature other = (FunctionalFeature) obj;
        if (feature == null) {
            if (other.feature != null)
                return false;
        } else if (!feature.equals(other.feature))
            return false;
        return true;
    }

    @Override
    public int compareTo(Axiom o) {
        if (!(o instanceof FunctionalFeature)) {
            return 1;
        } else {
            return 0;
        }
    }

} @XmlRootElement
public class IntegerLiteral extends Literal {

    private static final long serialVersionUID = 1L;
    
    private int value;
    
    /**
     * 
     */
    public IntegerLiteral() {
        
    }
    
    /**
     * Constructor.
     * 
     * @param type
     */
    public IntegerLiteral(int value) {
        this.value = value;
    }

    /**
     * @return the value
     */
    public int getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(int value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + value;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IntegerLiteral other = (IntegerLiteral) obj;
        if (value != other.value)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }

    public int compareTo(Literal o) {
        return ((Integer) value).compareTo(((IntegerLiteral) o).value);
    }

} public abstract class Literal implements Comparable<Literal>, Serializable {
    
    private static final long serialVersionUID = 1L;
    
    public abstract String toString();

    public abstract int hashCode();

    public abstract boolean equals(Object o);

} @XmlRootElement
public class NamedConcept extends Concept {

    private static final long serialVersionUID = 1L;

    /**
     * Represents the top concept.
     */
    public static String TOP = "_TOP_";
    
    /**
     * Represents the bottom concept.
     */
    public static String BOTTOM = "_BOTTOM_";
    
    /**
     * The top concept.
     */
    public static final Concept TOP_CONCEPT = new NamedConcept(TOP);
    
    /**
     * The bottom concept.
     */
    public static final Concept BOTTOM_CONCEPT = new NamedConcept(BOTTOM);
    
    /**
     * String identifier of this concept.
     */
    protected String id;
    
    /**
     * No args constructor.
     */
    public NamedConcept() {
        
    }
    
    /**
     * Creates a new Concept.
     * 
     * @param id
     *            The concept's identifier.
     */
    public NamedConcept(String id) {
        assert(id != null);
        this.id = id;
    }
    
    /**
     * Returns this concept's identifier.
     * 
     * @return The identifier.
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Concept [id=");
        builder.append(id);
        builder.append("]");
        return builder.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        NamedConcept other = (NamedConcept) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public int compareTo(Concept other) {
        if(!(other instanceof NamedConcept)) {
            return -1;
        }
        return id.compareTo(((NamedConcept) other).id);
    }
    
} @XmlRootElement
public class NamedFeature extends Feature {

    private static final long serialVersionUID = 1L;
    
    /**
     * String identifier of this concept.
     */
    private String id;
    
    /**
     * 
     */
    public NamedFeature() {
        
    }
    
    /**
     * Creates a new Concept.
     * 
     * @param id
     *            The concept's identifier.
     */
    public NamedFeature(String id) {
        assert(id != null);
        this.id = id;
    }

    /**
     * Returns this concept's identifier.
     * 
     * @return The identifier.
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return id.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        NamedFeature other = (NamedFeature) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public int compareTo(Feature o) {
        if(!(o instanceof NamedFeature)) {
            return -1;
        } else {
            return id.compareTo(((NamedFeature) o).getId());
        }
    }

} @XmlRootElement
public class NamedRole extends Role {
    
    private static final long serialVersionUID = 1L;
    
    /**
     * String identifier of this concept.
     */
    protected String id;
    
    /**
     * 
     */
    public NamedRole() {
        
    }
    
    /**
     * Creates a new Role.
     * 
     * @param id
     *            The role's identifier.
     */
    public NamedRole(String id) {
        assert(id != null);
        this.id = id;
    }

    /**
     * Returns this role's identifier.
     * 
     * @return The identifier.
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return id.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        NamedRole other = (NamedRole) obj;
        if (id == null) {
            if (other.id != null)
                return false;
            else
                assert(false);
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    public int compareTo(Role o) {
        if(!(o instanceof NamedRole)) {
            return -1;
        } else {
            return id.compareTo(((NamedRole) o).getId());
        }
    }

} public enum Operator {
    EQUALS,
    LESS_THAN,
    LESS_THAN_EQUALS,
    GREATER_THAN,
    GREATER_THAN_EQUALS
} public abstract class Role implements Comparable<Role>, Serializable {
    
    private static final long serialVersionUID = 1L;

    abstract public String toString();

    abstract public int hashCode();

    abstract public boolean equals(Object o);
    
} @XmlRootElement
public class RoleInclusion extends Axiom {

    /**
     * The left hand side of the expression.
     */
    protected Role[] lhs;

    /**
     * The right hand side of the expression.
     */
    protected Role rhs;

    /**
     *
     */
    public RoleInclusion() {

    }

    /**
     * Creates a new {@link RoleInclusion}.
     *
     * @param lhs
     * @param rhs
     */
    public RoleInclusion(final Role[] lhs, final Role rhs) {
        this.lhs = lhs;
        this.rhs = rhs;
    }

    /**
     * Creates a new {@link RoleInclusion}.
     *
     * @param lhs
     * @param rhs
     */
    public RoleInclusion(final Role lhs, final Role rhs) {
        this.lhs = new Role[]{ lhs };
        this.rhs = rhs;
    }

    /**
     * @return the lhs
     */
    public Role[] getLhs() {
        return lhs;
    }

    /**
     * @param lhs the lhs to set
     */
    public void setLhs(Role[] lhs) {
        this.lhs = lhs;
    }

    /**
     * @return the rhs
     */
    public Role getRhs() {
        return rhs;
    }

    /**
     * @param rhs the rhs to set
     */
    public void setRhs(Role rhs) {
        this.rhs = rhs;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        if (lhs.length > 0) {
            sb.append(lhs[0]);
            for (int i = 1; i < lhs.length; i++) {
                sb.append(" o ");
                sb.append(lhs[i]);
            }
        } else {
            sb.append("\u03B5");
        }
        sb.append(" \u2291 ");
        sb.append(rhs);
        return sb.toString();
    }

    @Override
    public int compareTo(Axiom o) {
        if (o instanceof ConceptInclusion) {
            return 1;
        } else if (o instanceof RoleInclusion) {
            RoleInclusion otherRi = (RoleInclusion) o;
            int lhsRes = 0;
            Role[] oLhs = otherRi.getLhs();
            if(!Arrays.equals(lhs, oLhs)) {
                // If length is different put the shortest one first
                if(lhs.length < oLhs.length) {
                    lhsRes = -1;
                } else if(lhs.length > oLhs.length) {
                    lhsRes = 1;
                } else {
                    for(int i = 0; i < lhs.length; i++) {
                        int res = lhs[i].compareTo(oLhs[i]);
                        if(res < 0) {
                            lhsRes = -1;
                            break;
                        } else if(res > 0) {
                            lhsRes = 1;
                            break;
                        }
                    }
                }
            }
            int rhsRes = rhs.compareTo(otherRi.getRhs());
            if(lhsRes == 0 && rhsRes == 0)
                return 0;
            else if(lhsRes != 0)
                return lhsRes;
            else
                return rhsRes;
        } else {
            return -1;
        }
    }

} @XmlRootElement
public class StringLiteral extends Literal {

    private static final long serialVersionUID = 1L;
    
    private String value;
    
    /**
     * 
     */
    public StringLiteral() {
        
    }
    
    public StringLiteral(String value) {
        this.value = value;
    }

    /**
     * @return the value
     */
    public String getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StringLiteral other = (StringLiteral) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return value;
    }

    public int compareTo(Literal o) {
        StringLiteral sl = (StringLiteral) o;
        String otherValue = sl.value;
        return value.compareTo(otherValue);
    }

} public interface IProgressMonitor {
    
    /**
     * Indicates that some task has started.
     */
    void taskStarted(String taskName);

    /**
     * Indicates that the previously started task has now ended.
     */
    void taskEnded();

    /**
     * Indicates that there has been progress in a task.
     *  
     * @param value
     * @param max
     */
    void step(int value, int max);

    /**
     * Indicates that there is a task in progress whose length cannot be
     * determined.
     */
    void taskBusy();
} public class Statistics {
    
    /**
     * Singleton instance.
     */
    public static final Statistics INSTANCE = new Statistics();
    
    /**
     * Map with performance values.
     */
    private final Map<String, Long> stats = new HashMap<String, Long>();
    
    /**
     * Private constructor.
     */
    private Statistics() {
        
    }
    
    /**
     * Sets a time for a performance measurement.
     * 
     * @param name
     * @param value
     */
    public void setTime(String name, long value) {
        stats.put(name, value);
    }
    
    /**
     * Gets a time for a performance measurement. If no measurement with the
     * specified name exists then it returns -1.
     * 
     * @param name
     * @return
     */
    public long getTime(String name) {
        Long res = stats.get(name);
        return (res == null) ? -1 : res.longValue();
    }
    
    /**
     * Returns the names of the performance measures.
     * 
     * @return
     */
    public Set<String> getNames() {
        return stats.keySet();
    }
    
    /**
     * Returns a string with all the current statistics.
     * @return
     */
    public String getStatistics() {
        StringBuilder sb = new StringBuilder();
        
        for(String key : stats.keySet()) {
            sb.append(key);
            sb.append(": ");
            sb.append(stats.get(key));
            sb.append("\n");
        }
        
        return sb.toString();
    }
    
    public long getTotalTime() {
        long res = 0;
        for(String key : stats.keySet()) {
            res += stats.get(key);
        }
        return res;
    }
    
}
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EmptyStackException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import javax.xml.bind.DatatypeConverter;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
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.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.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.OWLDatatypeRestriction;
import org.semanticweb.owlapi.model.OWLDeclarationAxiom;
import org.semanticweb.owlapi.model.OWLDisjointClassesAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLEquivalentObjectPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLFacetRestriction;
import org.semanticweb.owlapi.model.OWLFunctionalDataPropertyAxiom;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLObjectAllValuesFrom;
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.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectUnionOf;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLReflexiveObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.model.OWLSubDataPropertyOfAxiom;
import org.semanticweb.owlapi.model.OWLSubObjectPropertyOfAxiom;
import org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom;
import org.semanticweb.owlapi.model.OWLTransitiveObjectPropertyAxiom;
import org.semanticweb.owlapi.vocab.OWL2Datatype;
import org.semanticweb.owlapi.vocab.OWLFacet;
import au.csiro.ontology.Ontology;
import au.csiro.ontology.importer.BaseImporter;
import au.csiro.ontology.importer.ImportException;
import au.csiro.ontology.model.Axiom;
import au.csiro.ontology.model.BigIntegerLiteral;
import au.csiro.ontology.model.Concept;
import au.csiro.ontology.model.ConceptInclusion;
import au.csiro.ontology.model.Conjunction;
import au.csiro.ontology.model.Datatype;
import au.csiro.ontology.model.DateLiteral;
import au.csiro.ontology.model.DecimalLiteral;
import au.csiro.ontology.model.Existential;
import au.csiro.ontology.model.FloatLiteral;
import au.csiro.ontology.model.FunctionalFeature;
import au.csiro.ontology.model.IntegerLiteral;
import au.csiro.ontology.model.Literal;
import au.csiro.ontology.model.NamedConcept;
import au.csiro.ontology.model.NamedFeature;
import au.csiro.ontology.model.NamedRole;
import au.csiro.ontology.model.Operator;
import au.csiro.ontology.model.Role;
import au.csiro.ontology.model.RoleInclusion;
import au.csiro.ontology.model.StringLiteral;
import au.csiro.ontology.util.IProgressMonitor;
import au.csiro.ontology.util.Statistics;
                if (ent.isOWLClass()) {
                    res.add(new ConceptInclusion(
                            new NamedConcept(ent.asOWLClass().toStringID()), NamedConcept.TOP_CONCEPT));
                } else if (ent.isOWLObjectProperty()) {
                    // Do nothing for now.
                } else if (ent.isOWLDataProperty()) {
                    // Do nothing for now.
                }
            } else if (axiom instanceof OWLSubPropertyChainOfAxiom) {
                OWLSubPropertyChainOfAxiom a = (OWLSubPropertyChainOfAxiom) axiom;
                Collection<Axiom> ax = transformOWLSubPropertyChainOfAxiom(a);
                if(ax != null) res.addAll(ax);
                monitor.step(workDone, totalAxioms);
            } else if (axiom instanceof OWLSubObjectPropertyOfAxiom) {
                OWLSubObjectPropertyOfAxiom a = (OWLSubObjectPropertyOfAxiom) axiom;
                res.addAll(transformOWLSubObjectPropertyOfAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLReflexiveObjectPropertyAxiom) {
                OWLReflexiveObjectPropertyAxiom a = (OWLReflexiveObjectPropertyAxiom) axiom;
                res.add(transformOWLReflexiveObjectPropertyAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLTransitiveObjectPropertyAxiom) {
                OWLTransitiveObjectPropertyAxiom a = (OWLTransitiveObjectPropertyAxiom) axiom;
                res.add(transformOWLTransitiveObjectPropertyAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLSubClassOfAxiom) {
                OWLSubClassOfAxiom a = (OWLSubClassOfAxiom) axiom;
                Axiom ax = transformOWLSubClassOfAxiom(a);
                if(ax != null) res.add(ax);
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLEquivalentClassesAxiom) {
                OWLEquivalentClassesAxiom a = (OWLEquivalentClassesAxiom) axiom;
                res.addAll(transformOWLEquivalentClassesAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLDisjointClassesAxiom) {
                OWLDisjointClassesAxiom a = (OWLDisjointClassesAxiom) axiom;
                Axiom ax = transformOWLDisjointClassesAxiom(a);
                if(ax != null) res.add(ax);
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLEquivalentObjectPropertiesAxiom) {
                OWLEquivalentObjectPropertiesAxiom a = (OWLEquivalentObjectPropertiesAxiom) axiom;
                res.addAll(transformOWLEquivalentObjectPropertiesAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLFunctionalDataPropertyAxiom) {
                OWLFunctionalDataPropertyAxiom a = (OWLFunctionalDataPropertyAxiom) axiom;
                res.add(transformOWLFunctionalDataPropertyAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLSubDataPropertyOfAxiom) {
                OWLSubDataPropertyOfAxiom a = (OWLSubDataPropertyOfAxiom) axiom;
                res.addAll(transformOWLSubDataPropertyOfAxiom(a));
                monitor.step(++workDone, totalAxioms);
            } else if (axiom instanceof OWLAnnotationAssertionAxiom) {
                // Do nothing
                monitor.step(++workDone, totalAxioms);
            } else {
                problems.add("The axiom " + axiom.toString() + " is not currently supported by Snorocket.");
                System.err.println("The axiom " + axiom.toString() + " is not currently supported by Snorocket.");
            }
        }

        // TODO: deal with other axioms types even if Snorocket does not
        // currently support them

        monitor.taskEnded();

        /*
        if(!problems.isEmpty()) {
            throw new ImportException("Problems occurred during import. See getProblems()");
        }
        */

        return res;
    }

	private Set<Axiom> transform(OWLOntology ont, IProgressMonitor monitor) throws ImportException {
        return transform(Collections.list(Collections.enumeration(ont.getAxioms())), monitor);
    }

    /**
     *
     * @param l
     * @return
     */
    private Literal getLiteral(OWLLiteral l) {
        OWLDatatype dt = l.getDatatype();
        String literal = l.getLiteral();

        Literal res = null;

        if(dt.isBuiltIn()) {
            OWL2Datatype odt = dt.getBuiltInDatatype();
            switch (odt) {
                case RDF_PLAIN_LITERAL:
                case RDF_XML_LITERAL:
                case XSD_STRING:
                case XSD_NORMALIZED_STRING:
                case XSD_NAME:
                case XSD_NCNAME:
                case XSD_NMTOKEN:
                case XSD_HEX_BINARY:
                case XSD_BASE_64_BINARY:
                case XSD_ANY_URI:
                case XSD_TOKEN:
                    res = new StringLiteral(literal);
                    break;
                case XSD_INTEGER:
                case XSD_NON_NEGATIVE_INTEGER:
                    if(useSimpleInts) {
                        res = new IntegerLiteral(Integer.parseInt(literal));
                    } else {
                        res = new BigIntegerLiteral(new BigInteger(literal));
                    }
                    break;
                case XSD_DATE_TIME:
                    res = new DateLiteral(DatatypeConverter.parseDateTime(literal));
                    break;
                case OWL_RATIONAL:
                case OWL_REAL:
                case XSD_DECIMAL:
                    if(useSimpleFloats) {
                        res = new FloatLiteral(Float.parseFloat(literal));