package org.nextprot.api.commons.bio.variation.prot.impl;
import com.google.common.base.Preconditions;
import org.nextprot.api.commons.bio.AminoAcidCode;
import org.nextprot.api.commons.bio.variation.prot.SequenceVariation;
import org.nextprot.api.commons.bio.variation.prot.SequenceVariationBuilder;
import org.nextprot.api.commons.bio.variation.prot.impl.seqchange.*;
import org.nextprot.api.commons.bio.variation.prot.impl.varseq.VaryingSequenceImpl;
import org.nextprot.api.commons.bio.variation.prot.seqchange.SequenceChange;
import org.nextprot.api.commons.bio.variation.prot.varseq.VaryingSequence;
import java.util.Objects;
/**
* This object describes protein sequence variations of many types (substitution, deletion, delins, frameshift, ...)
* Its instanciation is based on a fluent interface.
*
* See specifications at http://varnomen.hgvs.org/recommendations/protein/
*
* Created by fnikitin on 09/07/15.
*/
public class SequenceVariationImpl implements SequenceVariation {
private final VaryingSequence varyingSequence;
private final SequenceChange sequenceChange;
private SequenceVariationImpl(SequenceVariationBuilder builder) {
varyingSequence = new VaryingSequenceImpl(builder.getDataCollector().getFirstChangingAminoAcid(),
builder.getDataCollector().getFirstChangingAminoAcidPos(),
builder.getDataCollector().getLastChangingAminoAcid(),
builder.getDataCollector().getLastChangingAminoAcidPos());
sequenceChange = builder.getDataCollector().getSequenceChange();
}
@Override
public VaryingSequence getVaryingSequence() {
return varyingSequence;
}
public SequenceChange getSequenceChange() {
return sequenceChange;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SequenceVariationImpl)) return false;
SequenceVariationImpl that = (SequenceVariationImpl) o;
return Objects.equals(varyingSequence, that.varyingSequence) &&
Objects.equals(sequenceChange, that.sequenceChange);
}
@Override
public int hashCode() {
return Objects.hash(varyingSequence, sequenceChange);
}
@Override
public String toString() {
return "SequenceVariationImpl{" +
"changingSequence=" + varyingSequence +
", sequenceChange=" + sequenceChange +
'}';
}
public static class FluentBuilding implements SequenceVariationBuilder.FluentBuilding {
private final SequenceVariationBuilder.DataCollector dataCollector;
public FluentBuilding() {
dataCollector = new SequenceVariationBuilder.DataCollector();
}
@Override
public SequenceVariationBuilder.ChangingAminoAcid selectAminoAcid(AminoAcidCode firstAffectedAminoAcid, int firstAffectedAminoAcidPos) {
dataCollector.setFirstChangingAminoAcid(firstAffectedAminoAcid, firstAffectedAminoAcidPos);
dataCollector.setLastChangingAminoAcid(firstAffectedAminoAcid, firstAffectedAminoAcidPos);
return new AAMutationActionImpl();
}
@Override
public SequenceVariationBuilder.ChangingAminoAcidRange selectAminoAcidRange(AminoAcidCode firstAffectedAminoAcid, int firstAffectedAminoAcidPos, AminoAcidCode lastAffectedAminoAcid, int lastAffectedAminoAcidPos) {
Preconditions.checkArgument(firstAffectedAminoAcidPos < lastAffectedAminoAcidPos);
dataCollector.setFirstChangingAminoAcid(firstAffectedAminoAcid, firstAffectedAminoAcidPos);
dataCollector.setLastChangingAminoAcid(lastAffectedAminoAcid, lastAffectedAminoAcidPos);
return new AAMutationActionImpl();
}
class MutationActionImpl implements SequenceVariationBuilder.ChangingAminoAcidRange {
@Override
public SequenceVariationBuilder thenDelete() {
return new DeletionBuilder(dataCollector);
}
@Override
public SequenceVariationBuilder thenInsert(AminoAcidCode... aas) {
return new InsertionBuilder(dataCollector, aas);
}
@Override
public SequenceVariationBuilder thenDuplicate() {
return new DuplicationBuilder(dataCollector);
}
@Override
public SequenceVariationBuilder thenDeleteAndInsert(AminoAcidCode... aas) {
return new DeletionInsertionBuilder(dataCollector, aas);
}
}
class AAMutationActionImpl extends MutationActionImpl implements SequenceVariationBuilder.ChangingAminoAcid {
@Override
public SequenceVariationBuilder thenSubstituteWith(AminoAcidCode aa) {
return new SubstitutionBuilder(dataCollector, aa);
}
@Override
public SequenceVariationBuilder thenFrameshift(AminoAcidCode newAminoAcidCode, int newTerminationPosition) {
return new FrameshiftBuilder(dataCollector, newAminoAcidCode, newTerminationPosition);
}
@Override
public SequenceVariationBuilder thenAddModification(AminoAcidModification mod) {
return new AminoAcidModificationBuilder(dataCollector, mod);
}
@Override
public SequenceVariationBuilder thenInitiationExtension(int newUpstreamInitPos, AminoAcidCode newAminoAcidCode) {
return new InitiationExtensionBuilder(dataCollector, newUpstreamInitPos, newAminoAcidCode);
}
@Override
public SequenceVariationBuilder thenTerminationExtension(int newDownstreamTermPos, AminoAcidCode newAminoAcidCode) {
return new TerminationExtensionBuilder(dataCollector, newDownstreamTermPos, newAminoAcidCode);
}
}
abstract class SequenceVariationBuilderImpl implements SequenceVariationBuilder {
private final DataCollector dataCollector;
SequenceVariationBuilderImpl(DataCollector dataCollector) {
this.dataCollector = dataCollector;
}
protected abstract SequenceChange getProteinSequenceChange();
@Override
public DataCollector getDataCollector() {
return dataCollector;
}
@Override
public SequenceVariation build() {
dataCollector.setSequenceChange(getProteinSequenceChange());
return new SequenceVariationImpl(this);
}
}
class DeletionBuilder extends SequenceVariationBuilderImpl {
DeletionBuilder(DataCollector dataCollector) {
super(dataCollector);
}
@Override
protected SequenceChange getProteinSequenceChange() {
return new Deletion();
}
}
class InsertionBuilder extends SequenceVariationBuilderImpl {
private final AminoAcidCode[] insertedAas;
InsertionBuilder(DataCollector dataCollector, AminoAcidCode... insertedAas) {
super(dataCollector);
this.insertedAas = insertedAas;
}
@Override
protected SequenceChange getProteinSequenceChange() {
return new Insertion(dataCollector.getFirstChangingAminoAcidPos(), insertedAas);
}
AminoAcidCode[] getInsertedAas() {
return insertedAas;
}
}
class DeletionInsertionBuilder extends InsertionBuilder {
DeletionInsertionBuilder(DataCollector dataCollector, AminoAcidCode... aas) {
super(dataCollector, aas);
}
@Override
protected SequenceChange getProteinSequenceChange() {
return new DeletionAndInsertion(getInsertedAas());
}
}
class DuplicationBuilder extends SequenceVariationBuilderImpl {
DuplicationBuilder(DataCollector dataCollector) {
super(dataCollector);
}
@Override
protected SequenceChange getProteinSequenceChange() {
return new Duplication(dataCollector.getLastChangingAminoAcidPos());
}
}
class SubstitutionBuilder extends SequenceVariationBuilderImpl {
private final AminoAcidCode substitutedAminoAcid;
SubstitutionBuilder(DataCollector dataCollector, AminoAcidCode substitutedAminoAcid) {
super(dataCollector);
this.substitutedAminoAcid = substitutedAminoAcid;
}
@Override
protected SequenceChange getProteinSequenceChange() {
return new Substitution(substitutedAminoAcid);
}
}
class FrameshiftBuilder extends SequenceVariationBuilderImpl {
private final AminoAcidCode newAminoAcidCode;
private final int newTerminationPosition;
FrameshiftBuilder(DataCollector dataCollector, AminoAcidCode newAminoAcidCode, int newTerminationPosition) {
super(dataCollector);
this.newAminoAcidCode = newAminoAcidCode;
this.newTerminationPosition = newTerminationPosition;
}
@Override
protected SequenceChange getProteinSequenceChange() {
return new Frameshift(new Frameshift.Change(newAminoAcidCode, newTerminationPosition));
}
}
class AminoAcidModificationBuilder extends SequenceVariationBuilderImpl {
private final AminoAcidModification mod;
AminoAcidModificationBuilder(DataCollector dataCollector, AminoAcidModification mod) {
super(dataCollector);
this.mod = mod;
}
@Override
protected SequenceChange getProteinSequenceChange() {
return mod;
}
}
class InitiationExtensionBuilder extends SequenceVariationBuilderImpl {
private final ExtensionInitiation extension;
InitiationExtensionBuilder(DataCollector dataCollector, int newUpstreamSitePos, AminoAcidCode newAminoAcidCode) {
super(dataCollector);
this.extension = new ExtensionInitiation(newUpstreamSitePos, newAminoAcidCode);
}
@Override
protected SequenceChange getProteinSequenceChange() {
return extension;
}
}
class TerminationExtensionBuilder extends SequenceVariationBuilderImpl {
private final ExtensionTermination extension;
TerminationExtensionBuilder(DataCollector dataCollector, int newDownstreamTermPos, AminoAcidCode newAminoAcidCode) {
super(dataCollector);
if (dataCollector.getFirstChangingAminoAcid() != AminoAcidCode.STOP) {
throw new IllegalStateException("Invalid termination extension: first amino-acid should be a STOP but is a " + dataCollector.getFirstChangingAminoAcid());
}
this.extension = new ExtensionTermination(newDownstreamTermPos, newAminoAcidCode);
}
@Override
protected SequenceChange getProteinSequenceChange() {
return extension;
}
}
}
}