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