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