public class CategorisedChange extends LogicalChange {

	/**
	 * @param axiom	Changed axiom
	 * @param isEffectual	true if change is effectual, false otherwise
	 */
	public CategorisedChange(OWLAxiom axiom, boolean isEffectual) {
		super(axiom, isEffectual);
	}
} public class CategorisedEffectualAddition extends CategorisedEffectualChange {
	private EffectualAdditionCategory cat;
	
	/**
	 * Constructor
	 * @param ax	OWL Axiom
	 * @param cat	Change category
	 * @param axAlignment	Set of alignments
	 * @param newTerms	Set of new terms used in the axiom
	 */
	public CategorisedEffectualAddition(OWLAxiom ax, EffectualAdditionCategory cat, Set<OWLAxiom> axAlignment, Set<OWLEntity> newTerms) {
		super(ax, axAlignment, newTerms);
		this.cat = cat;
	}
	
	
	/**
	 * Get effectual addition category name
	 * @return Change category name
	 */
	public String getCategoryName() {
		return cat.toString();
	}
	
	
	/**
	 * Get effectual addition category
	 * @return Change category
	 */
	public EffectualAdditionCategory getCategory() {
		return cat;
	}

	
	/**
	 * Categories of effectual additions
	 */
	public enum EffectualAdditionCategory {
		STRENGTHENING ("Strengthening"),
		STRENGTHENINGNT ("StrengtheningWithNewTerms"),
		PUREADDITION ("PureAddition"),
		PUREADDITIONNT ("PureAdditionWithNewTerms"),
		NEWDESCRIPTION ("NewDescription"),
		MODIFIEDDEFINITION ("NewModifiedDefinition"),
		MODIFIEDDEFINITIONNT ("NewModifiedDefinitionWithNewTerms");

		String name;
		EffectualAdditionCategory(String name) {
			this.name = name;
		}

		public String toString() {
			return name;
		}
	}
} public class CategorisedEffectualChange extends CategorisedChange {
	private Set<OWLAxiom> axAlignment;
	private Set<OWLEntity> differentTerms;
	
	/**
	 * Constructor
	 * @param axiom	OWL axiom
	 * @param axAlignment	Set of axioms with which this change aligns to
	 * @param differentTerms	Set of new or retired terms used in the axiom
	 */
	public CategorisedEffectualChange(OWLAxiom axiom, Set<OWLAxiom> axAlignment, Set<OWLEntity> differentTerms) {
		super(axiom, true);
		this.axAlignment = axAlignment;
		this.differentTerms = differentTerms;
	}

	
	/**
	 * Get the set of axiomatic alignments for this change
	 * @return Set of axiomatic alignments for this change
	 */
	public Set<OWLAxiom> getAxiomAlignment() {
		return axAlignment;
	}
	
	
	/**
	 * Get the new terms used in this change
	 * @return The set of new terms used in this change
	 */
	public Set<OWLEntity> getDifferentTerms() {
		return differentTerms;
	}
} public class CategorisedEffectualRemoval extends CategorisedEffectualChange {
	private EffectualRemovalCategory cat;
	
	/**
	 * Constructor
	 * @param ax	OWL Axiom
	 * @param cat	Change category
	 * @param axAlignment	Set of alignments
	 * @param retiredTerms	Set of retired terms used in the axiom
	 */
	public CategorisedEffectualRemoval(OWLAxiom ax, EffectualRemovalCategory cat, Set<OWLAxiom> axAlignment, Set<OWLEntity> retiredTerms) {
		super(ax, axAlignment, retiredTerms);
		this.cat = cat;
	}
	
	
	/**
	 * Get effectual removal category name
	 * @return Change category name
	 */
	public String getCategoryName() {
		return cat.toString();
	}
	
	
	/**
	 * Get effectual removal category
	 * @return Change category
	 */
	public EffectualRemovalCategory getCategory() {
		return cat;
	}
	
	
	/**
	 * Categories of effectual removals
	 */
	public enum EffectualRemovalCategory {
		WEAKENING ("Weakening"),
		WEAKENINGRT ("WeakeningWithRetiredTerms"),
		PUREREMOVAL ("PureRemoval"),
		PUREREMOVALRT ("PureRemovalWithRetiredTerms"),
		RETIREDDESCRIPTION ("RetiredDescription"),
		MODIFIEDDEFINITION ("RetiredModifiedDefinition"),
		MODIFIEDDEFINITIONRT ("RetiredModifiedDefinitionWithRetiredTerms");

		String name;
		EffectualRemovalCategory(String name) {
			this.name = name;
		}

		public String toString() {
			return name;
		}
	}
} public class CategorisedIneffectualAddition extends CategorisedChange {
	private Map<Explanation<OWLAxiom>,Set<IneffectualAdditionCategory>> cats;
	
	/**
	 * Constructor
	 * @param ax	OWL Axiom
	 * @param cats	Map of justifications to change category
	 */
	public CategorisedIneffectualAddition(OWLAxiom ax, Map<Explanation<OWLAxiom>,Set<IneffectualAdditionCategory>> cats) {
		super(ax, false);
		this.cats = cats;
	}
	
	
	/**
	 * Get the map of justifications to change category
	 * @return Map of justifications to categories
	 */
	public Map<Explanation<OWLAxiom>,Set<IneffectualAdditionCategory>> getJustificationMap() {
		return cats;
	}
	
	
	/**
	 * Get ineffectual addition categories
	 * @return Change categories
	 */
	public Set<IneffectualAdditionCategory> getCategories() {
		Set<IneffectualAdditionCategory> result = new HashSet<IneffectualAdditionCategory>();
		for(Explanation<OWLAxiom> set : cats.keySet()) {
			result.addAll(cats.get(set));
		}
		return result;
	}
	
	
	/**
	 * Categories of ineffectual additions
	 */
	public enum IneffectualAdditionCategory {
		REWRITE ("AddedRewrite"),
		PREWRITE ("AddedPartialRewrite"),
		REDUNDANCY ("AddedRedundancy"),
		RESHUFFLEREDUNDANCY ("AddedReshuffleProspectiveRedundancy"),
		NEWPROSPREDUNDANCY ("AddedNewProspectiveRedundancy");
		
		String name;
		IneffectualAdditionCategory(String name) {
			this.name = name;
		}

		public String toString() {
			return name;
		}
	}
} public class CategorisedIneffectualRemoval extends CategorisedChange {
	private Map<Explanation<OWLAxiom>,Set<IneffectualRemovalCategory>> cats;
	
	/**
	 * Constructor
	 * @param ax	OWL Axiom
	 * @param cats	Map of justifications to change category
	 */
	public CategorisedIneffectualRemoval(OWLAxiom ax, Map<Explanation<OWLAxiom>,Set<IneffectualRemovalCategory>> cats) {
		super(ax, false);
		this.cats = cats;
	}
	
	
	/**
	 * Get the map of justifications to change category
	 * @return Map of justifications to categories
	 */
	public Map<Explanation<OWLAxiom>,Set<IneffectualRemovalCategory>> getJustificationMap() {
		return cats;
	}
	
	
	/**
	 * Get ineffectual removal categories
	 * @return Change categories
	 */
	public Set<IneffectualRemovalCategory> getCategories() {
		Set<IneffectualRemovalCategory> result = new HashSet<IneffectualRemovalCategory>();
		for(Explanation<OWLAxiom> set : cats.keySet()) {
			result.addAll(cats.get(set));
		}
		return result;
	}
	
	
	/**
	 * Categories of ineffectual removal
	 */
	public enum IneffectualRemovalCategory {
		REWRITE ("RemovedRewrite"),
		PREWRITE ("RemovedPartialRewrite"),
		REDUNDANCY ("RemovedRedundancy"),
		NEWPROSPREDUNDANCY ("RemovedNewProspectiveRedundancy"),
		RESHUFFLEREDUNDANCY ("RemovedReshuffleProspectiveRedundancy");
		
		String name;
		IneffectualRemovalCategory(String name) {
			this.name = name;
		}

		public String toString() {
			return name;
		}
	}
} public enum IneffectualAdditionCategory {
	REWRITE ("AddedRewrite"),
	PREWRITE ("AddedPartialRewrite"),
	REDUNDANCY ("AddedRedundancy"),
	RESHUFFLEREDUNDANCY ("AddedReshuffleProspectiveRedundancy"),
	NEWPROSPREDUNDANCY ("AddedNewProspectiveRedundancy");
		
	String name;
	IneffectualAdditionCategory(String name) {
		this.name = name;
	}

	public String toString() {
		return name;
	}
} public enum IneffectualRemovalCategory {
	REWRITE ("RemovedRewrite"),
	PREWRITE ("RemovedPartialRewrite"),
	REDUNDANCY ("RemovedRedundancy"),
	NEWPROSPREDUNDANCY ("RemovedNewProspectiveRedundancy"),
	RESHUFFLEREDUNDANCY ("RemovedReshuffleProspectiveRedundancy");
		
	String name;
	IneffectualRemovalCategory(String name) {
		this.name = name;
	}

	public String toString() {
		return name;
	}
} public interface AxiomChangeSet extends ChangeSet {
	
	/**
	 * Get the set of additions
	 * @return Set of additions
	 */
	public Set<? extends StructuralChange> getAdditions();
	
	
	/**
	 * Get the set of removals
	 * @return Set of removals
	 */
	public Set<? extends StructuralChange> getRemovals();
	
} public class CategorisedChangeSet implements AxiomChangeSet {
	private double diffTime, eaTime, erTime, iaTime, irTime, iaJustTime, irJustTime, iaLacJustTime, irLacJustTime;
	private Set<CategorisedEffectualAddition> effectualAdditions;
	private Set<CategorisedIneffectualAddition> ineffectualAdditions; 
	private Set<CategorisedEffectualRemoval> effectualRemovals;
	private Set<CategorisedIneffectualRemoval> ineffectualRemovals;
	private Set<CategorisedEffectualAddition> strengthenings, strengtheningsnt, pureadds, pureaddsnt, newdesc, amoddef, amoddefnt;
	private Set<CategorisedEffectualRemoval> weakenings, weakeningsrt, purerems, pureremsrt, retdesc, rmoddef, rmoddefrt;
	private Set<CategorisedIneffectualAddition> arewrite, aprewrite, aredundancy, areshuffle, aprosp, anew; 
	private Set<CategorisedIneffectualRemoval> rrewrite, rprewrite, rredundancy, rreshuffle, rprosp, rnew;
	private Set<OWLAxiom> sharedAxioms, effRems, ineffRems, effAdds, ineffAdds;
	private LogicalChangeSet logicalChangeSet;
	
	/**
	 * Constructor
	 * @param effectualAdditions	Set of categorised effectual additions
	 * @param ineffectualAdditions	Set of categorised ineffectual additions
	 * @param effectualRemovals	Set of categorised effectual removals
	 * @param ineffectualRemovals	Set of categorised ineffectual removals
	 * @param sharedAxioms	Set of shared (unchanged) axioms
	 * @param logicalChangeSet	Logical change set
	 */
	public CategorisedChangeSet(Set<CategorisedEffectualAddition> effectualAdditions, Set<CategorisedIneffectualAddition> ineffectualAdditions, 
			Set<CategorisedEffectualRemoval> effectualRemovals, Set<CategorisedIneffectualRemoval> ineffectualRemovals, Set<OWLAxiom> sharedAxioms, LogicalChangeSet logicalChangeSet) {
		this.effectualAdditions = effectualAdditions;
		this.ineffectualAdditions = ineffectualAdditions;
		this.effectualRemovals = effectualRemovals;
		this.ineffectualRemovals = ineffectualRemovals;
		this.sharedAxioms = sharedAxioms;
		this.logicalChangeSet = logicalChangeSet;
	}
	
	
	/**
	 * Get the logical change set between ontologies 
	 * @return Logical change set
	 */
	public LogicalChangeSet getLogicalChangeSet() {
		return logicalChangeSet;
	}
	
	
	/**
	 * Get the structural change set between ontologies 
	 * @return Structural change set
	 */
	public StructuralChangeSet getStructuralChangeSet() {
		return logicalChangeSet.getStructuralChangeSet();
	}
	
	
	/**
	 * Set the effectual additions categorisation time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setEffectualAdditionCategorisationTime(double time) {
		eaTime = time;
	}
	
	
	/**
	 * Set the effectual removals categorisation time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setEffectualRemovalCategorisationTime(double time) {
		erTime = time;
	}
	
	
	/**
	 * Set the ineffectual removals categorisation time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setIneffectualRemovalCategorisationTime(double time) {
		irTime = time;
	}
	
	
	/**
	 * Set the ineffectual removals categorisation time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setIneffectualAdditionCategorisationTime(double time) {
		iaTime = time;
	}
	
	
	/**
	 * Set the ineffectual addition justification finding time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setIneffectualAdditionJustificationFindingTime(double time) {
		iaJustTime = time;
	}
	
	
	/**
	 * Set the ineffectual removal justification finding time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setIneffectualRemovalJustificationFindingTime(double time) {
		irJustTime = time;
	}
	
	
	/**
	 * Set the ineffectual addition laconic justification finding time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setIneffectualAdditionLaconicJustificationFindingTime(double time) {
		iaLacJustTime = time;
	}
	
	
	/**
	 * Set the ineffectual removal laconic justification finding time
	 * @param time	Time (in seconds)
	 * @deprecated
	 */
	public void setIneffectualRemovalLaconicJustificationFindingTime(double time) {
		irLacJustTime = time;
	}
	
	
	/**
	 * Get the effectual additions categorisation time
	 * @return Categorisation time (in seconds)
	 */
	public double getEffectualAdditionCategorisationTime() {
		return eaTime;
	}
	
	
	/**
	 * Get the effectual removals categorisation time
	 * @return Categorisation time (in seconds)
	 */
	public double getEffectualRemovalCategorisationTime() {
		return erTime;
	}
	
	
	/**
	 * Get the ineffectual removals categorisation time
	 * @return Categorisation time (in seconds)
	 */
	public double getIneffectualRemovalCategorisationTime() {
		return irTime;
	}
	
	
	/**
	 * Get the ineffectual additions categorisation time
	 * @return Categorisation time (in seconds)
	 */
	public double getIneffectualAdditionCategorisationTime() {
		return iaTime;
	}
	
	
	/**
	 * Get the ineffectual additions justification finding time
	 * @return Justification finding time (in seconds)
	 */
	public double getIneffectualAdditionJustificationFindingTime() {
		return iaJustTime;
	}
	
	
	/**
	 * Get the ineffectual removals justification finding time
	 * @return Justification finding time (in seconds)
	 */
	public double getIneffectualRemovalJustificationFindingTime() {
		return irJustTime;
	}
	
	
	/**
	 * Get the ineffectual additions laconic justification finding time
	 * @return Justification finding time (in seconds)
	 */
	public double getIneffectualAdditionLaconicJustificationFindingTime() {
		return iaLacJustTime;
	}
	
	
	/**
	 * Get the ineffectual removals laconic justification finding time
	 * @return Justification finding time (in seconds)
	 */
	public double getIneffectualRemovalLaconicJustificationFindingTime() {
		return irLacJustTime;
	}
	
	
	/**
	 * Instantiate the effectual addition categories sets and populate them accordingly
	 */
	private void sortOutEffectualAdditions() {
		instantiateEASets();
		for(CategorisedEffectualAddition c : effectualAdditions) {
			if(c.getCategory().equals(EffectualAdditionCategory.STRENGTHENING))
				strengthenings.add(c);
			else if(c.getCategory().equals(EffectualAdditionCategory.STRENGTHENINGNT))
				strengtheningsnt.add(c);
			else if(c.getCategory().equals(EffectualAdditionCategory.PUREADDITION))
				pureadds.add(c);
			else if(c.getCategory().equals(EffectualAdditionCategory.PUREADDITIONNT))
				pureaddsnt.add(c);
			else if(c.getCategory().equals(EffectualAdditionCategory.NEWDESCRIPTION))
				newdesc.add(c);
			else if(c.getCategory().equals(EffectualAdditionCategory.MODIFIEDDEFINITION))
				amoddef.add(c);
			else if(c.getCategory().equals(EffectualAdditionCategory.MODIFIEDDEFINITIONNT))
				amoddefnt.add(c);
		}
	}
	
	
	/**
	 * Instantiate the effectual removal categories sets and populate them accordingly
	 */
	private void sortOutEffectualRemovals() {
		instantiateERSets();
		for(CategorisedEffectualRemoval c : effectualRemovals) {
			if(c.getCategory().equals(EffectualRemovalCategory.WEAKENING))
				weakenings.add(c);
			else if(c.getCategory().equals(EffectualRemovalCategory.WEAKENINGRT))
				weakeningsrt.add(c);
			else if(c.getCategory().equals(EffectualRemovalCategory.PUREREMOVAL))
				purerems.add(c);
			else if(c.getCategory().equals(EffectualRemovalCategory.PUREREMOVALRT))
				pureremsrt.add(c);
			else if(c.getCategory().equals(EffectualRemovalCategory.RETIREDDESCRIPTION))
				retdesc.add(c);
			else if(c.getCategory().equals(EffectualRemovalCategory.MODIFIEDDEFINITION))
				rmoddef.add(c);
			else if(c.getCategory().equals(EffectualRemovalCategory.MODIFIEDDEFINITIONRT))
				rmoddefrt.add(c);
		}
	}
	
	
	/**
	 * Instantiate the ineffectual addition categories sets and populate them accordingly
	 */
	private void sortOutIneffectualAdditions() {
		instantiateIASets();
		for(CategorisedIneffectualAddition c : ineffectualAdditions) {
			for(IneffectualAdditionCategory cat : c.getCategories()) {
				if(cat.equals(IneffectualAdditionCategory.REWRITE))
					arewrite.add(c);
				if(cat.equals(IneffectualAdditionCategory.PREWRITE))
					aprewrite.add(c);
				if(cat.equals(IneffectualAdditionCategory.REDUNDANCY))
					aredundancy.add(c);
				if(cat.equals(IneffectualAdditionCategory.NEWPROSPREDUNDANCY)) {
					anew.add(c);
					aprosp.add(c);
				}
				if(cat.equals(IneffectualAdditionCategory.RESHUFFLEREDUNDANCY)) {
					areshuffle.add(c);
					aprosp.add(c);
				}
			}
		}
	}
	
	
	/**
	 * Instantiate the ineffectual removal categories sets and populate them accordingly
	 */
	private void sortOutIneffectualRemovals() {
		instantiateIRSets();
		for(CategorisedIneffectualRemoval c : ineffectualRemovals) {
			for(IneffectualRemovalCategory cat : c.getCategories()) {
				if(cat.equals(IneffectualRemovalCategory.REWRITE))
					rrewrite.add(c);
				if(cat.equals(IneffectualRemovalCategory.PREWRITE))
					rprewrite.add(c);
				if(cat.equals(IneffectualRemovalCategory.REDUNDANCY))
					rredundancy.add(c);
				if(cat.equals(IneffectualRemovalCategory.NEWPROSPREDUNDANCY)) {
					rnew.add(c);
					rprosp.add(c);
				}
				if(cat.equals(IneffectualRemovalCategory.RESHUFFLEREDUNDANCY)) {
					rreshuffle.add(c);
					rprosp.add(c);
				}
			}
		}
	}
	
	
	/**
	 * Get the set of shared axioms
	 * @return Set of shared axioms
	 */
	public Set<OWLAxiom> getSharedAxioms() {
		return sharedAxioms;
	}
	
	
	/**
	 * Get the set of strengthenings from the change set
	 * @return Set of strengthenings in the change set
	 */
	public Set<CategorisedEffectualAddition> getStrengthenings() {
		if(strengthenings == null) sortOutEffectualAdditions();
		return strengthenings;
	}
	
	
	/**
	 * Get the set of strengthenings with new terms from the change set
	 * @return Set of strengthenings with new terms in the change set
	 */
	public Set<CategorisedEffectualAddition> getStrengtheningsWithNewTerms() {
		if(strengtheningsnt == null) sortOutEffectualAdditions();
		return strengtheningsnt;
	}
	
	
	/**
	 * Get the set of pure additions from the change set
	 * @return Set of pure additions in the change set
	 */
	public Set<CategorisedEffectualAddition> getPureAdditions() {
		if(pureadds == null) sortOutEffectualAdditions();
		return pureadds;
	}
	
	
	/**
	 * Get the set of pure additions with new terms from the change set
	 * @return Set of pure additions with new terms in the change set
	 */
	public Set<CategorisedEffectualAddition> getPureAdditionsWithNewTerms() {
		if(pureaddsnt == null) sortOutEffectualAdditions();
		return pureaddsnt;
	}
	
	
	/**
	 * Get the set of new descriptions from the change set
	 * @return Set of new descriptions in the change set
	 */
	public Set<CategorisedEffectualAddition> getNewDescriptions() {
		if(newdesc == null) sortOutEffectualAdditions();
		return newdesc;
	}
	
	
	/**
	 * Get the set of added modified definitions from the change set
	 * @return Set of added modified definitions in the change set
	 */
	public Set<CategorisedEffectualAddition> getAddedModifiedDefinitions() {
		if(amoddef == null) sortOutEffectualAdditions();
		return amoddef;
	}
	
	
	/**
	 * Get the set of added modified definitions with new terms from the change set
	 * @return Set of added modified definitions with new terms in the change set
	 */
	public Set<CategorisedEffectualAddition> getAddedModifiedDefinitionsWithNewTerms() {
		if(amoddefnt == null) sortOutEffectualAdditions();
		return amoddefnt;
	}
	
	
	/**
	 * Get the set of weakenings from the change set
	 * @return Set of weakenings in the change set
	 */
	public Set<CategorisedEffectualRemoval> getWeakenings() {
		if(weakenings == null) sortOutEffectualRemovals();
		return weakenings;
	}
	
	
	/**
	 * Get the set of weakenings with retired terms from the change set
	 * @return Set of weakenings with retired terms in the change set
	 */
	public Set<CategorisedEffectualRemoval> getWeakeningsWithRetiredTerms() {
		if(weakeningsrt == null) sortOutEffectualRemovals();
		return weakeningsrt;
	}
	
	
	/**
	 * Get the set of pure removals from the change set
	 * @return Set of pure removals in the change set
	 */
	public Set<CategorisedEffectualRemoval> getPureRemovals() {
		if(purerems == null) sortOutEffectualRemovals();
		return purerems;
	}
	
	
	/**
	 * Get the set of pure removals with retired terms from the change set
	 * @return Set of pure removals with retired terms in the change set
	 */
	public Set<CategorisedEffectualRemoval> getPureRemovalsWithRetiredTerms() {
		if(pureremsrt == null) sortOutEffectualRemovals();
		return pureremsrt;
	}
	
	
	/**
	 * Get the set of retired descriptions from the change set
	 * @return Set of retired descriptions in the change set
	 */
	public Set<CategorisedEffectualRemoval> getRetiredDescriptions() {
		if(retdesc == null) sortOutEffectualRemovals();
		return retdesc;
	}
	
	
	/**
	 * Get the set of removed modified definitions from the change set
	 * @return Set of removed modified definitions in the change set
	 */
	public Set<CategorisedEffectualRemoval> getRemovedModifiedDefinitions() {
		if(rmoddef == null) sortOutEffectualRemovals();
		return rmoddef;
	}
	
	
	/**
	 * Get the set of removed modified definitions with retired terms from the change set
	 * @return Set of removed modified definitions with retired terms in the change set
	 */
	public Set<CategorisedEffectualRemoval> getRemovedModifiedDefinitionsWithRetiredTerms() {
		if(rmoddefrt == null) sortOutEffectualRemovals();
		return rmoddefrt;
	}
	
	
	/**
	 * Get the set of added rewrites
	 * @return Set of added rewrites
	 */
	public Set<CategorisedIneffectualAddition> getAddedRewrites() {
		if(arewrite == null) sortOutIneffectualAdditions();
		return arewrite;
	}
	
	
	/**
	 * Get the set of added partial rewrites
	 * @return Set of added partial rewrites
	 */
	public Set<CategorisedIneffectualAddition> getAddedPartialRewrites() {
		if(aprewrite == null) sortOutIneffectualAdditions();
		return aprewrite;
	}
	
	
	/**
	 * Get the set of added redundancies
	 * @return Set of added redundancies
	 */
	public Set<CategorisedIneffectualAddition> getAddedRedundancies() {
		if(aredundancy == null) sortOutIneffectualAdditions();
		return aredundancy;
	}
	

	/**
	 * Get the set of added prospective redundancies
	 * @return Set of added prospective redundancies
	 */
	public Set<CategorisedIneffectualAddition> getAddedProspectiveRedundancies() {
		if(aprosp == null) sortOutIneffectualAdditions();
		return aprosp;
	}
	
	
	/**
	 * Get the set of added reshuffle redundancies
	 * @return Set of added reshuffle redundancies
	 */
	public Set<CategorisedIneffectualAddition> getAddedReshuffleRedundancies() {
		if(areshuffle == null) sortOutIneffectualAdditions();
		return areshuffle;
	}
	
	
	/**
	 * Get the set of added prospective new redundancies
	 * @return Set of added prospective new redundancies
	 */
	public Set<CategorisedIneffectualAddition> getAddedProspectiveNewRedundancies() {
		if(anew == null) sortOutIneffectualAdditions();
		return anew;
	}

	
	/**
	 * Get the set of removed rewrites
	 * @return Set of removed rewrites
	 */
	public Set<CategorisedIneffectualRemoval> getRemovedRewrites() {
		if(rrewrite == null) sortOutIneffectualRemovals();
		return rrewrite;
	}
	
	
	/**
	 * Get the set of added partial rewrites
	 * @return Set of added partial rewrites
	 */
	public Set<CategorisedIneffectualRemoval> getRemovedPartialRewrites() {
		if(rprewrite == null) sortOutIneffectualRemovals();
		return rprewrite;
	}
	
	
	/**
	 * Get the set of removed redundancies
	 * @return Set of removed redundancies
	 */
	public Set<CategorisedIneffectualRemoval> getRemovedRedundancies() {
		if(rredundancy == null) sortOutIneffectualRemovals();
		return rredundancy;
	}
	

	/**
	 * Get the set of removed prospective redundancies
	 * @return Set of removed prospective redundancies
	 */
	public Set<CategorisedIneffectualRemoval> getRemovedProspectiveRedundancies() {
		if(rprosp == null) sortOutIneffectualRemovals();
		return rprosp;
	}
	
	
	/**
	 * Get the set of removed reshuffle redundancies
	 * @return Set of removed reshuffle redundancies
	 */
	public Set<CategorisedIneffectualRemoval> getRemovedReshuffleRedundancies() {
		if(rreshuffle == null) sortOutIneffectualRemovals();
		return rreshuffle;
	}
	
	
	/**
	 * Get the set of removed prospective new redundancies
	 * @return Set of removed prospective new redundancies
	 */
	public Set<CategorisedIneffectualRemoval> getRemovedProspectiveNewRedundancies() {
		if(rnew == null) sortOutIneffectualRemovals();
		return rnew;
	}
	
	
	/**
	 * Get the set of categorised effectual additions
	 * @return Set of categorised effectual additions
	 */
	public Set<CategorisedEffectualAddition> getCategorisedEffectualAdditions() {
		return effectualAdditions;
	}
	
	
	/**
	 * Get the set of categorised ineffectual additions
	 * @return Set of categorised ineffectual additions
	 */
	public Set<CategorisedIneffectualAddition> getCategorisedIneffectualAdditions() {
		return ineffectualAdditions;
	}
	
	
	/**
	 * Get the set of categorised ineffectual removals
	 * @return Set of categorised ineffectual removals
	 */
	public Set<CategorisedIneffectualRemoval> getCategorisedIneffectualRemovals() {
		return ineffectualRemovals;
	}
	
	
	/**
	 * Get the set of categorised effectual removals
	 * @return Set of categorised effectual removals
	 */
	public Set<CategorisedEffectualRemoval> getCategorisedEffectualRemovals() {
		return effectualRemovals;
	}
	
	
	/**
	 * Set diff time 
	 * @param time	Diff time
	 * @deprecated
	 */
	public void setDiffTime(double time) {
		diffTime = time;
	}
	
	
	/**
	 * Get the CPU time (in seconds) spent in structural diff
	 * @return CPU time (in seconds) spent in structural diff
	 */
	public double getOperationTime() {
		return diffTime;
	}
	
	
	/**
	 * Get the set of effectual and ineffectual additions in the change set
	 * @return Set of effectual and ineffectual additions in the change set
	 */
	public Set<CategorisedChange> getAdditions() {
		Set<CategorisedChange> result = new HashSet<CategorisedChange>();
		result.addAll(effectualAdditions);
		result.addAll(ineffectualAdditions);
		return result;
	}
	
	
	/**
	 * Get the set of categorised effectual additions
	 * @return Set of categorised effectual additions
	 */
	public Set<? extends CategorisedChange> getEffectualAdditions() {
		return effectualAdditions;
	}
	
	
	/**
	 * Get the set of effectual addition axioms
	 * @return Set of effectual addition axioms
	 */
	public Set<OWLAxiom> getEffectualAdditionAxioms() {
		if(effAdds == null) {
			effAdds = new HashSet<OWLAxiom>();
			for(CategorisedChange c : effectualAdditions) {
				effAdds.add(c.getAxiom());
			}
		}
		return effAdds;
	}
	
	
	/**
	 * Get the set of categorised effectual removals
	 * @return Set of categorised effectual removals
	 */
	public Set<? extends CategorisedChange> getEffectualRemovals() {
		return effectualRemovals;
	}
	
	
	/**
	 * Get the set of effectual removal axioms
	 * @return Set of effectual removal axioms
	 */
	public Set<OWLAxiom> getEffectualRemovalAxioms() {
		if(effRems == null) {
			effRems = new HashSet<OWLAxiom>();
			for(CategorisedChange c : effectualRemovals) {
				effRems.add(c.getAxiom());
			}
		}
		return effRems;
	}
	
	
	/**
	 * Get the set of categorised ineffectual removals
	 * @return Set of categorised ineffectual removals
	 */
	public Set<? extends CategorisedChange> getIneffectualRemovals() {
		return ineffectualRemovals;
	}
	
	
	/**
	 * Get the set of ineffectual removal axioms
	 * @return Set of ineffectual removal axioms
	 */
	public Set<OWLAxiom> getIneffectualRemovalAxioms() {
		if(ineffRems == null) {
			ineffRems = new HashSet<OWLAxiom>();
			for(CategorisedChange c : ineffectualRemovals) {
				ineffRems.add(c.getAxiom());
			}
		}
		return ineffRems;
	}
	
	
	/**
	 * Get the set of categorised ineffectual additions
	 * @return Set of categorised ineffectual additions
	 */
	public Set<? extends CategorisedChange> getIneffectualAdditions() {
		return ineffectualAdditions;
	}
	
	
	/**
	 * Get the set of ineffectual addition axioms
	 * @return Set of ineffectual addition axioms
	 */
	public Set<OWLAxiom> getIneffectualAdditionAxioms() {
		if(ineffAdds == null) {
			ineffAdds = new HashSet<OWLAxiom>();
			for(CategorisedChange c : ineffectualAdditions) {
				ineffAdds.add(c.getAxiom());
			}
		}
		return ineffAdds;
	}
	
	
	/**
	 * Get the set of effectual and ineffectual removals in the change set
	 * @return Set of effectual and ineffectual removals in the change set
	 */
	public Set<CategorisedChange> getRemovals() {
		Set<CategorisedChange> result = new HashSet<CategorisedChange>();
		result.addAll(effectualRemovals);
		result.addAll(ineffectualRemovals);
		return result;
	}
	
	
	/**
	 * Check if change set contains no changes
	 * @return true if change set contains no changes, false otherwise
	 */
	public boolean isEmpty() {
		if(effectualAdditions.isEmpty() && effectualRemovals.isEmpty() 
				&& ineffectualAdditions.isEmpty() && ineffectualAdditions.isEmpty())
			return true;
		else
			return false;
	}
	
	
	/**
	 * Check if change set contains no meaningful changes, i.e., changes which are effectual
	 * @return true if change set contains no effectual changes, false otherwise
	 */
	public boolean isFreeOfEffectualChanges() {
		if(effectualAdditions.isEmpty() && effectualRemovals.isEmpty())
			return true;
		else
			return false;
	}
	
	
	/**
	 * Instantiate the effectual addition sets
	 */
	private void instantiateEASets() {
		strengthenings = new HashSet<CategorisedEffectualAddition>();
		strengtheningsnt = new HashSet<CategorisedEffectualAddition>();
		pureadds = new HashSet<CategorisedEffectualAddition>();
		pureaddsnt = new HashSet<CategorisedEffectualAddition>();
		newdesc = new HashSet<CategorisedEffectualAddition>();
		amoddef = new HashSet<CategorisedEffectualAddition>();
		amoddefnt = new HashSet<CategorisedEffectualAddition>();
	}
	
	
	/**
	 * Instantiate the effectual removal sets
	 */
	private void instantiateERSets() {
		weakenings = new HashSet<CategorisedEffectualRemoval>();
		weakeningsrt = new HashSet<CategorisedEffectualRemoval>();
		purerems = new HashSet<CategorisedEffectualRemoval>();
		pureremsrt = new HashSet<CategorisedEffectualRemoval>();
		retdesc = new HashSet<CategorisedEffectualRemoval>();
		rmoddef = new HashSet<CategorisedEffectualRemoval>();
		rmoddefrt = new HashSet<CategorisedEffectualRemoval>();
	}
	
	
	/**
	 * Instantiate the ineffectual addition sets
	 */
	private void instantiateIASets() {
		arewrite = new HashSet<CategorisedIneffectualAddition>();
		aprewrite = new HashSet<CategorisedIneffectualAddition>();
		aredundancy = new HashSet<CategorisedIneffectualAddition>();
		areshuffle = new HashSet<CategorisedIneffectualAddition>();
		aprosp = new HashSet<CategorisedIneffectualAddition>();
		anew = new HashSet<CategorisedIneffectualAddition>();
	}
	
	
	/**
	 * Instantiate the ineffectual removal sets
	 */
	private void instantiateIRSets() {
		rrewrite = new HashSet<CategorisedIneffectualRemoval>();
		rprewrite = new HashSet<CategorisedIneffectualRemoval>();
		rredundancy = new HashSet<CategorisedIneffectualRemoval>();
		rreshuffle = new HashSet<CategorisedIneffectualRemoval>();
		rprosp = new HashSet<CategorisedIneffectualRemoval>();
		rnew = new HashSet<CategorisedIneffectualRemoval>();
	}
} public class LogicalChangeSet implements AxiomChangeSet {
	private Set<OWLAxiom> effectualAdditions, ineffectualAdditions, effectualRemovals, ineffectualRemovals;
	private StructuralChangeSet structuralChangeSet;
	private double diffTime;
	
	/**
	 * Constructor
	 * @param effectualAdditions	Effectual additions
	 * @param ineffectualAdditions	Ineffectual additions
	 * @param effectualRemovals	Effectual removals
	 * @param ineffectualRemovals	Ineffectual removals
	 * @param structuralChangeSet	Structural change set
	 */
	public LogicalChangeSet(Set<OWLAxiom> effectualAdditions, Set<OWLAxiom> ineffectualAdditions, 
			Set<OWLAxiom> effectualRemovals, Set<OWLAxiom> ineffectualRemovals, StructuralChangeSet structuralChangeSet) {
		this.effectualAdditions = effectualAdditions;
		this.ineffectualAdditions = ineffectualAdditions;
		this.effectualRemovals = effectualRemovals;
		this.ineffectualRemovals = ineffectualRemovals;
		this.structuralChangeSet = structuralChangeSet;
	}
	
	
	/**
	 * Get the structural change set between ontologies
	 * @return Structural change set
	 */
	public StructuralChangeSet getStructuralChangeSet() {
		return structuralChangeSet;
	}
	
	
	/**
	 * Set diff time 
	 * @param time	Diff time
	 * @deprecated
	 */
	public void setDiffTime(double time) {
		diffTime = time;
	}
	
	
	/**
	 * Get the CPU time (in seconds) spent in structural diff
	 * @return CPU time (in seconds) spent in structural diff
	 */
	public double getOperationTime() {
		return diffTime;
	}
	
	
	/**
	 * Get the set of effectual and ineffectual additions
	 * @return Set of effectual and ineffectual additions
	 */
	public Set<LogicalAddition> getAdditions() {
		Set<LogicalAddition> additionSet = new HashSet<LogicalAddition>();
		for(OWLAxiom ax : effectualAdditions)
			additionSet.add(new LogicalAddition(ax, true));
		for(OWLAxiom ax : ineffectualAdditions)
			additionSet.add(new LogicalAddition(ax, false));
		return additionSet;
	}

	
	/**
	 * Get the set of effectual and ineffectual removals
	 * @return Set of effectual and ineffectual removals
	 */
	public Set<LogicalRemoval> getRemovals() {
		Set<LogicalRemoval> removalSet = new HashSet<LogicalRemoval>();
		for(OWLAxiom ax : effectualRemovals)
			removalSet.add(new LogicalRemoval(ax, true));
		for(OWLAxiom ax : ineffectualRemovals)
			removalSet.add(new LogicalRemoval(ax, false));
		return removalSet;
	}

	
	/**
	 * Get the set of effectual addition axioms
	 * @return Set of effectual addition axioms
	 */
	public Set<OWLAxiom> getEffectualAdditionAxioms() {
		return effectualAdditions;
	}
	
	
	/**
	 * Get the set of effectual removal axioms
	 * @return Set of effectual removal axioms
	 */
	public Set<OWLAxiom> getEffectualRemovalAxioms() {
		return effectualRemovals;
	}
	
	
	/**
	 * Get the set of ineffectual addition axioms
	 * @return Set of ineffectual addition axioms
	 */
	public Set<OWLAxiom> getIneffectualAdditionAxioms() {
		return ineffectualAdditions;
	}
	
	
	/**
	 * Get the set of ineffectual removal axioms
	 * @return Set of ineffectual removal axioms
	 */
	public Set<OWLAxiom> getIneffectualRemovalAxioms() {
		return ineffectualRemovals;
	}
	
	
	/**
	 * Check if change set contains no changes
	 * @return true if change set contains no changes, false otherwise
	 */
	public boolean isEmpty() {
		if(effectualAdditions.isEmpty() && effectualRemovals.isEmpty() 
				&& ineffectualAdditions.isEmpty() && ineffectualAdditions.isEmpty())
			return true;
		else
			return false;
	}
} public class StructuralChangeSet implements AxiomChangeSet {
	private Set<OWLAxiom> additions, removals, shared;
	private String ont1name, ont2name;
	private double diffTime;
	
	/**
	 * Constructor
	 * @param additions	Set of added axioms
	 * @param removals	Set of removed axioms
	 * @param shared	Set of shared axioms
	 */
	public StructuralChangeSet(Set<OWLAxiom> additions, Set<OWLAxiom> removals, Set<OWLAxiom> shared) {
		this.additions = additions;
		this.removals = removals;
		this.shared = shared;
	}
	
	
	/**
	 * Set file name of specified ontology (1 or 2)
	 * @param ontNr	Ontology number
	 * @param name	Ontology file name
	 * @deprecated
	 */
	public void setOntologyName(int ontNr, String name) {
		if(ontNr == 1) ont1name = name;
		else if(ontNr == 2) ont2name = name;
	}
	
	
	/**
	 * Set diff time 
	 * @param time	Diff time
	 * @deprecated
	 */
	public void setDiffTime(double time) {
		diffTime = time;
	}
	
	
	/**
	 * Get the CPU time (in seconds) spent in structural diff
	 * @return CPU time (in seconds) spent in structural diff
	 */
	public double getOperationTime() {
		return diffTime;
	}
	
	
	/**
	 * Get file name of ontology 1
	 * @return File name of ontology 1
	 */
	public String getOntology1FileName() {
		return ont1name;
	}
	
	
	/**
	 * Get file name of ontology 2
	 * @return File name of ontology 2
	 */
	public String getOntology2FileName() {
		return ont2name;
	}
	
	
	/**
	 * Get the set of structural additions
	 * @return Set of structural additions
	 */
	public Set<StructuralAddition> getAdditions() {
		Set<StructuralAddition> additionSet = new HashSet<StructuralAddition>();
		for(OWLAxiom ax : additions)
			additionSet.add(new StructuralAddition(ax));		
		return additionSet;
	}
	
	
	/**
	 * Get the set of structural removals
	 * @return Set of structural removals
	 */
	public Set<StructuralRemoval> getRemovals() {
		Set<StructuralRemoval> removalSet = new HashSet<StructuralRemoval>();
		for(OWLAxiom ax : removals)
			removalSet.add(new StructuralRemoval(ax));
		return removalSet;
	}
	
	
	/**
	 * Get the set of added axioms
	 * @return Set of added axioms
	 */
	public Set<OWLAxiom> getAddedAxioms() {
		return additions;
	}
	
	
	/**
	 * Get the set of removed axioms
	 * @return Set of removed axioms
	 */
	public Set<OWLAxiom> getRemovedAxioms() {
		return removals;
	}
	
	
	/**
	 * Get the set of shared axioms
	 * @return Set of shared axioms
	 */
	public Set<OWLAxiom> getShared() {
		return shared;
	}
	
	
	/**
	 * Check if change set is empty (i.e., contains no additions or removals)
	 */
	public boolean isEmpty() {
		if(removals.isEmpty() && additions.isEmpty())
			return true;
		else
			return false;
	}
} public class GenSymShortFormProvider implements ShortFormProvider {
	private HashMap<OWLEntity,String> map;
	
	public GenSymShortFormProvider(HashMap<OWLEntity,String> map) {
		this.map = map;
	}
	
	@Override
	public void dispose() {
		// Do nothing
	}

	@Override
	public String getShortForm(OWLEntity arg0) {
		String output = "";
		SimpleShortFormProvider fp = new SimpleShortFormProvider();
		if(map.get(arg0) != null)
			output = map.get(arg0);
		else
			output = fp.getShortForm(arg0);
		return output;
	}
} public class LabelShortFormProvider implements ShortFormProvider {
	private HashMap<OWLEntity,String> map;
	private SimpleShortFormProvider fp;
	
	/**
	 * Constructor
	 * @param map	Map of entities to labels
	 */
	public LabelShortFormProvider(HashMap<OWLEntity,String> map) {
		this.map = map;
		fp = new SimpleShortFormProvider();
	}
	
	@Override
	public void dispose() {
		// Do nothing
	}

	@Override
	public String getShortForm(OWLEntity arg0) {
		String output = "";
		if(map.get(arg0) != null)
			output = map.get(arg0);
		else
			output = fp.getShortForm(arg0);	
		return output;
	}
}
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.semanticweb.owl.explanation.api.Explanation;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLObject;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.util.ShortFormProvider;
import org.semanticweb.owlapi.util.SimpleShortFormProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedChange;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedEffectualAddition;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedEffectualChange;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedEffectualRemoval;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedIneffectualAddition;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedIneffectualRemoval;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedIneffectualAddition.IneffectualAdditionCategory;
import uk.ac.manchester.cs.diff.axiom.change.CategorisedIneffectualRemoval.IneffectualRemovalCategory;
import uk.ac.manchester.cs.diff.axiom.changeset.AxiomChangeSet;
import uk.ac.manchester.cs.diff.axiom.changeset.CategorisedChangeSet;
import uk.ac.manchester.cs.diff.axiom.changeset.LogicalChangeSet;
import uk.ac.manchester.cs.diff.axiom.changeset.StructuralChangeSet;
import uk.ac.manchester.cs.diff.output.GenSymShortFormProvider;
import uk.ac.manchester.cs.diff.output.LabelShortFormProvider;
import uk.ac.manchester.cs.owl.owlapi.mansyntaxrenderer.ManchesterOWLSyntaxObjectRenderer;
/*******************************************************************************
 * This file is part of ecco.
 * 
 * ecco is distributed under the terms of the GNU Lesser General Public License (LGPL), Version 3.0.
 *  
 * Copyright 2011-2014, The University of Manchester
 *  
 * ecco is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 *  
 * ecco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even 
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
 * General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public License along with ecco.
 * If not, see http://www.gnu.org/licenses/.
 ******************************************************************************/
package uk.ac.manchester.cs.diff.output.xml;





/**
 * @author Rafael S. Goncalves <br>
 * Information Management Group (IMG) <br>
 * School of Computer Science <br>
 * University of Manchester <br>
 */
public class XMLAxiomDiffReport implements XMLDiffReport {
	protected final String uuid = UUID.randomUUID().toString();
	protected SimpleShortFormProvider sf;
	protected GenSymShortFormProvider gp;
	protected LabelShortFormProvider lp;
	protected Document doc, genSymDoc, labelDoc;
	protected HashMap<OWLEntity, String> genSymMap, labelMap;
	protected HashMap<OWLAxiom,Integer> axiomIds;
	protected OWLOntology ont1, ont2;
	protected OWLDataFactory df;
	protected DocumentBuilderFactory dbfac;
	protected DocumentBuilder docBuilder;
	protected AxiomChangeSet changeSet;
	protected int changeNr = 1;
	protected Set<OWLAxiom> sharedAxioms;
	
	/**
	 * Constructor
	 * @param ont1	Ontology 1
	 * @param ont2	Ontology 2
	 * @param changeSet	Change set
	 */
	public XMLAxiomDiffReport(OWLOntology ont1, OWLOntology ont2, AxiomChangeSet changeSet) {
		this.ont1 = ont1;
		this.ont2 = ont2;
		this.dbfac = DocumentBuilderFactory.newInstance();
		this.changeSet = changeSet;
		initMapsAndSFPs();
	}
		
	
	/**
	 * Initialise labels and gensyms maps, and short form providers
	 */
	private void initMapsAndSFPs() {
		try {
			this.docBuilder = dbfac.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		df = ont1.getOWLOntologyManager().getOWLDataFactory();
		genSymMap = new HashMap<OWLEntity,String>();
		labelMap = new HashMap<OWLEntity, String>();
		sf = new SimpleShortFormProvider();
		generateGenSyms(); 		// Prep gen syms output
		mapLabels(ont1); mapLabels(ont2);		// Prep labels output
		gp = new GenSymShortFormProvider(genSymMap);
		lp = new LabelShortFormProvider(labelMap);
	}
	
	
	@Override
	public Document getXMLDocumentUsingTermNames() {
		doc = docBuilder.newDocument();
		prepDocument(doc, "");
		
		if(changeSet instanceof StructuralChangeSet)