package org.phenoscape.io;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.bioontologies.obd.schema.pheno.BearerDocument.Bearer;
import org.bioontologies.obd.schema.pheno.DescriptionDocument.Description;
import org.bioontologies.obd.schema.pheno.MeasurementDocument.Measurement;
import org.bioontologies.obd.schema.pheno.PhenotypeCharacterDocument.PhenotypeCharacter;
import org.bioontologies.obd.schema.pheno.PhenotypeDocument.Phenotype;
import org.bioontologies.obd.schema.pheno.QualifierDocument.Qualifier;
import org.bioontologies.obd.schema.pheno.QualityDocument.Quality;
import org.bioontologies.obd.schema.pheno.RelatedEntityDocument.RelatedEntity;
import org.bioontologies.obd.schema.pheno.TyperefDocument.Typeref;
import org.bioontologies.obd.schema.pheno.UnitDocument.Unit;
import org.obo.annotation.base.OBOUtil;
import org.obo.annotation.base.OBOUtil.Differentium;
import org.obo.datamodel.DanglingObject;
import org.obo.datamodel.IdentifiedObject;
import org.obo.datamodel.Link;
import org.obo.datamodel.LinkedObject;
import org.obo.datamodel.OBOClass;
import org.obo.datamodel.OBOProperty;
import org.obo.datamodel.OBOSession;
import org.obo.datamodel.ObsoletableObject;
import org.obo.datamodel.impl.DanglingClassImpl;
import org.obo.datamodel.impl.DanglingPropertyImpl;
public class PhenoXMLAdapter {
private final Set<String> danglers = new HashSet<String>();
private final Set<String> secondaryIDs = new HashSet<String>();
private final Set<String> replacedIDs = new HashSet<String>();
private final OBOSession session;
public PhenoXMLAdapter(OBOSession session) {
this.session = session;
}
public boolean didCreateDanglers() {
return !this.danglers.isEmpty();
}
public Collection<String> getDanglersList() {
return this.danglers;
}
public boolean didMigrateSecondaryIDs() {
return !this.secondaryIDs.isEmpty();
}
public Collection<String> getMigratedSecondaryIDsList() {
return this.secondaryIDs;
}
public boolean didReplaceObsoleteTerms() {
return !this.replacedIDs.isEmpty();
}
public Collection<String> getReplacedIDsList() {
return this.replacedIDs;
}
public static PhenotypeCharacter createPhenotypeCharacter(org.phenoscape.model.Phenotype phenoCharacter) {
if ((phenoCharacter.getEntity() == null) && (phenoCharacter.getQuality() == null)) {
return null;
}
final PhenotypeCharacter phenotypeCharacter = PhenotypeCharacter.Factory.newInstance();
if (phenoCharacter.getEntity() != null) {
final Bearer bearer = phenotypeCharacter.addNewBearer();
bearer.setTyperef(getTyperefForTerm(phenoCharacter.getEntity()));
}
if (phenoCharacter.getQuality() != null) {
final Quality quality = phenotypeCharacter.addNewQuality();
quality.setTyperef(getTyperefForTerm(phenoCharacter.getQuality()));
if (phenoCharacter.getRelatedEntity() != null) {
final RelatedEntity relatedEntity = quality.addNewRelatedEntity();
relatedEntity.setTyperef(getTyperefForTerm(phenoCharacter.getRelatedEntity()));
}
if (phenoCharacter.getCount() != null) {
quality.setCount(BigInteger.valueOf(phenoCharacter.getCount()));
}
if (phenoCharacter.getMeasurement() != null) {
final Measurement measurement = quality.addNewMeasurement();
measurement.setValue(phenoCharacter.getMeasurement());
if (phenoCharacter.getUnit() != null) {
final Unit unit = measurement.addNewUnit();
unit.setTyperef(getTyperefForTerm(phenoCharacter.getUnit()));
}
}
}
if (phenoCharacter.getComment() != null) {
final Description description = phenotypeCharacter.addNewDescription();
description.setStringValue(phenoCharacter.getComment());
}
return phenotypeCharacter;
}
public static Phenotype createPhenotype(List<PhenotypeCharacter> phenotypeCharacters) {
final Phenotype phenotype = Phenotype.Factory.newInstance();
phenotype.setPhenotypeCharacterArray(phenotypeCharacters.toArray(new PhenotypeCharacter[] {}));
return phenotype;
}
public List<org.phenoscape.model.Phenotype> parsePhenotype(Phenotype phenotype) {
final List<org.phenoscape.model.Phenotype> newPhenotypes = new ArrayList<org.phenoscape.model.Phenotype>();
for (PhenotypeCharacter pc : phenotype.getPhenotypeCharacterList()) {
newPhenotypes.add(parsePhenotypeCharacter(pc));
}
return newPhenotypes;
}
public org.phenoscape.model.Phenotype parsePhenotypeCharacter(PhenotypeCharacter pc) {
final org.phenoscape.model.Phenotype newPhenotype = new org.phenoscape.model.Phenotype();
if ((pc.getBearer() != null) && (pc.getBearer().getTyperef() != null)) {
newPhenotype.setEntity(this.getTermForTyperef(pc.getBearer().getTyperef()));
}
if (!pc.getQualityList().isEmpty()) {
// we only load the first quality for now
final Quality quality = pc.getQualityList().get(0);
if (quality.getTyperef() != null) {
newPhenotype.setQuality(this.getTermForTyperef(quality.getTyperef()));
}
if (!quality.getRelatedEntityList().isEmpty()) {
//we only use one related entity for now
final RelatedEntity e2 = quality.getRelatedEntityList().get(0);
if (e2.getTyperef() != null) {
newPhenotype.setRelatedEntity(this.getTermForTyperef(e2.getTyperef()));
}
}
if (quality.getCount() != null) {
newPhenotype.setCount(quality.getCount().intValue());
}
if (!quality.getMeasurementList().isEmpty()) {
// we only use one measurement for now
final Measurement measurement = quality.getMeasurementList().get(0);
newPhenotype.setMeasurement(measurement.getValue());
if ((measurement.getUnit() != null) && (measurement.getUnit().getTyperef() != null)) {
newPhenotype.setUnit(this.getTermForTyperef(measurement.getUnit().getTyperef()));
}
}
}
if (pc.getDescription() != null) {
newPhenotype.setComment(pc.getDescription().getStringValue());
}
return newPhenotype;
}
private static Typeref getTyperefForTerm(OBOClass term) {
final Typeref tr = Typeref.Factory.newInstance();
if (OBOUtil.isPostCompTerm(term)) {
tr.setAbout(OBOUtil.getGenusTerm(term).getID());
for (Link link : OBOUtil.getAllDifferentia(term)) {
final LinkedObject parent = link.getParent();
if (!(parent instanceof OBOClass)) continue;
final OBOClass differentia = (OBOClass)parent;
final Qualifier qualifier = tr.addNewQualifier();
qualifier.setRelation(link.getType().getID());
qualifier.addNewHoldsInRelationTo().setTyperef(getTyperefForTerm(differentia));
}
} else {
tr.setAbout(term.getID());
}
return tr;
}
private OBOClass getTermForTyperef(Typeref tr) {
final OBOClass genus = this.getTerm(tr.getAbout());
if (tr.sizeOfQualifierArray() > 0) {
// need to create post-comp
final List<Differentium> differentia = new ArrayList<Differentium>();
for (Qualifier qualifier : tr.getQualifierList()) {
final OBOProperty relation = this.getRelation(qualifier.getRelation());
final OBOClass term = this.getTermForTyperef(qualifier.getHoldsInRelationTo().getTyperef());
final Differentium differentium = new Differentium();
differentium.setRelation(relation);
differentium.setTerm(term);
differentia.add(differentium);
}
return OBOUtil.createPostComposition(genus, differentia);
} else {
return genus;
}
}
private OBOClass getTerm(String id) {
log().debug("Term id: " + id);
if (id.equals("http://purl.bioontology.org/ontology/provisional/d0267b99-ff52-4a4c-bd31-ff6dbf4dafcc")) {
log().debug("Provisional term");
}
final IdentifiedObject term = this.session.getObject(id);
if (term instanceof OBOClass) {
final OBOClass oboClass = (OBOClass)term;
if (oboClass.isObsolete()) {
if (!oboClass.getReplacedBy().isEmpty()) {
final ObsoletableObject replacement = oboClass.getReplacedBy().iterator().next();
if ((replacement instanceof OBOClass) && (!(replacement instanceof DanglingObject))) {
this.replacedIDs.add(id);
return (OBOClass)replacement;
} else {
return oboClass;
}
} else {
return oboClass;
}
} else {
return oboClass;
}
} else {
final OBOClass altTerm = this.findTermByAltID(id);
if (altTerm != null) {
return altTerm;
} else {
log().warn("Term not found; creating dangler for " + id);
this.danglers.add(id);
final OBOClass dangler = new DanglingClassImpl(id.trim());
return dangler;
}
}
}
private OBOClass findTermByAltID(String id) {
final Collection<IdentifiedObject> terms = this.session.getObjects();
for (IdentifiedObject object : terms) {
if (object instanceof OBOClass) {
final OBOClass term = (OBOClass)object;
if (term.getSecondaryIDs().contains(id)) {
this.secondaryIDs.add(id);
return term;
}
}
}
return null;
}
private OBOProperty getRelation(String id) {
final IdentifiedObject relation = this.session.getObject(id);
if (relation instanceof OBOProperty) {
return (OBOProperty)relation;
} else {
log().warn("Property not found; creating dangler for " + id);
this.danglers.add(id);
final OBOProperty dangler = new DanglingPropertyImpl(id);
return dangler;
}
}
private static Logger log() {
return Logger.getLogger(PhenoXMLAdapter.class);
}
}