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