package org.nextprot.api.isoform.mapper.service;
import org.nextprot.api.core.utils.seqmap.IsoformSequencePositionMapper;
import org.nextprot.api.isoform.mapper.domain.SingleFeatureQuery;
import org.nextprot.api.isoform.mapper.domain.FeatureQueryException;
import org.nextprot.api.isoform.mapper.domain.SequenceFeature;
import org.nextprot.api.isoform.mapper.domain.impl.BaseFeatureQueryResult;
import org.nextprot.api.isoform.mapper.domain.impl.SingleFeatureQuerySuccessImpl;
import org.nextprot.api.isoform.mapper.domain.impl.exception.*;
import org.nextprot.api.commons.bio.AminoAcidCode;
import org.nextprot.api.commons.bio.variation.prot.SequenceVariation;
import org.nextprot.api.core.dao.EntityName;
import org.nextprot.api.core.domain.Entry;
import org.nextprot.api.core.domain.Isoform;
import java.util.stream.Collectors;
/**
* Validate variant type features on isoform sequence
*
* Created by fnikitin on 05/07/16.
*/
public class SequenceFeatureValidator {
private final Entry entry;
private final SingleFeatureQuery query;
public SequenceFeatureValidator(Entry entry, SingleFeatureQuery query) {
this.entry = entry;
this.query = query;
}
/**
* Coordinate validation process in the multiple steps defined in protected methods.
*/
public BaseFeatureQueryResult validate(SequenceFeature sequenceFeature) throws FeatureQueryException {
checkFeatureGeneName(sequenceFeature);
checkIsoformExistence(sequenceFeature);
checkFeatureChangingAminoAcids(sequenceFeature);
doMoreChecks(sequenceFeature.getProteinVariation());
return new SingleFeatureQuerySuccessImpl(entry, query, sequenceFeature);
}
private void checkIsoformExistence(SequenceFeature sequenceFeature) throws UnknownFeatureIsoformException {
if (!sequenceFeature.isValidIsoform(entry)) {
throw new UnknownFeatureIsoformException(entry, query, sequenceFeature.getIsoformName());
}
}
/**
* Do more feature validation (nothing by default). It is supposed to be overiden by validators that need to
* do more validations.
*
* @param sequenceVariation the sequence variation
* @throws FeatureQueryException if invalid
*/
protected void doMoreChecks(SequenceVariation sequenceVariation) throws FeatureQueryException { }
/**
* Check that gene name is compatible with protein name
* Part of the contract a validator should implement to validate a feature on an isoform sequence
*/
private void checkFeatureGeneName(SequenceFeature sequenceFeature) throws IncompatibleGeneAndProteinNameException {
if (!sequenceFeature.isValidGeneName(entry)) {
throw new IncompatibleGeneAndProteinNameException(query, sequenceFeature.getGeneName(),
entry.getOverview().getGeneNames().stream().map(EntityName::getName).collect(Collectors.toList()));
}
}
/**
* Check that first and last amino-acid(s) described by the feature exists on isoform sequence at given positions
* Part of the contract a validator should implement to validate a feature on an isoform sequence.
*/
private void checkFeatureChangingAminoAcids(SequenceFeature sequenceFeature) throws FeatureQueryException {
SequenceVariation variation = sequenceFeature.getProteinVariation();
Isoform isoform = sequenceFeature.getIsoform(entry);
// do check only position for STOP code
if (sequenceFeature.getProteinVariation().getVaryingSequence().getFirstAminoAcid() == AminoAcidCode.STOP) {
checkIsoformPos(isoform, variation.getVaryingSequence().getFirstAminoAcidPos()-1, query, false);
}
else {
checkIsoformPosAndAminoAcids(isoform, variation.getVaryingSequence().getFirstAminoAcidPos(), variation.getVaryingSequence().getFirstAminoAcid().get1LetterCode(), query);
}
if (sequenceFeature.getProteinVariation().getVaryingSequence().getLastAminoAcid() == AminoAcidCode.STOP) {
checkIsoformPos(isoform, variation.getVaryingSequence().getLastAminoAcidPos()-1, query, false);
}
else {
checkIsoformPosAndAminoAcids(isoform, variation.getVaryingSequence().getLastAminoAcidPos(), variation.getVaryingSequence().getLastAminoAcid().get1LetterCode(), query);
}
}
/**
* Check that the given amino-acid(s) exist(s) at the given position of given isoform sequence
* @throws FeatureQueryException if invalid
*/
private void checkIsoformPosAndAminoAcids(Isoform isoform, int position, String aas, SingleFeatureQuery query) throws FeatureQueryException {
boolean insertionMode = (aas == null || aas.isEmpty());
checkIsoformPos(isoform, position, query, insertionMode);
if (!insertionMode && !IsoformSequencePositionMapper.checkAminoAcidsFromPosition(isoform, position, aas)) {
String aasOnSequence = isoform.getSequence().substring(position - 1, position + aas.length() - 1);
throw new UnexpectedFeatureQueryAminoAcidException(query, position,
AminoAcidCode.valueOfAminoAcidCodeSequence(aasOnSequence),
AminoAcidCode.valueOfAminoAcidCodeSequence(aas));
}
}
private void checkIsoformPos(Isoform isoform, int position, SingleFeatureQuery query, boolean insertionMode) throws FeatureQueryException {
boolean valid = IsoformSequencePositionMapper.checkSequencePosition(isoform, position, insertionMode);
if (!valid) {
throw new OutOfBoundSequencePositionException(query, position);
}
}
}