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