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