getDBRefs now always returns DBRefArray if it exists on this sequence or dataset...
[jalview.git] / src / jalview / datamodel / Sequence.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 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    * (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    * (non-Javadoc)
685    * 
686    * @see jalview.datamodel.SequenceI#deleteChars(int, int)
687    */
688   public void deleteChars(int i, int j)
689   {
690     int newstart = start, newend = end;
691     if (i >= sequence.length)
692     {
693       return;
694     }
695
696     char[] tmp;
697
698     if (j >= sequence.length)
699     {
700       tmp = new char[i];
701       System.arraycopy(sequence, 0, tmp, 0, i);
702     }
703     else
704     {
705       tmp = new char[sequence.length - j + i];
706       System.arraycopy(sequence, 0, tmp, 0, i);
707       System.arraycopy(sequence, j, tmp, i, sequence.length - j);
708     }
709     boolean createNewDs = false;
710     for (int s = i; s < j; s++)
711     {
712       if (jalview.schemes.ResidueProperties.aaIndex[sequence[s]] != 23)
713       {
714         if (createNewDs)
715         {
716           newend--;
717         }
718         else
719         {
720           int sindex = findIndex(start) - 1;
721           if (sindex == s)
722           {
723             // delete characters including start of sequence
724             newstart = findPosition(j);
725             break; // don't need to search for any more residue characters.
726           }
727           else
728           {
729             // delete characters after start.
730             int eindex = findIndex(end) - 1;
731             if (eindex < j)
732             {
733               // delete characters at end of sequence
734               newend = findPosition(i - 1);
735               break; // don't need to search for any more residue characters.
736             }
737             else
738             {
739               createNewDs = true;
740               newend--; // decrease end position by one for the deleted residue
741                         // and search further
742             }
743           }
744         }
745       }
746     }
747     // deletion occured in the middle of the sequence
748     if (createNewDs && this.datasetSequence != null)
749     {
750       // construct a new sequence
751       Sequence ds = new Sequence(datasetSequence);
752       // TODO: remove any non-inheritable properties ?
753       // TODO: create a sequence mapping (since there is a relation here ?)
754       ds.deleteChars(i, j);
755       datasetSequence = ds;
756     }
757     start = newstart;
758     end = newend;
759     sequence = tmp;
760   }
761
762   /**
763    * DOCUMENT ME!
764    * 
765    * @param i
766    *                DOCUMENT ME!
767    * @param c
768    *                DOCUMENT ME!
769    * @param chop
770    *                DOCUMENT ME!
771    */
772   public void insertCharAt(int i, int length, char c)
773   {
774     char[] tmp = new char[sequence.length + length];
775
776     if (i >= sequence.length)
777     {
778       System.arraycopy(sequence, 0, tmp, 0, sequence.length);
779       i = sequence.length;
780     }
781     else
782     {
783       System.arraycopy(sequence, 0, tmp, 0, i);
784     }
785
786     int index = i;
787     while (length > 0)
788     {
789       tmp[index++] = c;
790       length--;
791     }
792
793     if (i < sequence.length)
794     {
795       System.arraycopy(sequence, i, tmp, index, sequence.length - i);
796     }
797
798     sequence = tmp;
799   }
800
801   public void insertCharAt(int i, char c)
802   {
803     insertCharAt(i, 1, c);
804   }
805
806   public String getVamsasId()
807   {
808     return vamsasId;
809   }
810
811   public void setVamsasId(String id)
812   {
813     vamsasId = id;
814   }
815
816   public void setDBRef(DBRefEntry[] dbref)
817   {
818     dbrefs = dbref;
819   }
820
821   public DBRefEntry[] getDBRef()
822   {
823     if (dbrefs==null && datasetSequence!=null && this!=datasetSequence)
824     {
825       return datasetSequence.getDBRef();
826     }
827     return dbrefs;
828   }
829
830   public void addDBRef(DBRefEntry entry)
831   {
832     if (dbrefs == null)
833     {
834       dbrefs = new DBRefEntry[0];
835     }
836
837     int i, iSize = dbrefs.length;
838
839     for (i = 0; i < iSize; i++)
840     {
841       if (dbrefs[i].equalRef(entry))
842       {
843         if (entry.getMap() != null)
844         {
845           if (dbrefs[i].getMap() == null)
846           {
847             // overwrite with 'superior' entry that contains a mapping.
848             dbrefs[i] = entry;
849           }
850         }
851         return;
852       }
853     }
854
855     DBRefEntry[] temp = new DBRefEntry[iSize + 1];
856     System.arraycopy(dbrefs, 0, temp, 0, iSize);
857     temp[temp.length - 1] = entry;
858
859     dbrefs = temp;
860   }
861
862   public void setDatasetSequence(SequenceI seq)
863   {
864     datasetSequence = seq;
865   }
866
867   public SequenceI getDatasetSequence()
868   {
869     return datasetSequence;
870   }
871
872   public AlignmentAnnotation[] getAnnotation()
873   {
874     if (annotation == null)
875     {
876       return null;
877     }
878
879     AlignmentAnnotation[] ret = new AlignmentAnnotation[annotation.size()];
880     for (int r = 0; r < ret.length; r++)
881     {
882       ret[r] = (AlignmentAnnotation) annotation.elementAt(r);
883     }
884
885     return ret;
886   }
887
888   public void addAlignmentAnnotation(AlignmentAnnotation annotation)
889   {
890     if (this.annotation == null)
891     {
892       this.annotation = new Vector();
893     }
894
895     this.annotation.addElement(annotation);
896     annotation.setSequenceRef(this);
897   }
898
899   public void removeAlignmentAnnotation(AlignmentAnnotation annotation)
900   {
901     if (this.annotation != null)
902     {
903       this.annotation.removeElement(annotation);
904       if (this.annotation.size() == 0)
905         this.annotation = null;
906     }
907   }
908
909   /**
910    * test if this is a valid candidate for another sequence's dataset sequence.
911    * 
912    */
913   private boolean isValidDatasetSequence()
914   {
915     if (datasetSequence != null)
916     {
917       return false;
918     }
919     for (int i = 0; i < sequence.length; i++)
920     {
921       if (jalview.util.Comparison.isGap(sequence[i]))
922       {
923         return false;
924       }
925     }
926     return true;
927   }
928
929   /*
930    * (non-Javadoc)
931    * 
932    * @see jalview.datamodel.SequenceI#deriveSequence()
933    */
934   public SequenceI deriveSequence()
935   {
936     SequenceI seq = new Sequence(this);
937     if (datasetSequence != null)
938     {
939       // duplicate current sequence with same dataset
940       seq.setDatasetSequence(datasetSequence);
941     }
942     else
943     {
944       if (isValidDatasetSequence())
945       {
946         // Use this as dataset sequence
947         seq.setDatasetSequence(this);
948       }
949       else
950       {
951         // Create a new, valid dataset sequence
952         SequenceI ds = seq;
953         ds.setSequence(AlignSeq.extractGaps(
954                 jalview.util.Comparison.GapChars, new String(sequence)));
955         setDatasetSequence(ds);
956         ds.setSequenceFeatures(getSequenceFeatures());
957         seq = this; // and return this sequence as the derived sequence.
958       }
959     }
960     return seq;
961   }
962
963   /*
964    * (non-Javadoc)
965    * 
966    * @see jalview.datamodel.SequenceI#createDatasetSequence()
967    */
968   public SequenceI createDatasetSequence()
969   {
970     if (datasetSequence == null)
971     {
972       datasetSequence = new Sequence(getName(), AlignSeq.extractGaps(
973               jalview.util.Comparison.GapChars, getSequenceAsString()),
974               getStart(), getEnd());
975       datasetSequence.setSequenceFeatures(getSequenceFeatures());
976       datasetSequence.setDescription(getDescription());
977       setSequenceFeatures(null);
978       // move database references onto dataset sequence
979       datasetSequence.setDBRef(getDBRef());
980       setDBRef(null);
981       datasetSequence.setPDBId(getPDBId());
982       setPDBId(null);
983       datasetSequence.updatePDBIds();
984     }
985     return datasetSequence;
986   }
987
988   /*
989    * (non-Javadoc)
990    * 
991    * @see jalview.datamodel.SequenceI#setAlignmentAnnotation(AlignmmentAnnotation[]
992    *      annotations)
993    */
994   public void setAlignmentAnnotation(AlignmentAnnotation[] annotations)
995   {
996     if (annotation != null)
997     {
998       annotation.removeAllElements();
999     }
1000     if (annotations != null)
1001     {
1002       for (int i = 0; i < annotations.length; i++)
1003       {
1004         if (annotations[i] != null)
1005           addAlignmentAnnotation(annotations[i]);
1006       }
1007     }
1008   }
1009
1010   /*
1011    * (non-Javadoc)
1012    * 
1013    * @see jalview.datamodel.SequenceI#getAnnotation(java.lang.String)
1014    */
1015   public AlignmentAnnotation[] getAnnotation(String label)
1016   {
1017     if (annotation == null || annotation.size() == 0)
1018     {
1019       return null;
1020     }
1021
1022     Vector subset = new Vector();
1023     Enumeration e = annotation.elements();
1024     while (e.hasMoreElements())
1025     {
1026       AlignmentAnnotation ann = (AlignmentAnnotation) e.nextElement();
1027       if (ann.label != null && ann.label.equals(label))
1028       {
1029         subset.addElement(ann);
1030       }
1031     }
1032     if (subset.size() == 0)
1033     {
1034       return null;
1035     }
1036     AlignmentAnnotation[] anns = new AlignmentAnnotation[subset.size()];
1037     int i = 0;
1038     e = subset.elements();
1039     while (e.hasMoreElements())
1040     {
1041       anns[i++] = (AlignmentAnnotation) e.nextElement();
1042     }
1043     subset.removeAllElements();
1044     return anns;
1045   }
1046
1047   public boolean updatePDBIds()
1048   {
1049     if (datasetSequence != null)
1050     {
1051       // TODO: could merge DBRefs
1052       return datasetSequence.updatePDBIds();
1053     }
1054     if (dbrefs == null || dbrefs.length == 0)
1055     {
1056       return false;
1057     }
1058     Vector newpdb = new Vector();
1059     for (int i = 0; i < dbrefs.length; i++)
1060     {
1061       if (DBRefSource.PDB.equals(dbrefs[i].getSource()))
1062       {
1063         PDBEntry pdbe = new PDBEntry();
1064         pdbe.setId(dbrefs[i].getAccessionId());
1065         if (pdbIds == null || pdbIds.size() == 0)
1066         {
1067           newpdb.addElement(pdbe);
1068         }
1069         else
1070         {
1071           Enumeration en = pdbIds.elements();
1072           boolean matched = false;
1073           while (!matched && en.hasMoreElements())
1074           {
1075             PDBEntry anentry = (PDBEntry) en.nextElement();
1076             if (anentry.getId().equals(pdbe.getId()))
1077             {
1078               matched = true;
1079             }
1080           }
1081           if (!matched)
1082           {
1083             newpdb.addElement(pdbe);
1084           }
1085         }
1086       }
1087     }
1088     if (newpdb.size() > 0)
1089     {
1090       Enumeration en = newpdb.elements();
1091       while (en.hasMoreElements())
1092       {
1093         addPDBId((PDBEntry) en.nextElement());
1094       }
1095       return true;
1096     }
1097     return false;
1098   }
1099
1100   /*
1101    * (non-Javadoc)
1102    * 
1103    * @see jalview.datamodel.SequenceI#transferAnnotation(jalview.datamodel.SequenceI,
1104    *      jalview.datamodel.Mapping)
1105    */
1106   public void transferAnnotation(SequenceI entry, Mapping mp)
1107   {
1108     if (datasetSequence != null)
1109     {
1110       datasetSequence.transferAnnotation(entry, mp);
1111       return;
1112     }
1113     if (entry.getDatasetSequence() != null)
1114     {
1115       transferAnnotation(entry.getDatasetSequence(), mp);
1116       return;
1117     }
1118     // transfer any new features from entry onto sequence
1119     if (entry.getSequenceFeatures() != null)
1120     {
1121
1122       SequenceFeature[] sfs = entry.getSequenceFeatures();
1123       for (int si = 0; si < sfs.length; si++)
1124       {
1125         SequenceFeature sf[] = (mp != null) ? mp.locateFeature(sfs[si])
1126                 : new SequenceFeature[]
1127                 { new SequenceFeature(sfs[si]) };
1128         if (sf != null && sf.length > 0)
1129         {
1130           for (int sfi = 0; sfi < sf.length; sfi++)
1131           {
1132             addSequenceFeature(sf[sfi]);
1133           }
1134         }
1135       }
1136     }
1137
1138     // transfer PDB entries
1139     if (entry.getPDBId() != null)
1140     {
1141       Enumeration e = entry.getPDBId().elements();
1142       while (e.hasMoreElements())
1143       {
1144         PDBEntry pdb = (PDBEntry) e.nextElement();
1145         addPDBId(pdb);
1146       }
1147     }
1148     // transfer database references
1149     DBRefEntry[] entryRefs = entry.getDBRef();
1150     if (entryRefs != null)
1151     {
1152       for (int r = 0; r < entryRefs.length; r++)
1153       {
1154         DBRefEntry newref = new DBRefEntry(entryRefs[r]);
1155         if (newref.getMap() != null && mp != null)
1156         {
1157           // remap ref using our local mapping
1158         }
1159         // we also assume all version string setting is done by dbSourceProxy
1160         /*
1161          * if (!newref.getSource().equalsIgnoreCase(dbSource)) {
1162          * newref.setSource(dbSource); }
1163          */
1164         addDBRef(newref);
1165       }
1166     }
1167   }
1168
1169 }