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