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