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