take the average of the three consecutive codon sites when translating annotation...
[jalview.git] / src / jalview / analysis / Dna.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)\r
3  * Copyright (C) 2009 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.analysis;\r
20 \r
21 import java.util.Enumeration;\r
22 import java.util.Hashtable;\r
23 import java.util.Vector;\r
24 \r
25 import jalview.datamodel.AlignedCodonFrame;\r
26 import jalview.datamodel.Alignment;\r
27 import jalview.datamodel.AlignmentAnnotation;\r
28 import jalview.datamodel.AlignmentI;\r
29 import jalview.datamodel.Annotation;\r
30 import jalview.datamodel.ColumnSelection;\r
31 import jalview.datamodel.DBRefEntry;\r
32 import jalview.datamodel.FeatureProperties;\r
33 import jalview.datamodel.Mapping;\r
34 import jalview.datamodel.Sequence;\r
35 import jalview.datamodel.SequenceFeature;\r
36 import jalview.datamodel.SequenceI;\r
37 import jalview.schemes.ResidueProperties;\r
38 import jalview.util.MapList;\r
39 import jalview.util.ShiftList;\r
40 \r
41 public class Dna\r
42 {\r
43   /**\r
44    * \r
45    * @param cdp1\r
46    * @param cdp2\r
47    * @return -1 if cdp1 aligns before cdp2, 0 if in the same column or cdp2 is\r
48    *         null, +1 if after cdp2\r
49    */\r
50   private static int compare_codonpos(int[] cdp1, int[] cdp2)\r
51   {\r
52     if (cdp2 == null\r
53             || (cdp1[0] == cdp2[0] && cdp1[1] == cdp2[1] && cdp1[2] == cdp2[2]))\r
54       return 0;\r
55     if (cdp1[0] < cdp2[0] || cdp1[1] < cdp2[1] || cdp1[2] < cdp2[2])\r
56       return -1; // one base in cdp1 precedes the corresponding base in the\r
57     // other codon\r
58     return 1; // one base in cdp1 appears after the corresponding base in the\r
59     // other codon.\r
60   }\r
61 \r
62   /**\r
63    * DNA->mapped protein sequence alignment translation given set of sequences\r
64    * 1. id distinct coding regions within selected region for each sequence 2.\r
65    * generate peptides based on inframe (or given) translation or (optionally\r
66    * and where specified) out of frame translations (annotated appropriately) 3.\r
67    * align peptides based on codon alignment\r
68    */\r
69   /**\r
70    * id potential products from dna 1. search for distinct products within\r
71    * selected region for each selected sequence 2. group by associated DB type.\r
72    * 3. return as form for input into above function\r
73    */\r
74   /**\r
75    * \r
76    */\r
77   /**\r
78    * create a new alignment of protein sequences by an inframe translation of\r
79    * the provided NA sequences\r
80    * \r
81    * @param selection\r
82    * @param seqstring\r
83    * @param viscontigs\r
84    * @param gapCharacter\r
85    * @param annotations\r
86    * @param aWidth\r
87    * @param dataset\r
88    *                destination dataset for translated sequences and mappings\r
89    * @return\r
90    */\r
91   public static AlignmentI CdnaTranslate(SequenceI[] selection,\r
92           String[] seqstring, int viscontigs[], char gapCharacter,\r
93           AlignmentAnnotation[] annotations, int aWidth, Alignment dataset)\r
94   {\r
95     return CdnaTranslate(selection, seqstring, null, viscontigs,\r
96             gapCharacter, annotations, aWidth, dataset);\r
97   }\r
98 \r
99   /**\r
100    * \r
101    * @param selection\r
102    * @param seqstring\r
103    * @param product -\r
104    *                array of DbRefEntry objects from which exon map in seqstring\r
105    *                is derived\r
106    * @param viscontigs\r
107    * @param gapCharacter\r
108    * @param annotations\r
109    * @param aWidth\r
110    * @param dataset\r
111    * @return\r
112    */\r
113   public static AlignmentI CdnaTranslate(SequenceI[] selection,\r
114           String[] seqstring, DBRefEntry[] product, int viscontigs[],\r
115           char gapCharacter, AlignmentAnnotation[] annotations, int aWidth,\r
116           Alignment dataset)\r
117   {\r
118     AlignedCodonFrame codons = new AlignedCodonFrame(aWidth); // stores hash of\r
119     // subsequent\r
120     // positions for\r
121     // each codon\r
122     // start position\r
123     // in alignment\r
124     int s, sSize = selection.length;\r
125     Vector pepseqs = new Vector();\r
126     for (s = 0; s < sSize; s++)\r
127     {\r
128       SequenceI newseq = translateCodingRegion(selection[s], seqstring[s],\r
129               viscontigs, codons, gapCharacter,\r
130               (product != null) ? product[s] : null); // possibly anonymous\r
131                                                       // product\r
132       if (newseq != null)\r
133       {\r
134         pepseqs.addElement(newseq);\r
135         SequenceI ds = newseq;\r
136         while (ds.getDatasetSequence() != null)\r
137         {\r
138           ds = ds.getDatasetSequence();\r
139         }\r
140         dataset.addSequence(ds);\r
141       }\r
142     }\r
143     if (codons.aaWidth == 0)\r
144       return null;\r
145     SequenceI[] newseqs = new SequenceI[pepseqs.size()];\r
146     pepseqs.copyInto(newseqs);\r
147     AlignmentI al = new Alignment(newseqs);\r
148     al.padGaps(); // ensure we look aligned.\r
149     al.setDataset(dataset);\r
150     translateAlignedAnnotations(annotations, al, codons);\r
151     al.addCodonFrame(codons);\r
152     return al;\r
153   }\r
154 \r
155   /**\r
156    * fake the collection of DbRefs with associated exon mappings to identify if\r
157    * a translation would generate distinct product in the currently selected\r
158    * region.\r
159    * \r
160    * @param selection\r
161    * @param viscontigs\r
162    * @return\r
163    */\r
164   public static boolean canTranslate(SequenceI[] selection,\r
165           int viscontigs[])\r
166   {\r
167     for (int gd = 0; gd < selection.length; gd++)\r
168     {\r
169       SequenceI dna = selection[gd];\r
170       jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils\r
171               .selectRefs(dna.getDBRef(),\r
172                       jalview.datamodel.DBRefSource.DNACODINGDBS);\r
173       if (dnarefs != null)\r
174       {\r
175         // intersect with pep\r
176         // intersect with pep\r
177         Vector mappedrefs = new Vector();\r
178         DBRefEntry[] refs = dna.getDBRef();\r
179         for (int d = 0; d < refs.length; d++)\r
180         {\r
181           if (refs[d].getMap() != null && refs[d].getMap().getMap() != null\r
182                   && refs[d].getMap().getMap().getFromRatio() == 3\r
183                   && refs[d].getMap().getMap().getToRatio() == 1)\r
184           {\r
185             mappedrefs.addElement(refs[d]); // add translated protein maps\r
186           }\r
187         }\r
188         dnarefs = new DBRefEntry[mappedrefs.size()];\r
189         mappedrefs.copyInto(dnarefs);\r
190         for (int d = 0; d < dnarefs.length; d++)\r
191         {\r
192           Mapping mp = dnarefs[d].getMap();\r
193           if (mp != null)\r
194           {\r
195             for (int vc = 0; vc < viscontigs.length; vc += 2)\r
196             {\r
197               int[] mpr = mp.locateMappedRange(viscontigs[vc],\r
198                       viscontigs[vc + 1]);\r
199               if (mpr != null)\r
200               {\r
201                 return true;\r
202               }\r
203             }\r
204           }\r
205         }\r
206       }\r
207     }\r
208     return false;\r
209   }\r
210 \r
211   /**\r
212    * generate a set of translated protein products from annotated sequenceI\r
213    * \r
214    * @param selection\r
215    * @param viscontigs\r
216    * @param gapCharacter\r
217    * @param dataset\r
218    *                destination dataset for translated sequences\r
219    * @param annotations\r
220    * @param aWidth\r
221    * @return\r
222    */\r
223   public static AlignmentI CdnaTranslate(SequenceI[] selection,\r
224           int viscontigs[], char gapCharacter, Alignment dataset)\r
225   {\r
226     int alwidth = 0;\r
227     Vector cdnasqs = new Vector();\r
228     Vector cdnasqi = new Vector();\r
229     Vector cdnaprod = new Vector();\r
230     for (int gd = 0; gd < selection.length; gd++)\r
231     {\r
232       SequenceI dna = selection[gd];\r
233       jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils\r
234               .selectRefs(dna.getDBRef(),\r
235                       jalview.datamodel.DBRefSource.DNACODINGDBS);\r
236       if (dnarefs != null)\r
237       {\r
238         // intersect with pep\r
239         Vector mappedrefs = new Vector();\r
240         DBRefEntry[] refs = dna.getDBRef();\r
241         for (int d = 0; d < refs.length; d++)\r
242         {\r
243           if (refs[d].getMap() != null && refs[d].getMap().getMap() != null\r
244                   && refs[d].getMap().getMap().getFromRatio() == 3\r
245                   && refs[d].getMap().getMap().getToRatio() == 1)\r
246           {\r
247             mappedrefs.addElement(refs[d]); // add translated protein maps\r
248           }\r
249         }\r
250         dnarefs = new DBRefEntry[mappedrefs.size()];\r
251         mappedrefs.copyInto(dnarefs);\r
252         for (int d = 0; d < dnarefs.length; d++)\r
253         {\r
254           Mapping mp = dnarefs[d].getMap();\r
255           StringBuffer sqstr = new StringBuffer();\r
256           if (mp != null)\r
257           {\r
258             Mapping intersect = mp.intersectVisContigs(viscontigs);\r
259             // generate seqstring for this sequence based on mapping\r
260 \r
261             if (sqstr.length() > alwidth)\r
262               alwidth = sqstr.length();\r
263             cdnasqs.addElement(sqstr.toString());\r
264             cdnasqi.addElement(dna);\r
265             cdnaprod.addElement(intersect);\r
266           }\r
267         }\r
268       }\r
269       SequenceI[] cdna = new SequenceI[cdnasqs.size()];\r
270       DBRefEntry[] prods = new DBRefEntry[cdnaprod.size()];\r
271       String[] xons = new String[cdnasqs.size()];\r
272       cdnasqs.copyInto(xons);\r
273       cdnaprod.copyInto(prods);\r
274       cdnasqi.copyInto(cdna);\r
275       return CdnaTranslate(cdna, xons, prods, viscontigs, gapCharacter,\r
276               null, alwidth, dataset);\r
277     }\r
278     return null;\r
279   }\r
280 \r
281   /**\r
282    * translate na alignment annotations onto translated amino acid alignment al\r
283    * using codon mapping codons\r
284    * \r
285    * @param annotations\r
286    * @param al\r
287    * @param codons\r
288    */\r
289   public static void translateAlignedAnnotations(\r
290           AlignmentAnnotation[] annotations, AlignmentI al,\r
291           AlignedCodonFrame codons)\r
292   {\r
293     // //////////////////////////////\r
294     // Copy annotations across\r
295     //\r
296     // Can only do this for columns with consecutive codons, or where\r
297     // annotation is sequence associated.\r
298 \r
299     int pos, a, aSize;\r
300     if (annotations != null)\r
301     {\r
302       for (int i = 0; i < annotations.length; i++)\r
303       {\r
304         // Skip any autogenerated annotation\r
305         if (annotations[i].autoCalculated)\r
306         {\r
307           continue;\r
308         }\r
309 \r
310         aSize = codons.getaaWidth(); // aa alignment width.\r
311         jalview.datamodel.Annotation[] anots = (annotations[i].annotations == null) ? null\r
312                 : new jalview.datamodel.Annotation[aSize];\r
313         if (anots != null)\r
314         {\r
315           for (a = 0; a < aSize; a++)\r
316           {\r
317             // process through codon map.\r
318             if (codons.codons[a] != null\r
319                     && codons.codons[a][0] == (codons.codons[a][2] - 2))\r
320             {\r
321               anots[a] = getCodonAnnotation(codons.codons[a],\r
322                       annotations[i].annotations);\r
323             }\r
324           }\r
325         }\r
326 \r
327         jalview.datamodel.AlignmentAnnotation aa = new jalview.datamodel.AlignmentAnnotation(\r
328                 annotations[i].label, annotations[i].description, anots);\r
329         aa.graph = annotations[i].graph;\r
330         aa.graphGroup = annotations[i].graphGroup;\r
331         aa.graphHeight = annotations[i].graphHeight;\r
332         if (annotations[i].getThreshold() != null)\r
333         {\r
334           aa.setThreshold(new jalview.datamodel.GraphLine(annotations[i]\r
335                   .getThreshold()));\r
336         }\r
337         if (annotations[i].hasScore)\r
338         {\r
339           aa.setScore(annotations[i].getScore());\r
340         }\r
341         if (annotations[i].sequenceRef != null)\r
342         {\r
343           SequenceI aaSeq = codons\r
344                   .getAaForDnaSeq(annotations[i].sequenceRef);\r
345           if (aaSeq != null)\r
346           {\r
347             // aa.compactAnnotationArray(); // throw away alignment annotation\r
348             // positioning\r
349             aa.setSequenceRef(aaSeq);\r
350             aa.createSequenceMapping(aaSeq, aaSeq.getStart(), true); // rebuild\r
351             // mapping\r
352             aa.adjustForAlignment();\r
353             aaSeq.addAlignmentAnnotation(aa);\r
354           }\r
355 \r
356         }\r
357         al.addAnnotation(aa);\r
358       }\r
359     }\r
360   }\r
361 \r
362   private static Annotation getCodonAnnotation(int[] is,\r
363           Annotation[] annotations)\r
364   {\r
365     // Have a look at all the codon positions for annotation and put the first\r
366     // one found into the translated annotation pos.\r
367     int contrib=0;\r
368     Annotation annot = null;\r
369     for (int p = 0; p < 3; p++)\r
370     {\r
371       if (annotations[is[p]] != null)\r
372       {\r
373         if (annot==null) {\r
374           annot = new Annotation(annotations[is[p]]);\r
375           contrib = 1;\r
376         } else {\r
377           // merge with last\r
378           Annotation cpy = new Annotation(annotations[is[p]]);\r
379           if (annot.colour==null)\r
380           {\r
381             annot.colour = cpy.colour;\r
382           }\r
383           if (annot.description==null || annot.description.length()==0)\r
384           {\r
385             annot.description = cpy.description;\r
386           }\r
387           if (annot.displayCharacter==null)\r
388           {\r
389             annot.displayCharacter = cpy.displayCharacter;\r
390           }\r
391           if (annot.secondaryStructure==0)\r
392           {\r
393             annot.secondaryStructure = cpy.secondaryStructure;\r
394           }\r
395           annot.value+=cpy.value;\r
396           contrib++;\r
397         }\r
398       }\r
399     }\r
400     if (contrib>1)\r
401     {\r
402       annot.value/=(float)contrib;\r
403     }\r
404     return annot;\r
405   }\r
406 \r
407   /**\r
408    * Translate a na sequence\r
409    * \r
410    * @param selection\r
411    *                sequence displayed under viscontigs visible columns\r
412    * @param seqstring\r
413    *                ORF read in some global alignment reference frame\r
414    * @param viscontigs\r
415    *                mapping from global reference frame to visible seqstring ORF\r
416    *                read\r
417    * @param codons\r
418    *                Definition of global ORF alignment reference frame\r
419    * @param gapCharacter\r
420    * @param newSeq\r
421    * @return sequence ready to be added to alignment.\r
422    */\r
423   public static SequenceI translateCodingRegion(SequenceI selection,\r
424           String seqstring, int[] viscontigs, AlignedCodonFrame codons,\r
425           char gapCharacter, DBRefEntry product)\r
426   {\r
427     Vector skip = new Vector();\r
428     int skipint[] = null;\r
429     ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring\r
430     // intervals\r
431     int vc, scontigs[] = new int[viscontigs.length];\r
432     int npos = 0;\r
433     for (vc = 0; vc < viscontigs.length; vc += 2)\r
434     {\r
435       if (vc == 0)\r
436       {\r
437         vismapping.addShift(npos, viscontigs[vc]);\r
438       }\r
439       else\r
440       {\r
441         // hidden region\r
442         vismapping.addShift(npos, viscontigs[vc] - viscontigs[vc - 1] + 1);\r
443       }\r
444       scontigs[vc] = viscontigs[vc];\r
445       scontigs[vc + 1] = viscontigs[vc + 1];\r
446     }\r
447 \r
448     StringBuffer protein = new StringBuffer();\r
449     String seq = seqstring.replace('U', 'T');\r
450     char codon[] = new char[3];\r
451     int cdp[] = new int[3], rf = 0, lastnpos = 0, nend;\r
452     int aspos = 0;\r
453     int resSize = 0;\r
454     for (npos = 0, nend = seq.length(); npos < nend; npos++)\r
455     {\r
456       if (!jalview.util.Comparison.isGap(seq.charAt(npos)))\r
457       {\r
458         cdp[rf] = npos; // store position\r
459         codon[rf++] = seq.charAt(npos); // store base\r
460       }\r
461       // filled an RF yet ?\r
462       if (rf == 3)\r
463       {\r
464         String aa = ResidueProperties.codonTranslate(new String(codon));\r
465         rf = 0;\r
466         if (aa == null)\r
467         {\r
468           aa = String.valueOf(gapCharacter);\r
469           if (skipint == null)\r
470           {\r
471             skipint = new int[]\r
472             { cdp[0], cdp[2] };\r
473           }\r
474           skipint[1] = cdp[2];\r
475         }\r
476         else\r
477         {\r
478           if (skipint != null)\r
479           {\r
480             // edit scontigs\r
481             skipint[0] = vismapping.shift(skipint[0]);\r
482             skipint[1] = vismapping.shift(skipint[1]);\r
483             for (vc = 0; vc < scontigs.length; vc += 2)\r
484             {\r
485               if (scontigs[vc + 1] < skipint[0])\r
486               {\r
487                 continue;\r
488               }\r
489               if (scontigs[vc] <= skipint[0])\r
490               {\r
491                 if (skipint[0] == scontigs[vc])\r
492                 {\r
493 \r
494                 }\r
495                 else\r
496                 {\r
497                   int[] t = new int[scontigs.length + 2];\r
498                   System.arraycopy(scontigs, 0, t, 0, vc - 1);\r
499                   // scontigs[vc]; //\r
500                 }\r
501               }\r
502             }\r
503             skip.addElement(skipint);\r
504             skipint = null;\r
505           }\r
506           if (aa.equals("STOP"))\r
507           {\r
508             aa = "X";\r
509           }\r
510           resSize++;\r
511         }\r
512         // insert/delete gaps prior to this codon - if necessary\r
513         boolean findpos = true;\r
514         while (findpos)\r
515         {\r
516           // first ensure that the codons array is long enough.\r
517           codons.checkCodonFrameWidth(aspos);\r
518           // now check to see if we place the aa at the current aspos in the\r
519           // protein alignment\r
520           switch (Dna.compare_codonpos(cdp, codons.codons[aspos]))\r
521           {\r
522           case -1:\r
523             codons.insertAAGap(aspos, gapCharacter);\r
524             findpos = false;\r
525             break;\r
526           case +1:\r
527             // this aa appears after the aligned codons at aspos, so prefix it\r
528             // with a gap\r
529             aa = "" + gapCharacter + aa;\r
530             aspos++;\r
531             // if (aspos >= codons.aaWidth)\r
532             // codons.aaWidth = aspos + 1;\r
533             break; // check the next position for alignment\r
534           case 0:\r
535             // codon aligns at aspos position.\r
536             findpos = false;\r
537           }\r
538         }\r
539         // codon aligns with all other sequence residues found at aspos\r
540         protein.append(aa);\r
541         lastnpos = npos;\r
542         if (codons.codons[aspos] == null)\r
543         {\r
544           // mark this column as aligning to this aligned reading frame\r
545           codons.codons[aspos] = new int[]\r
546           { cdp[0], cdp[1], cdp[2] };\r
547         }\r
548         if (aspos >= codons.aaWidth)\r
549         {\r
550           // update maximum alignment width \r
551           // (we can do this without calling checkCodonFrameWidth because it was already done above)\r
552           codons.setAaWidth(aspos);\r
553         }\r
554         // ready for next translated reading frame alignment position (if any)\r
555         aspos++;\r
556       }\r
557     }\r
558     if (resSize > 0)\r
559     {\r
560       SequenceI newseq = new Sequence(selection.getName(), protein\r
561               .toString());\r
562       if (rf != 0)\r
563       {\r
564         jalview.bin.Cache.log\r
565                 .debug("trimming contigs for incomplete terminal codon.");\r
566         // map and trim contigs to ORF region\r
567         vc = scontigs.length - 1;\r
568         lastnpos = vismapping.shift(lastnpos); // place npos in context of\r
569         // whole dna alignment (rather\r
570         // than visible contigs)\r
571         // incomplete ORF could be broken over one or two visible contig\r
572         // intervals.\r
573         while (vc >= 0 && scontigs[vc] > lastnpos)\r
574         {\r
575           if (vc > 0 && scontigs[vc - 1] > lastnpos)\r
576           {\r
577             vc -= 2;\r
578           }\r
579           else\r
580           {\r
581             // correct last interval in list.\r
582             scontigs[vc] = lastnpos;\r
583           }\r
584         }\r
585 \r
586         if (vc > 0 && (vc + 1) < scontigs.length)\r
587         {\r
588           // truncate map list to just vc elements\r
589           int t[] = new int[vc + 1];\r
590           System.arraycopy(scontigs, 0, t, 0, vc + 1);\r
591           scontigs = t;\r
592         }\r
593         if (vc <= 0)\r
594           scontigs = null;\r
595       }\r
596       if (scontigs != null)\r
597       {\r
598         npos = 0;\r
599         // map scontigs to actual sequence positions on selection\r
600         for (vc = 0; vc < scontigs.length; vc += 2)\r
601         {\r
602           scontigs[vc] = selection.findPosition(scontigs[vc]); // not from 1!\r
603           scontigs[vc + 1] = selection.findPosition(scontigs[vc + 1]); // exclusive\r
604           if (scontigs[vc + 1] == selection.getEnd())\r
605             break;\r
606         }\r
607         // trim trailing empty intervals.\r
608         if ((vc + 2) < scontigs.length)\r
609         {\r
610           int t[] = new int[vc + 2];\r
611           System.arraycopy(scontigs, 0, t, 0, vc + 2);\r
612           scontigs = t;\r
613         }\r
614         /*\r
615          * delete intervals in scontigs which are not translated. 1. map skip\r
616          * into sequence position intervals 2. truncate existing ranges and add\r
617          * new ranges to exclude untranslated regions. if (skip.size()>0) {\r
618          * Vector narange = new Vector(); for (vc=0; vc<scontigs.length; vc++) {\r
619          * narange.addElement(new int[] {scontigs[vc]}); } int sint=0,iv[]; vc =\r
620          * 0; while (sint<skip.size()) { skipint = (int[])\r
621          * skip.elementAt(sint); do { iv = (int[]) narange.elementAt(vc); if\r
622          * (iv[0]>=skipint[0] && iv[0]<=skipint[1]) { if (iv[0]==skipint[0]) { //\r
623          * delete beginning of range } else { // truncate range and create new\r
624          * one if necessary iv = (int[]) narange.elementAt(vc+1); if (iv[0]<=skipint[1]) { //\r
625          * truncate range iv[0] = skipint[1]; } else {\r
626          *  } } } else if (iv[0]<skipint[0]) { iv = (int[])\r
627          * narange.elementAt(vc+1); } } while (iv[0]) } }\r
628          */\r
629         MapList map = new MapList(scontigs, new int[]\r
630         { 1, resSize }, 3, 1);\r
631 \r
632         // update newseq as if it was generated as mapping from product\r
633 \r
634         if (product != null)\r
635         {\r
636           newseq.setName(product.getSource() + "|"\r
637                   + product.getAccessionId());\r
638           if (product.getMap() != null)\r
639           {\r
640             // Mapping mp = product.getMap();\r
641             // newseq.setStart(mp.getPosition(scontigs[0]));\r
642             // newseq.setEnd(mp\r
643             // .getPosition(scontigs[scontigs.length - 1]));\r
644           }\r
645         }\r
646         transferCodedFeatures(selection, newseq, map, null, null);\r
647         SequenceI rseq = newseq.deriveSequence(); // construct a dataset\r
648         // sequence for our new\r
649         // peptide, regardless.\r
650         // store a mapping (this actually stores a mapping between the dataset\r
651         // sequences for the two sequences\r
652         codons.addMap(selection, rseq, map);\r
653         return rseq;\r
654       }\r
655     }\r
656     // register the mapping somehow\r
657     // \r
658     return null;\r
659   }\r
660 \r
661   /**\r
662    * Given a peptide newly translated from a dna sequence, copy over and set any\r
663    * features on the peptide from the DNA. If featureTypes is null, all features\r
664    * on the dna sequence are searched (rather than just the displayed ones), and\r
665    * similarly for featureGroups.\r
666    * \r
667    * @param dna\r
668    * @param pep\r
669    * @param map\r
670    * @param featureTypes\r
671    *                hash who's keys are the displayed feature type strings\r
672    * @param featureGroups\r
673    *                hash where keys are feature groups and values are Boolean\r
674    *                objects indicating if they are displayed.\r
675    */\r
676   private static void transferCodedFeatures(SequenceI dna, SequenceI pep,\r
677           MapList map, Hashtable featureTypes, Hashtable featureGroups)\r
678   {\r
679     SequenceFeature[] sf = dna.getDatasetSequence().getSequenceFeatures();\r
680     Boolean fgstate;\r
681     jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils\r
682             .selectRefs(dna.getDBRef(),\r
683                     jalview.datamodel.DBRefSource.DNACODINGDBS);\r
684     if (dnarefs != null)\r
685     {\r
686       // intersect with pep\r
687       for (int d = 0; d < dnarefs.length; d++)\r
688       {\r
689         Mapping mp = dnarefs[d].getMap();\r
690         if (mp != null)\r
691         {\r
692         }\r
693       }\r
694     }\r
695     if (sf != null)\r
696     {\r
697       for (int f = 0; f < sf.length; f++)\r
698       {\r
699         fgstate = (featureGroups == null) ? null : ((Boolean) featureGroups\r
700                 .get(sf[f].featureGroup));\r
701         if ((featureTypes == null || featureTypes.containsKey(sf[f]\r
702                 .getType()))\r
703                 && (fgstate == null || fgstate.booleanValue()))\r
704         {\r
705           if (FeatureProperties.isCodingFeature(null, sf[f].getType()))\r
706           {\r
707             // if (map.intersectsFrom(sf[f].begin, sf[f].end))\r
708             {\r
709 \r
710             }\r
711           }\r
712         }\r
713       }\r
714     }\r
715   }\r
716 }\r