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