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