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