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