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