/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Jalview 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.datamodel;
import java.util.ArrayList;
import java.util.List;
import jalview.util.MapList;
import jalview.util.MappingUtils;
/**
* Stores mapping between the columns of a protein alignment and a DNA alignment
* and a list of individual codon to amino acid mappings between sequences.
*/
public class AlignedCodonFrame
{
/**
* tied array of na Sequence objects.
*/
private SequenceI[] dnaSeqs = null;
/**
* tied array of Mappings to protein sequence Objects and SequenceI[]
* aaSeqs=null; MapLists where each maps from the corresponding dnaSeqs
* element to corresponding aaSeqs element
*/
private Mapping[] dnaToProt = null;
/**
* Constructor
*/
public AlignedCodonFrame()
{
}
/**
* Adds a mapping between the dataset sequences for the associated dna and
* protein sequence objects
*
* @param dnaseq
* @param aaseq
* @param map
*/
public void addMap(SequenceI dnaseq, SequenceI aaseq, MapList map)
{
int nlen = 1;
if (dnaSeqs != null)
{
nlen = dnaSeqs.length + 1;
}
SequenceI[] ndna = new SequenceI[nlen];
Mapping[] ndtp = new Mapping[nlen];
if (dnaSeqs != null)
{
System.arraycopy(dnaSeqs, 0, ndna, 0, dnaSeqs.length);
System.arraycopy(dnaToProt, 0, ndtp, 0, dnaSeqs.length);
}
dnaSeqs = ndna;
dnaToProt = ndtp;
nlen--;
dnaSeqs[nlen] = (dnaseq.getDatasetSequence() == null) ? dnaseq : dnaseq
.getDatasetSequence();
Mapping mp = new Mapping(map);
// JBPNote DEBUG! THIS !
// dnaseq.transferAnnotation(aaseq, mp);
// aaseq.transferAnnotation(dnaseq, new Mapping(map.getInverse()));
mp.to = (aaseq.getDatasetSequence() == null) ? aaseq : aaseq
.getDatasetSequence();
dnaToProt[nlen] = mp;
}
public SequenceI[] getdnaSeqs()
{
return dnaSeqs;
}
public SequenceI[] getAaSeqs()
{
if (dnaToProt == null)
{
return null;
}
SequenceI[] sqs = new SequenceI[dnaToProt.length];
for (int sz = 0; sz < dnaToProt.length; sz++)
{
sqs[sz] = dnaToProt[sz].to;
}
return sqs;
}
public MapList[] getdnaToProt()
{
if (dnaToProt == null)
{
return null;
}
MapList[] sqs = new MapList[dnaToProt.length];
for (int sz = 0; sz < dnaToProt.length; sz++)
{
sqs[sz] = dnaToProt[sz].map;
}
return sqs;
}
public Mapping[] getProtMappings()
{
return dnaToProt;
}
/**
* Returns the first mapping found which is to or from the given sequence, or
* null.
*
* @param seq
* @return
*/
public Mapping getMappingForSequence(SequenceI seq)
{
if (dnaSeqs == null)
{
return null;
}
SequenceI seqDs = seq.getDatasetSequence();
seqDs = seqDs != null ? seqDs : seq;
for (int ds = 0; ds < dnaSeqs.length; ds++)
{
if (dnaSeqs[ds] == seqDs || dnaToProt[ds].to == seqDs)
{
return dnaToProt[ds];
}
}
return null;
}
/**
* Return the corresponding aligned or dataset aa sequence for given dna
* sequence, null if not found.
*
* @param sequenceRef
* @return
*/
public SequenceI getAaForDnaSeq(SequenceI dnaSeqRef)
{
if (dnaSeqs == null)
{
return null;
}
SequenceI dnads = dnaSeqRef.getDatasetSequence();
for (int ds = 0; ds < dnaSeqs.length; ds++)
{
if (dnaSeqs[ds] == dnaSeqRef || dnaSeqs[ds] == dnads)
{
return dnaToProt[ds].to;
}
}
return null;
}
/**
*
* @param sequenceRef
* @return null or corresponding aaSeq entry for dnaSeq entry
*/
public SequenceI getDnaForAaSeq(SequenceI aaSeqRef)
{
if (dnaToProt == null)
{
return null;
}
SequenceI aads = aaSeqRef.getDatasetSequence();
for (int as = 0; as < dnaToProt.length; as++)
{
if (dnaToProt[as].to == aaSeqRef || dnaToProt[as].to == aads)
{
return dnaSeqs[as];
}
}
return null;
}
/**
* test to see if codon frame involves seq in any way
*
* @param seq
* a nucleotide or protein sequence
* @return true if a mapping exists to or from this sequence to any translated
* sequence
*/
public boolean involvesSequence(SequenceI seq)
{
return getAaForDnaSeq(seq) != null || getDnaForAaSeq(seq) != null;
}
/**
* Add search results for regions in other sequences that translate or are
* translated from a particular position in seq
*
* @param seq
* @param index
* position in seq
* @param results
* where highlighted regions go
*/
public void markMappedRegion(SequenceI seq, int index,
SearchResults results)
{
if (dnaToProt == null)
{
return;
}
int[] codon;
SequenceI ds = seq.getDatasetSequence();
for (int mi = 0; mi < dnaToProt.length; mi++)
{
if (dnaSeqs[mi] == seq || dnaSeqs[mi] == ds)
{
// DEBUG System.err.println("dna pos "+index);
codon = dnaToProt[mi].map.locateInTo(index, index);
if (codon != null)
{
for (int i = 0; i < codon.length; i += 2)
{
results.addResult(dnaToProt[mi].to, codon[i], codon[i + 1]);
}
}
}
else if (dnaToProt[mi].to == seq || dnaToProt[mi].to == ds)
{
// DEBUG System.err.println("aa pos "+index);
{
codon = dnaToProt[mi].map.locateInFrom(index, index);
if (codon != null)
{
for (int i = 0; i < codon.length; i += 2)
{
results.addResult(dnaSeqs[mi], codon[i], codon[i + 1]);
}
}
}
}
}
}
/**
* Returns the DNA codon positions (base 1) for the given position (base 1) in
* a mapped protein sequence, or null if no mapping is found.
*
* Intended for use in aligning cDNA to match aligned protein. Only the first
* mapping found is returned, so not suitable for use if multiple protein
* sequences are mapped to the same cDNA (but aligning cDNA as protein is
* ill-defined for this case anyway).
*
* @param seq
* the DNA dataset sequence
* @param aaPos
* residue position (base 1) in a protein sequence
* @return
*/
public int[] getDnaPosition(SequenceI seq, int aaPos)
{
/*
* Adapted from markMappedRegion().
*/
MapList ml = null;
for (int i = 0; i < dnaToProt.length; i++)
{
if (dnaSeqs[i] == seq)
{
ml = getdnaToProt()[i];
break;
}
}
return ml == null ? null : ml.locateInFrom(aaPos, aaPos);
}
/**
* Convenience method to return the first aligned sequence in the given
* alignment whose dataset has a mapping with the given dataset sequence.
*
* @param seq
*
* @param al
* @return
*/
public SequenceI findAlignedSequence(SequenceI seq, AlignmentI al)
{
/*
* Search mapped protein ('to') sequences first.
*/
if (this.dnaToProt != null)
{
for (int i = 0; i < dnaToProt.length; i++)
{
if (this.dnaSeqs[i] == seq)
{
for (SequenceI sourceAligned : al.getSequences())
{
if (this.dnaToProt[i].to == sourceAligned.getDatasetSequence())
{
return sourceAligned;
}
}
}
}
}
/*
* Then try mapped dna sequences.
*/
if (this.dnaToProt != null)
{
for (int i = 0; i < dnaToProt.length; i++)
{
if (this.dnaToProt[i].to == seq)
{
for (SequenceI sourceAligned : al.getSequences())
{
if (this.dnaSeqs[i] == sourceAligned.getDatasetSequence())
{
return sourceAligned;
}
}
}
}
}
return null;
}
/**
* Returns the region in the 'mappedFrom' sequence's dataset that is mapped to
* position 'pos' (base 1) in the 'mappedTo' sequence's dataset. The region is
* a set of start/end position pairs.
*
* @param mappedFrom
* @param mappedTo
* @param pos
* @return
*/
public int[] getMappedRegion(SequenceI mappedFrom, SequenceI mappedTo,
int pos)
{
SequenceI targetDs = mappedFrom.getDatasetSequence() == null ? mappedFrom
: mappedFrom.getDatasetSequence();
SequenceI sourceDs = mappedTo.getDatasetSequence() == null ? mappedTo
: mappedTo.getDatasetSequence();
if (targetDs == null || sourceDs == null || dnaToProt == null)
{
return null;
}
for (int mi = 0; mi < dnaToProt.length; mi++)
{
if (dnaSeqs[mi] == targetDs && dnaToProt[mi].to == sourceDs)
{
int[] codon = dnaToProt[mi].map.locateInFrom(pos, pos);
if (codon != null) {
return codon;
}
}
}
return null;
}
/**
* Returns the DNA codon for the given position (base 1) in a mapped protein
* sequence, or null if no mapping is found.
*
* @param protein
* the peptide dataset sequence
* @param aaPos
* residue position (base 1) in the peptide sequence
* @return
*/
public char[] getMappedCodon(SequenceI protein, int aaPos)
{
if (dnaToProt == null)
{
return null;
}
MapList ml = null;
char[] dnaSeq = null;
for (int i = 0; i < dnaToProt.length; i++)
{
if (dnaToProt[i].to == protein)
{
ml = getdnaToProt()[i];
dnaSeq = dnaSeqs[i].getSequence();
break;
}
}
if (ml == null)
{
return null;
}
int[] codonPos = ml.locateInFrom(aaPos, aaPos);
if (codonPos == null)
{
return null;
}
/*
* Read off the mapped nucleotides (converting to position base 0)
*/
codonPos = MappingUtils.flattenRanges(codonPos);
return new char[]
{ dnaSeq[codonPos[0] - 1], dnaSeq[codonPos[1] - 1],
dnaSeq[codonPos[2] - 1] };
}
/**
* Returns any mappings found which are to (or from) the given sequence, and
* to distinct sequences.
*
* @param seq
* @return
*/
public List getMappingsForSequence(SequenceI seq)
{
List result = new ArrayList();
if (dnaSeqs == null)
{
return result;
}
List related = new ArrayList();
SequenceI seqDs = seq.getDatasetSequence();
seqDs = seqDs != null ? seqDs : seq;
for (int ds = 0; ds < dnaSeqs.length; ds++)
{
final Mapping mapping = dnaToProt[ds];
if (dnaSeqs[ds] == seqDs || mapping.to == seqDs)
{
if (!related.contains(mapping.to))
{
result.add(mapping);
related.add(mapping.to);
}
}
}
return result;
}
}