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