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