5315d1a2802f91ea0d93ceae9a9e9140b12d031d
[jalview.git] / src / jalview / datamodel / Sequence.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.datamodel;
19
20 import jalview.analysis.AlignSeq;
21
22 import java.util.Enumeration;
23 import java.util.Vector;
24
25 import fr.orsay.lri.varna.models.rna.RNA;
26
27 /**
28  * 
29  * Implements the SequenceI interface for a char[] based sequence object.
30  * 
31  * @author $author$
32  * @version $Revision$
33  */
34 public class Sequence implements SequenceI
35 {
36   SequenceI datasetSequence;
37
38   String name;
39
40   private char[] sequence;
41
42   String description;
43
44   int start;
45
46   int end;
47
48   Vector pdbIds;
49
50   String vamsasId;
51
52   DBRefEntry[] dbrefs;
53   
54   RNA rna;
55
56   /**
57    * This annotation is displayed below the alignment but the positions are tied
58    * to the residues of this sequence
59    */
60   Vector annotation;
61
62   /**
63    * The index of the sequence in a MSA
64    */
65   int index = -1;
66
67   /** array of sequence features - may not be null for a valid sequence object */
68   public SequenceFeature[] sequenceFeatures;
69
70   /**
71    * Creates a new Sequence object.
72    * 
73    * @param name
74    *          display name string
75    * @param sequence
76    *          string to form a possibly gapped sequence out of
77    * @param start
78    *          first position of non-gap residue in the sequence
79    * @param end
80    *          last position of ungapped residues (nearly always only used for
81    *          display purposes)
82    */
83   public Sequence(String name, String sequence, int start, int end)
84   {
85     this.name = name;
86     this.sequence = sequence.toCharArray();
87     this.start = start;
88     this.end = end;
89     parseId();
90     checkValidRange();
91   }
92
93   public Sequence(String name, char[] sequence, int start, int end)
94   {
95     this.name = name;
96     this.sequence = sequence;
97     this.start = start;
98     this.end = end;
99     parseId();
100     checkValidRange();
101   }
102
103   com.stevesoft.pat.Regex limitrx = new com.stevesoft.pat.Regex(
104           "[/][0-9]{1,}[-][0-9]{1,}$");
105
106   com.stevesoft.pat.Regex endrx = new com.stevesoft.pat.Regex("[0-9]{1,}$");
107
108   void parseId()
109   {
110     if (name == null)
111     {
112       System.err
113               .println("POSSIBLE IMPLEMENTATION ERROR: null sequence name passed to constructor.");
114       name = "";
115     }
116     // Does sequence have the /start-end signiature?
117     if (limitrx.search(name))
118     {
119       name = limitrx.left();
120       endrx.search(limitrx.stringMatched());
121       setStart(Integer.parseInt(limitrx.stringMatched().substring(1,
122               endrx.matchedFrom() - 1)));
123       setEnd(Integer.parseInt(endrx.stringMatched()));
124     }
125   }
126
127   void checkValidRange()
128   {
129     // Note: JAL-774 :
130     // http://issues.jalview.org/browse/JAL-774?focusedCommentId=11239&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-11239
131     {
132       int endRes = 0;
133       for (int j = 0; j < sequence.length; j++)
134       {
135         if (!jalview.util.Comparison.isGap(sequence[j]))
136         {
137           endRes++;
138         }
139       }
140       if (endRes > 0)
141       {
142         endRes += start - 1;
143       }
144
145       if (end < endRes)
146       {
147         end = endRes;
148       }
149     }
150
151   }
152
153   /**
154    * Creates a new Sequence object.
155    * 
156    * @param name
157    *          DOCUMENT ME!
158    * @param sequence
159    *          DOCUMENT ME!
160    */
161   public Sequence(String name, String sequence)
162   {
163     this(name, sequence, 1, -1);
164   }
165
166   /**
167    * Creates a new Sequence object with new features, DBRefEntries,
168    * AlignmentAnnotations, and PDBIds but inherits any existing dataset sequence
169    * reference.
170    * 
171    * @param seq
172    *          DOCUMENT ME!
173    */
174   public Sequence(SequenceI seq)
175   {
176     this(seq, seq.getAnnotation());
177   }
178
179   /**
180    * Create a new sequence object with new features, DBRefEntries, and PDBIds
181    * but inherits any existing dataset sequence reference, and duplicate of any
182    * annotation that is present in the given annotation array.
183    * 
184    * @param seq
185    *          the sequence to be copied
186    * @param alAnnotation
187    *          an array of annotation including some associated with seq
188    */
189   public Sequence(SequenceI seq, AlignmentAnnotation[] alAnnotation)
190   {
191     this(seq.getName(), seq.getSequence(), seq.getStart(), seq.getEnd());
192     description = seq.getDescription();
193     if (seq.getSequenceFeatures() != null)
194     {
195       SequenceFeature[] sf = seq.getSequenceFeatures();
196       for (int i = 0; i < sf.length; i++)
197       {
198         addSequenceFeature(new SequenceFeature(sf[i]));
199       }
200     }
201     setDatasetSequence(seq.getDatasetSequence());
202     if (datasetSequence == null && seq.getDBRef() != null)
203     {
204       // only copy DBRefs if we really are a dataset sequence
205       DBRefEntry[] dbr = seq.getDBRef();
206       for (int i = 0; i < dbr.length; i++)
207       {
208         addDBRef(new DBRefEntry(dbr[i]));
209       }
210     }
211     if (seq.getAnnotation() != null)
212     {
213       AlignmentAnnotation[] sqann = seq.getAnnotation();
214       for (int i = 0; i < sqann.length; i++)
215       {
216         if (sqann[i] == null)
217         {
218           continue;
219         }
220         boolean found = (alAnnotation == null);
221         if (!found)
222         {
223           for (int apos = 0; !found && apos < alAnnotation.length; apos++)
224           {
225             found = (alAnnotation[apos] == sqann[i]);
226           }
227         }
228         if (found)
229         {
230           // only copy the given annotation
231           AlignmentAnnotation newann = new AlignmentAnnotation(sqann[i]);
232           addAlignmentAnnotation(newann);
233         }
234       }
235     }
236     if (seq.getPDBId() != null)
237     {
238       Vector ids = seq.getPDBId();
239       Enumeration e = ids.elements();
240       while (e.hasMoreElements())
241       {
242         this.addPDBId(new PDBEntry((PDBEntry) e.nextElement()));
243       }
244     }
245   }
246
247   /**
248    * DOCUMENT ME!
249    * 
250    * @param v
251    *          DOCUMENT ME!
252    */
253   public void setSequenceFeatures(SequenceFeature[] features)
254   {
255     sequenceFeatures = features;
256   }
257
258   public synchronized void addSequenceFeature(SequenceFeature sf)
259   {
260     if (sequenceFeatures == null)
261     {
262       sequenceFeatures = new SequenceFeature[0];
263     }
264
265     for (int i = 0; i < sequenceFeatures.length; i++)
266     {
267       if (sequenceFeatures[i].equals(sf))
268       {
269         return;
270       }
271     }
272
273     SequenceFeature[] temp = new SequenceFeature[sequenceFeatures.length + 1];
274     System.arraycopy(sequenceFeatures, 0, temp, 0, sequenceFeatures.length);
275     temp[sequenceFeatures.length] = sf;
276
277     sequenceFeatures = temp;
278   }
279
280   public void deleteFeature(SequenceFeature sf)
281   {
282     if (sequenceFeatures == null)
283     {
284       return;
285     }
286
287     int index = 0;
288     for (index = 0; index < sequenceFeatures.length; index++)
289     {
290       if (sequenceFeatures[index].equals(sf))
291       {
292         break;
293       }
294     }
295
296     if (index == sequenceFeatures.length)
297     {
298       return;
299     }
300
301     int sfLength = sequenceFeatures.length;
302     if (sfLength < 2)
303     {
304       sequenceFeatures = null;
305     }
306     else
307     {
308       SequenceFeature[] temp = new SequenceFeature[sfLength - 1];
309       System.arraycopy(sequenceFeatures, 0, temp, 0, index);
310
311       if (index < sfLength)
312       {
313         System.arraycopy(sequenceFeatures, index + 1, temp, index,
314                 sequenceFeatures.length - index - 1);
315       }
316
317       sequenceFeatures = temp;
318     }
319   }
320
321   /**
322    * DOCUMENT ME!
323    * 
324    * @return DOCUMENT ME!
325    */
326   public SequenceFeature[] getSequenceFeatures()
327   {
328     return sequenceFeatures;
329   }
330
331   public void addPDBId(PDBEntry entry)
332   {
333     if (pdbIds == null)
334     {
335       pdbIds = new Vector();
336     }
337     if (!pdbIds.contains(entry))
338     {
339       pdbIds.addElement(entry);
340     }
341   }
342
343   /**
344    * DOCUMENT ME!
345    * 
346    * @param id
347    *          DOCUMENT ME!
348    */
349   public void setPDBId(Vector id)
350   {
351     pdbIds = id;
352   }
353
354   /**
355    * DOCUMENT ME!
356    * 
357    * @return DOCUMENT ME!
358    */
359   public Vector getPDBId()
360   {
361     return pdbIds;
362   }
363
364   /**
365    * DOCUMENT ME!
366    * 
367    * @return DOCUMENT ME!
368    */
369   public String getDisplayId(boolean jvsuffix)
370   {
371     StringBuffer result = new StringBuffer(name);
372     if (jvsuffix)
373     {
374       result.append("/" + start + "-" + end);
375     }
376
377     return result.toString();
378   }
379
380   /**
381    * DOCUMENT ME!
382    * 
383    * @param name
384    *          DOCUMENT ME!
385    */
386   public void setName(String name)
387   {
388     this.name = name;
389     this.parseId();
390   }
391
392   /**
393    * DOCUMENT ME!
394    * 
395    * @return DOCUMENT ME!
396    */
397   public String getName()
398   {
399     return this.name;
400   }
401
402   /**
403    * DOCUMENT ME!
404    * 
405    * @param start
406    *          DOCUMENT ME!
407    */
408   public void setStart(int start)
409   {
410     this.start = start;
411   }
412
413   /**
414    * DOCUMENT ME!
415    * 
416    * @return DOCUMENT ME!
417    */
418   public int getStart()
419   {
420     return this.start;
421   }
422
423   /**
424    * DOCUMENT ME!
425    * 
426    * @param end
427    *          DOCUMENT ME!
428    */
429   public void setEnd(int end)
430   {
431     this.end = end;
432   }
433
434   /**
435    * DOCUMENT ME!
436    * 
437    * @return DOCUMENT ME!
438    */
439   public int getEnd()
440   {
441     return this.end;
442   }
443
444   /**
445    * DOCUMENT ME!
446    * 
447    * @return DOCUMENT ME!
448    */
449   public int getLength()
450   {
451     return this.sequence.length;
452   }
453
454   /**
455    * DOCUMENT ME!
456    * 
457    * @param seq
458    *          DOCUMENT ME!
459    */
460   public void setSequence(String seq)
461   {
462     this.sequence = seq.toCharArray();
463     checkValidRange();
464   }
465
466   public String getSequenceAsString()
467   {
468     return new String(sequence);
469   }
470
471   public String getSequenceAsString(int start, int end)
472   {
473     return new String(getSequence(start, end));
474   }
475
476   public char[] getSequence()
477   {
478     return sequence;
479   }
480
481   /*
482    * (non-Javadoc)
483    * 
484    * @see jalview.datamodel.SequenceI#getSequence(int, int)
485    */
486   public char[] getSequence(int start, int end)
487   {
488     if (start < 0)
489       start = 0;
490     // JBPNote - left to user to pad the result here (TODO:Decide on this
491     // policy)
492     if (start >= sequence.length)
493     {
494       return new char[0];
495     }
496
497     if (end >= sequence.length)
498     {
499       end = sequence.length;
500     }
501
502     char[] reply = new char[end - start];
503     System.arraycopy(sequence, start, reply, 0, end - start);
504
505     return reply;
506   }
507
508   /**
509    * make a new Sequence object from start to end (including gaps) over this
510    * seqeunce
511    * 
512    * @param start
513    *          int
514    * @param end
515    *          int
516    * @return SequenceI
517    */
518   public SequenceI getSubSequence(int start, int end)
519   {
520     if (start < 0)
521     {
522       start = 0;
523     }
524     char[] seq = getSequence(start, end);
525     if (seq.length == 0)
526     {
527       return null;
528     }
529     int nstart = findPosition(start);
530     int nend = findPosition(end) - 1;
531     // JBPNote - this is an incomplete copy.
532     SequenceI nseq = new Sequence(this.getName(), seq, nstart, nend);
533     nseq.setDescription(description);
534     if (datasetSequence != null)
535     {
536       nseq.setDatasetSequence(datasetSequence);
537     }
538     else
539     {
540       nseq.setDatasetSequence(this);
541     }
542     return nseq;
543   }
544
545   /**
546    * DOCUMENT ME!
547    * 
548    * @param i
549    *          DOCUMENT ME!
550    * 
551    * @return DOCUMENT ME!
552    */
553   public char getCharAt(int i)
554   {
555     if (i < sequence.length)
556     {
557       return sequence[i];
558     }
559     else
560     {
561       return ' ';
562     }
563   }
564
565   /**
566    * DOCUMENT ME!
567    * 
568    * @param desc
569    *          DOCUMENT ME!
570    */
571   public void setDescription(String desc)
572   {
573     this.description = desc;
574   }
575
576   /**
577    * DOCUMENT ME!
578    * 
579    * @return DOCUMENT ME!
580    */
581   public String getDescription()
582   {
583     return this.description;
584   }
585
586   /*
587    * (non-Javadoc)
588    * 
589    * @see jalview.datamodel.SequenceI#findIndex(int)
590    */
591   public int findIndex(int pos)
592   {
593     // returns the alignment position for a residue
594     int j = start;
595     int i = 0;
596     // Rely on end being at least as long as the length of the sequence.
597     while ((i < sequence.length) && (j <= end) && (j <= pos))
598     {
599       if (!jalview.util.Comparison.isGap(sequence[i]))
600       {
601         j++;
602       }
603
604       i++;
605     }
606
607     if ((j == end) && (j < pos))
608     {
609       return end + 1;
610     }
611     else
612     {
613       return i;
614     }
615   }
616
617   /**
618    * Returns the sequence position for an alignment position
619    * 
620    * @param i
621    *          column index in alignment (from 1)
622    * 
623    * @return residue number for residue (left of and) nearest ith column
624    */
625   public int findPosition(int i)
626   {
627     int j = 0;
628     int pos = start;
629     int seqlen = sequence.length;
630     while ((j < i) && (j < seqlen))
631     {
632       if (!jalview.util.Comparison.isGap(sequence[j]))
633       {
634         pos++;
635       }
636
637       j++;
638     }
639
640     return pos;
641   }
642
643   /**
644    * Returns an int array where indices correspond to each residue in the
645    * sequence and the element value gives its position in the alignment
646    * 
647    * @return int[SequenceI.getEnd()-SequenceI.getStart()+1] or null if no
648    *         residues in SequenceI object
649    */
650   public int[] gapMap()
651   {
652     String seq = jalview.analysis.AlignSeq.extractGaps(
653             jalview.util.Comparison.GapChars, new String(sequence));
654     int[] map = new int[seq.length()];
655     int j = 0;
656     int p = 0;
657
658     while (j < sequence.length)
659     {
660       if (!jalview.util.Comparison.isGap(sequence[j]))
661       {
662         map[p++] = j;
663       }
664
665       j++;
666     }
667
668     return map;
669   }
670
671   /*
672    * (non-Javadoc)
673    * 
674    * @see jalview.datamodel.SequenceI#findPositionMap()
675    */
676   public int[] findPositionMap()
677   {
678     int map[] = new int[sequence.length];
679     int j = 0;
680     int pos = start;
681     int seqlen = sequence.length;
682     while ((j < seqlen))
683     {
684       map[j] = pos;
685       if (!jalview.util.Comparison.isGap(sequence[j]))
686       {
687         pos++;
688       }
689
690       j++;
691     }
692     return map;
693   }
694
695   /*
696    * (non-Javadoc)
697    * 
698    * @see jalview.datamodel.SequenceI#deleteChars(int, int)
699    */
700   public void deleteChars(int i, int j)
701   {
702     int newstart = start, newend = end;
703     if (i >= sequence.length)
704     {
705       return;
706     }
707
708     char[] tmp;
709
710     if (j >= sequence.length)
711     {
712       tmp = new char[i];
713       System.arraycopy(sequence, 0, tmp, 0, i);
714     }
715     else
716     {
717       tmp = new char[sequence.length - j + i];
718       System.arraycopy(sequence, 0, tmp, 0, i);
719       System.arraycopy(sequence, j, tmp, i, sequence.length - j);
720     }
721     boolean createNewDs = false;
722     for (int s = i; s < j; s++)
723     {
724       if (jalview.schemes.ResidueProperties.aaIndex[sequence[s]] != 23)
725       {
726         if (createNewDs)
727         {
728           newend--;
729         }
730         else
731         {
732           int sindex = findIndex(start) - 1;
733           if (sindex == s)
734           {
735             // delete characters including start of sequence
736             newstart = findPosition(j);
737             break; // don't need to search for any more residue characters.
738           }
739           else
740           {
741             // delete characters after start.
742             int eindex = findIndex(end) - 1;
743             if (eindex < j)
744             {
745               // delete characters at end of sequence
746               newend = findPosition(i - 1);
747               break; // don't need to search for any more residue characters.
748             }
749             else
750             {
751               createNewDs = true;
752               newend--; // decrease end position by one for the deleted residue
753               // and search further
754             }
755           }
756         }
757       }
758     }
759     // deletion occured in the middle of the sequence
760     if (createNewDs && this.datasetSequence != null)
761     {
762       // construct a new sequence
763       Sequence ds = new Sequence(datasetSequence);
764       // TODO: remove any non-inheritable properties ?
765       // TODO: create a sequence mapping (since there is a relation here ?)
766       ds.deleteChars(i, j);
767       datasetSequence = ds;
768     }
769     start = newstart;
770     end = newend;
771     sequence = tmp;
772   }
773
774   /**
775    * DOCUMENT ME!
776    * 
777    * @param i
778    *          DOCUMENT ME!
779    * @param c
780    *          DOCUMENT ME!
781    * @param chop
782    *          DOCUMENT ME!
783    */
784   public void insertCharAt(int i, int length, char c)
785   {
786     char[] tmp = new char[sequence.length + length];
787
788     if (i >= sequence.length)
789     {
790       System.arraycopy(sequence, 0, tmp, 0, sequence.length);
791       i = sequence.length;
792     }
793     else
794     {
795       System.arraycopy(sequence, 0, tmp, 0, i);
796     }
797
798     int index = i;
799     while (length > 0)
800     {
801       tmp[index++] = c;
802       length--;
803     }
804
805     if (i < sequence.length)
806     {
807       System.arraycopy(sequence, i, tmp, index, sequence.length - i);
808     }
809
810     sequence = tmp;
811   }
812
813   public void insertCharAt(int i, char c)
814   {
815     insertCharAt(i, 1, c);
816   }
817
818   public String getVamsasId()
819   {
820     return vamsasId;
821   }
822
823   public void setVamsasId(String id)
824   {
825     vamsasId = id;
826   }
827
828   public void setDBRef(DBRefEntry[] dbref)
829   {
830     dbrefs = dbref;
831   }
832
833   public DBRefEntry[] getDBRef()
834   {
835     if (dbrefs == null && datasetSequence != null
836             && this != datasetSequence)
837     {
838       return datasetSequence.getDBRef();
839     }
840     return dbrefs;
841   }
842
843   public void addDBRef(DBRefEntry entry)
844   {
845     if (dbrefs == null)
846     {
847       dbrefs = new DBRefEntry[0];
848     }
849
850     int i, iSize = dbrefs.length;
851
852     for (i = 0; i < iSize; i++)
853     {
854       if (dbrefs[i].equalRef(entry))
855       {
856         if (entry.getMap() != null)
857         {
858           if (dbrefs[i].getMap() == null)
859           {
860             // overwrite with 'superior' entry that contains a mapping.
861             dbrefs[i] = entry;
862           }
863         }
864         return;
865       }
866     }
867
868     DBRefEntry[] temp = new DBRefEntry[iSize + 1];
869     System.arraycopy(dbrefs, 0, temp, 0, iSize);
870     temp[temp.length - 1] = entry;
871
872     dbrefs = temp;
873   }
874
875   public void setDatasetSequence(SequenceI seq)
876   {
877     datasetSequence = seq;
878   }
879
880   public SequenceI getDatasetSequence()
881   {
882     return datasetSequence;
883   }
884
885   public AlignmentAnnotation[] getAnnotation()
886   {
887     if (annotation == null)
888     {
889       return null;
890     }
891
892     AlignmentAnnotation[] ret = new AlignmentAnnotation[annotation.size()];
893     for (int r = 0; r < ret.length; r++)
894     {
895       ret[r] = (AlignmentAnnotation) annotation.elementAt(r);
896     }
897
898     return ret;
899   }
900
901   public void addAlignmentAnnotation(AlignmentAnnotation annotation)
902   {
903     if (this.annotation == null)
904     {
905       this.annotation = new Vector();
906     }
907     if (!this.annotation.contains(annotation))
908     {
909       this.annotation.addElement(annotation);
910     }
911     annotation.setSequenceRef(this);
912   }
913
914   public void removeAlignmentAnnotation(AlignmentAnnotation annotation)
915   {
916     if (this.annotation != null)
917     {
918       this.annotation.removeElement(annotation);
919       if (this.annotation.size() == 0)
920         this.annotation = null;
921     }
922   }
923
924   /**
925    * test if this is a valid candidate for another sequence's dataset sequence.
926    * 
927    */
928   private boolean isValidDatasetSequence()
929   {
930     if (datasetSequence != null)
931     {
932       return false;
933     }
934     for (int i = 0; i < sequence.length; i++)
935     {
936       if (jalview.util.Comparison.isGap(sequence[i]))
937       {
938         return false;
939       }
940     }
941     return true;
942   }
943
944   /*
945    * (non-Javadoc)
946    * 
947    * @see jalview.datamodel.SequenceI#deriveSequence()
948    */
949   public SequenceI deriveSequence()
950   {
951     SequenceI seq = new Sequence(this);
952     if (datasetSequence != null)
953     {
954       // duplicate current sequence with same dataset
955       seq.setDatasetSequence(datasetSequence);
956     }
957     else
958     {
959       if (isValidDatasetSequence())
960       {
961         // Use this as dataset sequence
962         seq.setDatasetSequence(this);
963       }
964       else
965       {
966         // Create a new, valid dataset sequence
967         SequenceI ds = seq;
968         ds.setSequence(AlignSeq.extractGaps(
969                 jalview.util.Comparison.GapChars, new String(sequence)));
970         setDatasetSequence(ds);
971         ds.setSequenceFeatures(getSequenceFeatures());
972         seq = this; // and return this sequence as the derived sequence.
973       }
974     }
975     return seq;
976   }
977
978   /*
979    * (non-Javadoc)
980    * 
981    * @see jalview.datamodel.SequenceI#createDatasetSequence()
982    */
983   public SequenceI createDatasetSequence()
984   {
985     if (datasetSequence == null)
986     {
987       datasetSequence = new Sequence(getName(), AlignSeq.extractGaps(
988               jalview.util.Comparison.GapChars, getSequenceAsString()),
989               getStart(), getEnd());
990       datasetSequence.setSequenceFeatures(getSequenceFeatures());
991       datasetSequence.setDescription(getDescription());
992       setSequenceFeatures(null);
993       // move database references onto dataset sequence
994       datasetSequence.setDBRef(getDBRef());
995       setDBRef(null);
996       datasetSequence.setPDBId(getPDBId());
997       setPDBId(null);
998       datasetSequence.updatePDBIds();
999     }
1000     return datasetSequence;
1001   }
1002
1003   /*
1004    * (non-Javadoc)
1005    * 
1006    * @see
1007    * jalview.datamodel.SequenceI#setAlignmentAnnotation(AlignmmentAnnotation[]
1008    * annotations)
1009    */
1010   public void setAlignmentAnnotation(AlignmentAnnotation[] annotations)
1011   {
1012     if (annotation != null)
1013     {
1014       annotation.removeAllElements();
1015     }
1016     if (annotations != null)
1017     {
1018       for (int i = 0; i < annotations.length; i++)
1019       {
1020         if (annotations[i] != null)
1021           addAlignmentAnnotation(annotations[i]);
1022       }
1023     }
1024   }
1025
1026   /*
1027    * (non-Javadoc)
1028    * 
1029    * @see jalview.datamodel.SequenceI#getAnnotation(java.lang.String)
1030    */
1031   public AlignmentAnnotation[] getAnnotation(String label)
1032   {
1033     if (annotation == null || annotation.size() == 0)
1034     {
1035       return null;
1036     }
1037
1038     Vector subset = new Vector();
1039     Enumeration e = annotation.elements();
1040     while (e.hasMoreElements())
1041     {
1042       AlignmentAnnotation ann = (AlignmentAnnotation) e.nextElement();
1043       if (ann.label != null && ann.label.equals(label))
1044       {
1045         subset.addElement(ann);
1046       }
1047     }
1048     if (subset.size() == 0)
1049     {
1050       return null;
1051     }
1052     AlignmentAnnotation[] anns = new AlignmentAnnotation[subset.size()];
1053     int i = 0;
1054     e = subset.elements();
1055     while (e.hasMoreElements())
1056     {
1057       anns[i++] = (AlignmentAnnotation) e.nextElement();
1058     }
1059     subset.removeAllElements();
1060     return anns;
1061   }
1062
1063   public boolean updatePDBIds()
1064   {
1065     if (datasetSequence != null)
1066     {
1067       // TODO: could merge DBRefs
1068       return datasetSequence.updatePDBIds();
1069     }
1070     if (dbrefs == null || dbrefs.length == 0)
1071     {
1072       return false;
1073     }
1074     Vector newpdb = new Vector();
1075     for (int i = 0; i < dbrefs.length; i++)
1076     {
1077       if (DBRefSource.PDB.equals(dbrefs[i].getSource()))
1078       {
1079         PDBEntry pdbe = new PDBEntry();
1080         pdbe.setId(dbrefs[i].getAccessionId());
1081         if (pdbIds == null || pdbIds.size() == 0)
1082         {
1083           newpdb.addElement(pdbe);
1084         }
1085         else
1086         {
1087           Enumeration en = pdbIds.elements();
1088           boolean matched = false;
1089           while (!matched && en.hasMoreElements())
1090           {
1091             PDBEntry anentry = (PDBEntry) en.nextElement();
1092             if (anentry.getId().equals(pdbe.getId()))
1093             {
1094               matched = true;
1095             }
1096           }
1097           if (!matched)
1098           {
1099             newpdb.addElement(pdbe);
1100           }
1101         }
1102       }
1103     }
1104     if (newpdb.size() > 0)
1105     {
1106       Enumeration en = newpdb.elements();
1107       while (en.hasMoreElements())
1108       {
1109         addPDBId((PDBEntry) en.nextElement());
1110       }
1111       return true;
1112     }
1113     return false;
1114   }
1115
1116   /*
1117    * (non-Javadoc)
1118    * 
1119    * @see
1120    * jalview.datamodel.SequenceI#transferAnnotation(jalview.datamodel.SequenceI,
1121    * jalview.datamodel.Mapping)
1122    */
1123   public void transferAnnotation(SequenceI entry, Mapping mp)
1124   {
1125     if (datasetSequence != null)
1126     {
1127       datasetSequence.transferAnnotation(entry, mp);
1128       return;
1129     }
1130     if (entry.getDatasetSequence() != null)
1131     {
1132       transferAnnotation(entry.getDatasetSequence(), mp);
1133       return;
1134     }
1135     // transfer any new features from entry onto sequence
1136     if (entry.getSequenceFeatures() != null)
1137     {
1138
1139       SequenceFeature[] sfs = entry.getSequenceFeatures();
1140       for (int si = 0; si < sfs.length; si++)
1141       {
1142         SequenceFeature sf[] = (mp != null) ? mp.locateFeature(sfs[si])
1143                 : new SequenceFeature[]
1144                 { new SequenceFeature(sfs[si]) };
1145         if (sf != null && sf.length > 0)
1146         {
1147           for (int sfi = 0; sfi < sf.length; sfi++)
1148           {
1149             addSequenceFeature(sf[sfi]);
1150           }
1151         }
1152       }
1153     }
1154
1155     // transfer PDB entries
1156     if (entry.getPDBId() != null)
1157     {
1158       Enumeration e = entry.getPDBId().elements();
1159       while (e.hasMoreElements())
1160       {
1161         PDBEntry pdb = (PDBEntry) e.nextElement();
1162         addPDBId(pdb);
1163       }
1164     }
1165     // transfer database references
1166     DBRefEntry[] entryRefs = entry.getDBRef();
1167     if (entryRefs != null)
1168     {
1169       for (int r = 0; r < entryRefs.length; r++)
1170       {
1171         DBRefEntry newref = new DBRefEntry(entryRefs[r]);
1172         if (newref.getMap() != null && mp != null)
1173         {
1174           // remap ref using our local mapping
1175         }
1176         // we also assume all version string setting is done by dbSourceProxy
1177         /*
1178          * if (!newref.getSource().equalsIgnoreCase(dbSource)) {
1179          * newref.setSource(dbSource); }
1180          */
1181         addDBRef(newref);
1182       }
1183     }
1184   }
1185
1186   /**
1187    * @return The index (zero-based) on this sequence in the MSA. It returns
1188    *         {@code -1} if this information is not available.
1189    */
1190   public int getIndex()
1191   {
1192     return index;
1193   }
1194
1195   /**
1196    * Defines the position of this sequence in the MSA. Use the value {@code -1}
1197    * if this information is undefined.
1198    * 
1199    * @param The
1200    *          position for this sequence. This value is zero-based (zero for
1201    *          this first sequence)
1202    */
1203   public void setIndex(int value)
1204   {
1205     index = value;
1206   }
1207   
1208   public void setRNA(RNA r){rna=r;}
1209   
1210   public RNA getRNA() { return rna; }
1211   
1212 }