Merge branch 'releases/Release_2_11_4_Branch'
[jalview.git] / datamodel / AlignedCodonFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.datamodel;
22
23 import java.util.Enumeration;
24 import java.util.Vector;
25
26 import jalview.util.MapList;
27
28 /**
29  * Stores mapping between the columns of a protein alignment and a DNA alignment
30  * and a list of individual codon to amino acid mappings between sequences.
31  */
32
33 public class AlignedCodonFrame
34 {
35   /**
36    * array of nucleotide positions for aligned codons at column of aligned
37    * proteins.
38    */
39   public int[][] codons = null;
40
41   /**
42    * width of protein sequence alignement implicit assertion that codons.length
43    * >= aaWidth
44    */
45   public int aaWidth = 0;
46
47   /**
48    * initialise codon frame with a nominal alignment width
49    * 
50    * @param aWidth
51    */
52   public AlignedCodonFrame(int aWidth)
53   {
54     if (aWidth <= 0)
55     {
56       codons = null;
57       return;
58     }
59     codons = new int[aWidth][];
60     for (int res = 0; res < aWidth; res++)
61       codons[res] = null;
62   }
63
64   /**
65    * ensure that codons array is at least as wide as aslen residues
66    * 
67    * @param aslen
68    * @return (possibly newly expanded) codon array
69    */
70   public int[][] checkCodonFrameWidth(int aslen)
71   {
72     if (codons.length <= aslen + 1)
73     {
74       // probably never have to do this ?
75       int[][] c = new int[codons.length + 10][];
76       for (int i = 0; i < codons.length; i++)
77       {
78         c[i] = codons[i];
79         codons[i] = null;
80       }
81       codons = c;
82     }
83     return codons;
84   }
85
86   /**
87    * @return width of aligned translated amino acid residues
88    */
89   public int getaaWidth()
90   {
91     return aaWidth;
92   }
93
94   /**
95    * TODO: not an ideal solution - we reference the aligned amino acid sequences
96    * in order to make insertions on them Better would be dnaAlignment and
97    * aaAlignment reference....
98    */
99   Vector a_aaSeqs = new Vector();
100
101   /**
102    * increase aaWidth by one and insert a new aligned codon position space at
103    * aspos.
104    * 
105    * @param aspos
106    */
107   public void insertAAGap(int aspos, char gapCharacter)
108   {
109     // this aa appears before the aligned codons at aspos - so shift them in
110     // each pair of mapped sequences
111     aaWidth++;
112     if (a_aaSeqs != null)
113     {
114       // we actually have to modify the aligned sequences here, so use the
115       // a_aaSeqs vector
116       Enumeration sq = a_aaSeqs.elements();
117       while (sq.hasMoreElements())
118       {
119         ((SequenceI) sq.nextElement()).insertCharAt(aspos, gapCharacter);
120       }
121     }
122     checkCodonFrameWidth(aspos);
123     if (aspos < aaWidth)
124     {
125       aaWidth++;
126       System.arraycopy(codons, aspos, codons, aspos + 1, codons.length
127               - aspos - 1);
128       codons[aspos] = null; // clear so new codon position can be marked.
129     }
130   }
131
132   public void setAaWidth(int aapos)
133   {
134     aaWidth = aapos;
135   }
136
137   /**
138    * tied array of na Sequence objects.
139    */
140   SequenceI[] dnaSeqs = null;
141
142   /**
143    * tied array of Mappings to protein sequence Objects and SequenceI[]
144    * aaSeqs=null; MapLists where eac maps from the corresponding dnaSeqs element
145    * to corresponding aaSeqs element
146    */
147   Mapping[] dnaToProt = null;
148
149   /**
150    * add a mapping between the dataset sequences for the associated dna and
151    * protein sequence objects
152    * 
153    * @param dnaseq
154    * @param aaseq
155    * @param map
156    */
157   public void addMap(SequenceI dnaseq, SequenceI aaseq, MapList map)
158   {
159     int nlen = 1;
160     if (dnaSeqs != null)
161     {
162       nlen = dnaSeqs.length + 1;
163     }
164     SequenceI[] ndna = new SequenceI[nlen];
165     Mapping[] ndtp = new Mapping[nlen];
166     if (dnaSeqs != null)
167     {
168       System.arraycopy(dnaSeqs, 0, ndna, 0, dnaSeqs.length);
169       System.arraycopy(dnaToProt, 0, ndtp, 0, dnaSeqs.length);
170     }
171     dnaSeqs = ndna;
172     dnaToProt = ndtp;
173     nlen--;
174     dnaSeqs[nlen] = (dnaseq.getDatasetSequence() == null) ? dnaseq : dnaseq
175             .getDatasetSequence();
176     Mapping mp = new Mapping(map);
177     // JBPNote DEBUG! THIS !
178     // dnaseq.transferAnnotation(aaseq, mp);
179     // aaseq.transferAnnotation(dnaseq, new Mapping(map.getInverse()));
180     mp.to = (aaseq.getDatasetSequence() == null) ? aaseq : aaseq
181             .getDatasetSequence();
182     a_aaSeqs.addElement(aaseq);
183     dnaToProt[nlen] = mp;
184   }
185
186   public SequenceI[] getdnaSeqs()
187   {
188     return dnaSeqs;
189   }
190
191   public SequenceI[] getAaSeqs()
192   {
193     if (dnaToProt == null)
194       return null;
195     SequenceI[] sqs = new SequenceI[dnaToProt.length];
196     for (int sz = 0; sz < dnaToProt.length; sz++)
197     {
198       sqs[sz] = dnaToProt[sz].to;
199     }
200     return sqs;
201   }
202
203   public MapList[] getdnaToProt()
204   {
205     if (dnaToProt == null)
206       return null;
207     MapList[] sqs = new MapList[dnaToProt.length];
208     for (int sz = 0; sz < dnaToProt.length; sz++)
209     {
210       sqs[sz] = dnaToProt[sz].map;
211     }
212     return sqs;
213   }
214
215   public Mapping[] getProtMappings()
216   {
217     return dnaToProt;
218   }
219
220   /**
221    * 
222    * @param sequenceRef
223    * @return null or corresponding aaSeq entry for dnaSeq entry
224    */
225   public SequenceI getAaForDnaSeq(SequenceI dnaSeqRef)
226   {
227     if (dnaSeqs == null)
228     {
229       return null;
230     }
231     SequenceI dnads = dnaSeqRef.getDatasetSequence();
232     for (int ds = 0; ds < dnaSeqs.length; ds++)
233     {
234       if (dnaSeqs[ds] == dnaSeqRef || dnaSeqs[ds] == dnads)
235         return dnaToProt[ds].to;
236     }
237     return null;
238   }
239
240   /**
241    * 
242    * @param sequenceRef
243    * @return null or corresponding aaSeq entry for dnaSeq entry
244    */
245   public SequenceI getDnaForAaSeq(SequenceI aaSeqRef)
246   {
247     if (dnaToProt == null)
248     {
249       return null;
250     }
251     SequenceI aads = aaSeqRef.getDatasetSequence();
252     for (int as = 0; as < dnaToProt.length; as++)
253     {
254       if (dnaToProt[as].to == aaSeqRef || dnaToProt[as].to == aads)
255         return dnaSeqs[as];
256     }
257     return null;
258   }
259
260   /**
261    * test to see if codon frame involves seq in any way
262    * 
263    * @param seq
264    *          a nucleotide or protein sequence
265    * @return true if a mapping exists to or from this sequence to any translated
266    *         sequence
267    */
268   public boolean involvesSequence(SequenceI seq)
269   {
270     return getAaForDnaSeq(seq) != null || getDnaForAaSeq(seq) != null;
271   }
272
273   /**
274    * Add search results for regions in other sequences that translate or are
275    * translated from a particular position in seq
276    * 
277    * @param seq
278    * @param index
279    *          position in seq
280    * @param results
281    *          where highlighted regions go
282    */
283   public void markMappedRegion(SequenceI seq, int index,
284           SearchResults results)
285   {
286     if (dnaToProt == null)
287     {
288       return;
289     }
290     int[] codon;
291     SequenceI ds = seq.getDatasetSequence();
292     for (int mi = 0; mi < dnaToProt.length; mi++)
293     {
294       if (dnaSeqs[mi] == seq || dnaSeqs[mi] == ds)
295       {
296         // DEBUG System.err.println("dna pos "+index);
297         codon = dnaToProt[mi].map.locateInTo(index, index);
298         if (codon != null)
299         {
300           for (int i = 0; i < codon.length; i += 2)
301           {
302             results.addResult(dnaToProt[mi].to, codon[i], codon[i + 1]);
303           }
304         }
305       }
306       else if (dnaToProt[mi].to == seq || dnaToProt[mi].to == ds)
307       {
308         // DEBUG System.err.println("aa pos "+index);
309         {
310           codon = dnaToProt[mi].map.locateInFrom(index, index);
311           if (codon != null)
312           {
313             for (int i = 0; i < codon.length; i += 2)
314             {
315               results.addResult(dnaSeqs[mi], codon[i], codon[i + 1]);
316             }
317           }
318         }
319       }
320     }
321   }
322 }