Set description on copy
[jalview.git] / src / jalview / datamodel / Sequence.java
1 /*
2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2006 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
22 import java.util.*;
23
24
25 /**
26  * DOCUMENT ME!
27  *
28  * @author $author$
29  * @version $Revision$
30  */
31 public class Sequence implements SequenceI
32 {
33   SequenceI datasetSequence;
34   String name;
35   private char [] sequence;
36   String description;
37   int start;
38   int end;
39   Vector pdbIds;
40   String vamsasId;
41   DBRefEntry[] dbrefs;
42
43   /** This annotation is displayed below the alignment but the
44    * positions are tied to the residues of this sequence */
45   Vector annotation;
46
47   /** DOCUMENT ME!! */
48   public SequenceFeature[] sequenceFeatures;
49
50   /** This array holds hidden sequences
51    * of which this sequence is the representitive member of a group
52    */
53   SequenceGroup hiddenSequences;
54
55   /**
56    * Creates a new Sequence object.
57    *
58    * @param name DOCUMENT ME!
59    * @param sequence DOCUMENT ME!
60    * @param start DOCUMENT ME!
61    * @param end DOCUMENT ME!
62    */
63   public Sequence(String name, String sequence, int start, int end)
64   {
65     this.name = name;
66     this.sequence = sequence.toCharArray();
67     this.start = start;
68     this.end = end;
69     parseId();
70     checkValidRange();
71   }
72
73   public Sequence(String name, char [] sequence, int start, int end)
74   {
75     this.name = name;
76     this.sequence = sequence;
77     this.start = start;
78     this.end = end;
79     parseId();
80     checkValidRange();
81   }
82
83   com.stevesoft.pat.Regex limitrx = new com.stevesoft.pat.Regex(
84       "[/][0-9]{1,}[-][0-9]{1,}$");
85   com.stevesoft.pat.Regex endrx = new com.stevesoft.pat.Regex(
86       "[0-9]{1,}$");
87
88   void parseId()
89   {
90     // Does sequence have the /start-end signiature?
91     if (limitrx.search(name))
92     {
93       name = limitrx.left();
94       endrx.search(limitrx.stringMatched());
95       setStart(Integer.parseInt(limitrx.stringMatched().substring(1,
96           endrx.matchedFrom() - 1)));
97       setEnd(Integer.parseInt(endrx.stringMatched()));
98     }
99   }
100
101   void checkValidRange()
102   {
103     if (end < 1)
104     {
105       int endRes = 0;
106       for (int j = 0; j < sequence.length; j++)
107       {
108         if (!jalview.util.Comparison.isGap( sequence[j] ))
109         {
110           endRes++;
111         }
112       }
113       if (endRes > 0)
114       {
115         endRes += start - 1;
116       }
117
118       this.end = endRes;
119     }
120
121   }
122
123   /**
124    * Creates a new Sequence object.
125    *
126    * @param name DOCUMENT ME!
127    * @param sequence DOCUMENT ME!
128    */
129   public Sequence(String name, String sequence)
130   {
131     this(name, sequence, 1, -1);
132   }
133
134   /**
135    * Creates a new Sequence object.
136    *
137    * @param seq DOCUMENT ME!
138    */
139   public Sequence(SequenceI seq)
140   {
141     this(seq.getName(),
142          seq.getSequence(),
143          seq.getStart(),
144          seq.getEnd());
145     description = seq.getDescription();
146   }
147
148
149   /**
150    * DOCUMENT ME!
151    *
152    * @param v DOCUMENT ME!
153    */
154   public void setSequenceFeatures(SequenceFeature[] features)
155   {
156     sequenceFeatures = features;
157   }
158
159   public synchronized void addSequenceFeature(SequenceFeature sf)
160   {
161     if (sequenceFeatures == null)
162     {
163       sequenceFeatures = new SequenceFeature[0];
164     }
165
166     for (int i = 0; i < sequenceFeatures.length; i++)
167     {
168       if (sequenceFeatures[i].equals(sf))
169       {
170         return;
171       }
172     }
173
174     SequenceFeature[] temp = new SequenceFeature[sequenceFeatures.length + 1];
175     System.arraycopy(sequenceFeatures, 0, temp, 0, sequenceFeatures.length);
176     temp[sequenceFeatures.length] = sf;
177
178     sequenceFeatures = temp;
179   }
180
181   public void deleteFeature(SequenceFeature sf)
182   {
183     if(sequenceFeatures==null)
184       return;
185
186     int index=0;
187     for (index = 0; index < sequenceFeatures.length; index++)
188     {
189       if (sequenceFeatures[index].equals(sf))
190       {
191         break;
192       }
193     }
194
195
196     if(index==sequenceFeatures.length)
197       return;
198
199     int sfLength = sequenceFeatures.length;
200     if(sfLength<2)
201     {
202       sequenceFeatures = null;
203     }
204     else
205     {
206       SequenceFeature[] temp = new SequenceFeature[sfLength-1];
207       System.arraycopy(sequenceFeatures, 0, temp, 0, index);
208
209       if(index<sfLength)
210         System.arraycopy(sequenceFeatures,
211                          index + 1,
212                          temp,
213                          index, sequenceFeatures.length - index -1);
214
215       sequenceFeatures = temp;
216     }
217   }
218
219   /**
220    * DOCUMENT ME!
221    *
222    * @return DOCUMENT ME!
223    */
224   public SequenceFeature[] getSequenceFeatures()
225   {
226     return sequenceFeatures;
227   }
228
229   public void addPDBId(PDBEntry entry)
230   {
231     if (pdbIds == null)
232       pdbIds = new Vector();
233
234     pdbIds.addElement(entry);
235   }
236
237   /**
238    * DOCUMENT ME!
239    *
240    * @param id DOCUMENT ME!
241    */
242   public void setPDBId(Vector id)
243   {
244     pdbIds = id;
245   }
246
247   /**
248    * DOCUMENT ME!
249    *
250    * @return DOCUMENT ME!
251    */
252   public Vector getPDBId()
253   {
254     return pdbIds;
255   }
256
257   /**
258    * DOCUMENT ME!
259    *
260    * @return DOCUMENT ME!
261    */
262   public String getDisplayId(boolean jvsuffix)
263   {
264     StringBuffer result = new StringBuffer(name);
265     if (jvsuffix)
266     {
267       result.append("/" + start + "-" + end);
268     }
269
270     return result.toString();
271   }
272
273   /**
274    * DOCUMENT ME!
275    *
276    * @param name DOCUMENT ME!
277    */
278   public void setName(String name)
279   {
280     this.name = name;
281     this.parseId();
282   }
283
284   /**
285    * DOCUMENT ME!
286    *
287    * @return DOCUMENT ME!
288    */
289   public String getName()
290   {
291     return this.name;
292   }
293
294   /**
295    * DOCUMENT ME!
296    *
297    * @param start DOCUMENT ME!
298    */
299   public void setStart(int start)
300   {
301     this.start = start;
302   }
303
304   /**
305    * DOCUMENT ME!
306    *
307    * @return DOCUMENT ME!
308    */
309   public int getStart()
310   {
311     return this.start;
312   }
313
314   /**
315    * DOCUMENT ME!
316    *
317    * @param end DOCUMENT ME!
318    */
319   public void setEnd(int end)
320   {
321     this.end = end;
322   }
323
324   /**
325    * DOCUMENT ME!
326    *
327    * @return DOCUMENT ME!
328    */
329   public int getEnd()
330   {
331     return this.end;
332   }
333
334   /**
335    * DOCUMENT ME!
336    *
337    * @return DOCUMENT ME!
338    */
339   public int getLength()
340   {
341     return this.sequence.length;
342   }
343
344   /**
345    * DOCUMENT ME!
346    *
347    * @param seq DOCUMENT ME!
348    */
349   public void setSequence(String seq)
350   {
351     this.sequence = seq.toCharArray();
352     checkValidRange();
353   }
354
355
356   public String getSequenceAsString()
357   {
358     return new String(sequence);
359   }
360
361   public String getSequenceAsString(int start, int end)
362   {
363     return new String(getSequence(start, end));
364   }
365
366
367   public char [] getSequence()
368   {
369     return sequence;
370   }
371
372   /**
373    * DOCUMENT ME!
374    *
375    * @param start DOCUMENT ME!
376    * @param end DOCUMENT ME!
377    *
378    * @return DOCUMENT ME!
379    */
380   public char [] getSequence(int start, int end)
381   {
382     // JBPNote - left to user to pad the result here (TODO:Decide on this policy)
383     if (start >= sequence.length)
384     {
385       return new char[0];
386     }
387
388     if (end >= sequence.length)
389     {
390       end = sequence.length;
391     }
392
393     char [] reply = new char[end-start];
394     System.arraycopy(sequence, start, reply, 0, end-start);
395
396     return reply;
397   }
398
399
400   /**
401    * make a new Sequence object from start to end (including gaps) over this seqeunce
402    * @param start int
403    * @param end int
404    * @return SequenceI
405    */
406   public SequenceI getSubSequence(int start, int end)
407   {
408     if (start < 0)
409       start = 0;
410     char [] seq = getSequence(start, end);
411     if (seq.length == 0)
412       return null;
413     int nstart = findPosition(start);
414     int nend = findPosition(end) - 1;
415     // JBPNote - this is an incomplete copy.
416     SequenceI nseq = new Sequence(this.getName(), seq, nstart, nend);
417     nseq.setDescription(description);
418     nseq.setDatasetSequence(getDatasetSequence());
419     return nseq;
420   }
421
422   /**
423    * DOCUMENT ME!
424    *
425    * @param i DOCUMENT ME!
426    *
427    * @return DOCUMENT ME!
428    */
429   public char getCharAt(int i)
430   {
431     if (i < sequence.length)
432     {
433       return sequence[i];
434     }
435     else
436     {
437       return ' ';
438     }
439   }
440
441   /**
442    * DOCUMENT ME!
443    *
444    * @param desc DOCUMENT ME!
445    */
446   public void setDescription(String desc)
447   {
448     this.description = desc;
449   }
450
451   /**
452    * DOCUMENT ME!
453    *
454    * @return DOCUMENT ME!
455    */
456   public String getDescription()
457   {
458     return this.description;
459   }
460
461   /**
462    * DOCUMENT ME!
463    *
464    * @param pos DOCUMENT ME!
465    *
466    * @return DOCUMENT ME!
467    */
468   public int findIndex(int pos)
469   {
470     // returns the alignment position for a residue
471     int j = start;
472     int i = 0;
473
474     while ( (i < sequence.length) && (j <= end) && (j <= pos))
475     {
476       if (!jalview.util.Comparison.isGap(sequence[i]))
477       {
478         j++;
479       }
480
481       i++;
482     }
483
484     if ( (j == end) && (j < pos))
485     {
486       return end + 1;
487     }
488     else
489     {
490       return i;
491     }
492   }
493
494   /**
495    * Returns the sequence position for an alignment position
496    *
497    * @param i column index in alignment (from 1)
498    *
499    * @return residue number for residue (left of and) nearest ith column
500    */
501   public int findPosition(int i)
502   {
503     int j = 0;
504     int pos = start;
505     int seqlen = sequence.length;
506     while ( (j < i) && (j < seqlen))
507     {
508       if (!jalview.util.Comparison.isGap( sequence[j] ))
509       {
510         pos++;
511       }
512
513       j++;
514     }
515
516     return pos;
517   }
518
519   /**
520    * Returns an int array where indices correspond to each residue in the sequence and the element value gives its position in the alignment
521    *
522    * @return int[SequenceI.getEnd()-SequenceI.getStart()+1] or null if no residues in SequenceI object
523    */
524   public int[] gapMap()
525   {
526     String seq = jalview.analysis.AlignSeq.extractGaps(jalview.util.Comparison.
527         GapChars, new String(sequence));
528     int[] map = new int[seq.length()];
529     int j = 0;
530     int p = 0;
531
532     while (j < sequence.length)
533     {
534       if (!jalview.util.Comparison.isGap(sequence[j]))
535       {
536         map[p++] = j;
537       }
538
539       j++;
540     }
541
542     return map;
543   }
544
545   /**
546    * DOCUMENT ME!
547    *
548    * @param i DOCUMENT ME!
549    * @param j DOCUMENT ME!
550    */
551   public void deleteChars(int i, int j)
552   {
553     if (i >= sequence.length)
554     {
555       return;
556     }
557
558     char [] tmp;
559
560     if (j >= sequence.length)
561     {
562       tmp = new char[i];
563       System.arraycopy(sequence,0,tmp,0,i);
564     }
565     else
566     {
567       tmp = new char[sequence.length-j+i];
568       System.arraycopy(sequence,0,tmp,0,i);
569       System.arraycopy(sequence,j,tmp,i,sequence.length-j);
570     }
571
572     sequence = tmp;
573   }
574
575   /**
576    * DOCUMENT ME!
577    *
578    * @param i DOCUMENT ME!
579    * @param c DOCUMENT ME!
580    * @param chop DOCUMENT ME!
581    */
582   public void insertCharAt(int i, int length, char c)
583   {
584     char [] tmp = new char[sequence.length+length];
585
586     if (i >= sequence.length)
587     {
588       System.arraycopy(sequence, 0, tmp, 0, sequence.length);
589       i = sequence.length;
590     }
591     else
592    {
593       System.arraycopy(sequence, 0, tmp, 0, i);
594    }
595
596
597     int index = i;
598     while (length > 0)
599     {
600       tmp[ index++ ] = c;
601       length--;
602     }
603
604     if (i < sequence.length)
605     {
606       System.arraycopy(sequence, i, tmp, index, sequence.length-i );
607     }
608
609     sequence = tmp;
610   }
611
612   public void insertCharAt(int i, char c)
613   {
614     insertCharAt(i, 1, c);
615   }
616
617   public String getVamsasId()
618   {
619     return vamsasId;
620   }
621
622   public void setVamsasId(String id)
623   {
624     vamsasId = id;
625   }
626
627   public void setDBRef(DBRefEntry[] dbref)
628   {
629     dbrefs = dbref;
630   }
631
632   public DBRefEntry[] getDBRef()
633   {
634     return dbrefs;
635   }
636
637   public void addDBRef(DBRefEntry entry)
638   {
639     if (dbrefs == null)
640       dbrefs = new DBRefEntry[0];
641
642     int i, iSize = dbrefs.length;
643
644     for(i=0; i<iSize; i++)
645       if(dbrefs[i].getAccessionId().equals(entry.getAccessionId())
646       && dbrefs[i].getSource().equals(entry.getSource())
647       && dbrefs[i].getVersion().equals(entry.getVersion()))
648       {
649         return;
650       }
651
652     DBRefEntry[] temp = new DBRefEntry[iSize + 1];
653     System.arraycopy(dbrefs, 0, temp, 0, iSize);
654     temp[temp.length - 1] = entry;
655
656     dbrefs = temp;
657   }
658
659   public void setDatasetSequence(SequenceI seq)
660   {
661     datasetSequence = seq;
662   }
663
664   public SequenceI getDatasetSequence()
665   {
666     return datasetSequence;
667   }
668
669   public AlignmentAnnotation[] getAnnotation()
670   {
671     if (annotation == null)
672       return null;
673
674     AlignmentAnnotation[] ret = new AlignmentAnnotation[annotation.size()];
675     for (int r = 0; r < ret.length; r++)
676       ret[r] = (AlignmentAnnotation) annotation.elementAt(r);
677
678     return ret;
679   }
680
681   public void addAlignmentAnnotation(AlignmentAnnotation annotation)
682   {
683     if (this.annotation == null)
684       this.annotation = new Vector();
685
686     this.annotation.addElement(annotation);
687   }
688
689   public SequenceGroup getHiddenSequences()
690   {
691     return hiddenSequences;
692   }
693
694   public void addHiddenSequence(SequenceI seq)
695   {
696     if (hiddenSequences == null)
697     {
698       hiddenSequences = new SequenceGroup();
699     }
700     hiddenSequences.addSequence(seq, false);
701   }
702
703   public void showHiddenSequence(SequenceI seq)
704   {
705     hiddenSequences.deleteSequence(seq, false);
706     if (hiddenSequences.getSize(false) < 1)
707     {
708       hiddenSequences = null;
709     }
710   }
711 }
712
713