remove unnecessary import
[jalview.git] / src / jalview / datamodel / Alignment.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 jalview.analysis.*;
22
23 import java.util.*;
24
25 /** Data structure to hold and manipulate a multiple sequence alignment
26  */
27 public class Alignment implements AlignmentI
28 {
29     protected Alignment dataset;
30     protected Vector sequences;
31     protected Vector groups = new Vector();
32     protected char gapCharacter = '-';
33     protected int type = NUCLEOTIDE;
34     public static final int PROTEIN = 0;
35     public static final int NUCLEOTIDE = 1;
36
37     /** DOCUMENT ME!! */
38     public AlignmentAnnotation[] annotations;
39
40     HiddenSequences hiddenSequences = new HiddenSequences(this);
41
42     private void initAlignment(SequenceI[] seqs) {
43       int i=0;
44
45       if( jalview.util.Comparison.isNucleotide(seqs))
46         type = NUCLEOTIDE;
47       else
48         type = PROTEIN;
49
50       sequences = new Vector();
51
52       for (i = 0; i < seqs.length; i++)
53       {
54         sequences.addElement(seqs[i]);
55       }
56
57     }
58     /** Make an alignment from an array of Sequences.
59      *
60      * @param sequences
61      */
62     public Alignment(SequenceI[] seqs)
63     {
64       initAlignment(seqs);
65     }
66     /**
67      * Make a new alignment from an array of SeqCigars
68      * @param seqs SeqCigar[]
69      */
70     public Alignment(SeqCigar[] alseqs) {
71       SequenceI[] seqs = SeqCigar.createAlignmentSequences(alseqs, gapCharacter, new ColumnSelection(), null);
72       initAlignment(seqs);
73     }
74     /**
75      * Make a new alignment from an CigarArray
76      * JBPNote - can only do this when compactAlignment does not contain hidden regions.
77      * JBPNote - must also check that compactAlignment resolves to a set of SeqCigars - or construct them appropriately.
78      * @param compactAlignment CigarArray
79      */
80     public static AlignmentI createAlignment(CigarArray compactAlignment) {
81       throw new Error("Alignment(CigarArray) not yet implemented");
82       // this(compactAlignment.refCigars);
83     }
84
85     /**
86      * DOCUMENT ME!
87      *
88      * @return DOCUMENT ME!
89      */
90     public Vector getSequences()
91     {
92         return sequences;
93     }
94
95     public SequenceI [] getSequencesArray()
96     {
97       SequenceI [] reply = new SequenceI[sequences.size()];
98       for(int i=0; i<sequences.size(); i++)
99       {
100         reply[i] = (SequenceI)sequences.elementAt(i);
101       }
102       return reply;
103     }
104
105     /**
106      * DOCUMENT ME!
107      *
108      * @param i DOCUMENT ME!
109      *
110      * @return DOCUMENT ME!
111      */
112     public SequenceI getSequenceAt(int i)
113     {
114         if (i < sequences.size())
115         {
116             return (SequenceI) sequences.elementAt(i);
117         }
118
119         return null;
120     }
121
122     /** Adds a sequence to the alignment.  Recalculates maxLength and size.
123      *
124      * @param snew
125      */
126     public void addSequence(SequenceI snew)
127     {
128       if(dataset!=null)
129       {
130         if(snew.getDatasetSequence()!=null)
131         {
132           getDataset().addSequence(snew.getDatasetSequence());
133         }
134         else
135         {
136           Sequence ds = new Sequence(snew.getName(),
137                                      AlignSeq.extractGaps("-. ",
138               snew.getSequenceAsString()),
139                                      snew.getStart(),
140                                      snew.getEnd());
141
142           snew.setDatasetSequence(ds);
143           getDataset().addSequence(ds);
144         }
145       }
146       sequences.addElement(snew);
147
148       hiddenSequences.adjustHeightSequenceAdded();
149     }
150
151
152     /** Adds a sequence to the alignment.  Recalculates maxLength and size.
153      *
154      * @param snew
155      */
156     public void setSequenceAt(int i, SequenceI snew)
157     {
158         SequenceI oldseq = getSequenceAt(i);
159         deleteSequence(oldseq);
160
161         sequences.setElementAt(snew, i);
162     }
163
164     /**
165      * DOCUMENT ME!
166      *
167      * @return DOCUMENT ME!
168      */
169     public Vector getGroups()
170     {
171         return groups;
172     }
173
174     /**
175      * DOCUMENT ME!
176      *
177      * @param s DOCUMENT ME!
178      */
179     public void deleteSequence(SequenceI s)
180     {
181       deleteSequence(findIndex(s));
182     }
183
184     /**
185      * DOCUMENT ME!
186      *
187      * @param i DOCUMENT ME!
188      */
189     public void deleteSequence(int i)
190     {
191       if(i>-1 && i<getHeight())
192       {
193         sequences.removeElementAt(i);
194         hiddenSequences.adjustHeightSequenceDeleted(i);
195       }
196     }
197
198
199     /**    */
200     public SequenceGroup findGroup(SequenceI s)
201     {
202         for (int i = 0; i < this.groups.size(); i++)
203         {
204             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
205
206             if (sg.getSequences(false).contains(s))
207             {
208                 return sg;
209             }
210         }
211
212         return null;
213     }
214
215     /**
216      * DOCUMENT ME!
217      *
218      * @param s DOCUMENT ME!
219      *
220      * @return DOCUMENT ME!
221      */
222     public SequenceGroup[] findAllGroups(SequenceI s)
223     {
224         Vector temp = new Vector();
225
226         int gSize = groups.size();
227         for (int i = 0; i < gSize; i++)
228         {
229             SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
230             if(sg==null || sg.getSequences(false)==null)
231             {
232               this.deleteGroup(sg);
233               gSize--;
234               continue;
235             }
236
237             if (sg.getSequences(false).contains(s))
238             {
239                 temp.addElement(sg);
240             }
241         }
242
243         SequenceGroup[] ret = new SequenceGroup[temp.size()];
244
245         for (int i = 0; i < temp.size(); i++)
246         {
247             ret[i] = (SequenceGroup) temp.elementAt(i);
248         }
249
250         return ret;
251     }
252
253
254
255     /**    */
256     public void addGroup(SequenceGroup sg)
257     {
258         if (!groups.contains(sg))
259         {
260           if(hiddenSequences.getSize()>0)
261           {
262             //We're not going to make groups of
263             //Hidden sequences
264             int i, iSize = sg.getSize(false);
265             for (i = 0; i < iSize; i++)
266             {
267               if (!sequences.contains(sg.getSequenceAt(i)))
268               {
269                 sg.deleteSequence(sg.getSequenceAt(i), false);
270                 iSize--;
271                 i--;
272               }
273             }
274
275             if (sg.getSize(true) < 1)
276               return;
277           }
278
279           groups.addElement(sg);
280         }
281     }
282
283     /**
284      * DOCUMENT ME!
285      */
286     public void deleteAllGroups()
287     {
288         groups.removeAllElements();
289     }
290
291     /**    */
292     public void deleteGroup(SequenceGroup g)
293     {
294         if (groups.contains(g))
295         {
296             groups.removeElement(g);
297         }
298     }
299
300     /**    */
301     public SequenceI findName(String name)
302     {
303         int i = 0;
304
305         while (i < sequences.size())
306         {
307             if (getSequenceAt(i).getName().equals(name))
308             {
309                 return getSequenceAt(i);
310             }
311
312             i++;
313         }
314
315         return null;
316     }
317
318     public SequenceI [] findSequenceMatch(String name)
319     {
320       Vector matches = new Vector();
321       int i = 0;
322
323       while (i < sequences.size())
324       {
325           if (getSequenceAt(i).getName().equals(name))
326           {
327               matches.addElement(getSequenceAt(i));
328           }
329           i++;
330       }
331
332       SequenceI [] result = new SequenceI[matches.size()];
333       for(i=0; i<result.length; i++)
334         result[i] = (SequenceI)matches.elementAt(i);
335
336       return result;
337
338     }
339
340
341     /**    */
342     public int findIndex(SequenceI s)
343     {
344         int i = 0;
345
346         while (i < sequences.size())
347         {
348             if (s == getSequenceAt(i))
349             {
350                 return i;
351             }
352
353             i++;
354         }
355
356         return -1;
357     }
358
359     /**
360      * DOCUMENT ME!
361      *
362      * @return DOCUMENT ME!
363      */
364     public int getHeight()
365     {
366         return sequences.size();
367     }
368
369     /**
370      * DOCUMENT ME!
371      *
372      * @return DOCUMENT ME!
373      */
374     public int getWidth()
375     {
376         int maxLength = -1;
377
378         for (int i = 0; i < sequences.size(); i++)
379         {
380             if (getSequenceAt(i).getLength() > maxLength)
381             {
382                 maxLength = getSequenceAt(i).getLength();
383             }
384         }
385
386         return maxLength;
387     }
388
389
390     /**
391      * DOCUMENT ME!
392      *
393      * @param gc DOCUMENT ME!
394      */
395     public void setGapCharacter(char gc)
396     {
397         gapCharacter = gc;
398
399         for (int i = 0; i < sequences.size(); i++)
400         {
401             Sequence seq = (Sequence) sequences.elementAt(i);
402             seq.setSequence( seq.getSequenceAsString().replace('.', gc) );
403             seq.setSequence( seq.getSequenceAsString().replace('-', gc) );
404             seq.setSequence( seq.getSequenceAsString().replace(' ', gc) );
405         }
406     }
407
408     /**
409      * DOCUMENT ME!
410      *
411      * @return DOCUMENT ME!
412      */
413     public char getGapCharacter()
414     {
415         return gapCharacter;
416     }
417
418
419     /**
420      * DOCUMENT ME!
421      *
422      * @return DOCUMENT ME!
423      */
424     public boolean isAligned()
425     {
426         int width = getWidth();
427
428         for (int i = 0; i < sequences.size(); i++)
429         {
430             if (getSequenceAt(i).getLength() != width)
431             {
432                 return false;
433             }
434         }
435
436         return true;
437     }
438
439     /**
440      * DOCUMENT ME!
441      *
442      * @param aa DOCUMENT ME!
443      */
444     public void deleteAnnotation(AlignmentAnnotation aa)
445     {
446         int aSize = 1;
447
448         if (annotations != null)
449         {
450             aSize = annotations.length;
451         }
452
453         if(aSize<1)
454           return;
455
456         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize - 1];
457
458         int tIndex = 0;
459
460         for (int i = 0; i < aSize; i++)
461         {
462             if (annotations[i] == aa)
463             {
464                 continue;
465             }
466
467             temp[tIndex] = annotations[i];
468             tIndex++;
469         }
470
471         annotations = temp;
472     }
473
474
475     public void adjustSequenceAnnotations()
476     {
477       if(annotations!=null)
478       {
479         for (int a = 0; a < annotations.length; a++)
480         {
481           if (annotations[a].sequenceRef != null)
482           {
483             annotations[a].adjustForAlignment();
484           }
485         }
486       }
487     }
488
489     /**
490      * DOCUMENT ME!
491      *
492      * @param aa DOCUMENT ME!
493      */
494     public void addAnnotation(AlignmentAnnotation aa)
495     {
496         int aSize = 1;
497         if (annotations != null)
498         {
499             aSize = annotations.length + 1;
500         }
501
502         AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];
503
504         temp[aSize-1] = aa;
505
506         int i = 0;
507
508         if (aSize > 1)
509         {
510             for (i = 0; i < (aSize-1); i++)
511             {
512                 temp[i] = annotations[i];
513             }
514         }
515
516         annotations = temp;
517     }
518
519     public void setAnnotationIndex(AlignmentAnnotation aa, int index)
520     {
521       if(aa==null || annotations==null || annotations.length-1<index)
522         return;
523
524       int aSize = annotations.length;
525       AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];
526
527       temp[index] = aa;
528
529       for (int i = 0; i < aSize; i++)
530       {
531         if(i==index)
532           continue;
533
534         if(i<index)
535           temp[i] = annotations[i];
536         else
537           temp[i] = annotations[i-1];
538       }
539
540         annotations = temp;
541     }
542
543     /**
544      * DOCUMENT ME!
545      *
546      * @return DOCUMENT ME!
547      */
548     public AlignmentAnnotation[] getAlignmentAnnotation()
549     {
550         return annotations;
551     }
552
553     public void setNucleotide(boolean b)
554     {
555       if(b)
556         type = NUCLEOTIDE;
557       else
558         type = PROTEIN;
559     }
560
561     public boolean isNucleotide()
562     {
563       if(type==NUCLEOTIDE)
564         return true;
565       else
566         return false;
567     }
568
569     public void setDataset(Alignment data)
570     {
571       if(dataset==null && data==null)
572       {
573         // Create a new dataset for this alignment.
574         // Can only be done once, if dataset is not null
575         // This will not be performed
576         Sequence[] seqs = new Sequence[getHeight()];
577         SequenceI currentSeq;
578         for (int i = 0; i < getHeight(); i++)
579         {
580           currentSeq = getSequenceAt(i);
581           if(currentSeq.getDatasetSequence()!=null)
582           {
583             seqs[i] = (Sequence)currentSeq.getDatasetSequence();
584           }
585           else
586           {
587             seqs[i] = new Sequence(currentSeq.getName(),
588                                    AlignSeq.extractGaps(
589                                        jalview.util.Comparison.GapChars,
590                                        currentSeq.getSequenceAsString()
591                                    ),
592                                    currentSeq.getStart(),
593                                    currentSeq.getEnd());
594             seqs[i].sequenceFeatures = currentSeq.getSequenceFeatures();
595             seqs[i].setDescription(currentSeq.getDescription());
596             getSequenceAt(i).setSequenceFeatures(null);
597             getSequenceAt(i).setDatasetSequence(seqs[i]);
598           }
599         }
600
601         dataset = new Alignment(seqs);
602       }
603       else if(dataset==null && data!=null)
604       {
605         dataset = data;
606       }
607     }
608
609     public Alignment getDataset()
610     {
611       return dataset;
612     }
613
614     public boolean padGaps()
615     {
616       boolean modified=false;
617
618       //Remove excess gaps from the end of alignment
619       int maxLength = -1;
620
621       SequenceI current;
622       for (int i = 0; i < sequences.size(); i++)
623       {
624         current = getSequenceAt(i);
625         for (int j = current.getLength(); j > maxLength; j--)
626         {
627           if (j > maxLength && !jalview.util.Comparison.isGap(
628               current.getCharAt(j)))
629           {
630             maxLength = j;
631             break;
632           }
633         }
634       }
635
636       maxLength++;
637
638       int cLength;
639       for (int i = 0; i < sequences.size();
640            i++)
641       {
642         current = getSequenceAt(i);
643         cLength = current.getLength();
644
645         if (cLength < maxLength)
646         {
647           current.insertCharAt(cLength,
648                               maxLength-cLength, gapCharacter);
649           modified=true;
650         }
651         else if(current.getLength() > maxLength)
652         {
653           current.deleteChars(maxLength, current.getLength());
654         }
655       }
656       return modified;
657     }
658
659     public HiddenSequences getHiddenSequences()
660     {
661       return hiddenSequences;
662     }
663     SequenceI [] getVisibleAndRepresentedSeqs()
664     {
665       if(hiddenSequences==null || hiddenSequences.getSize()<1)
666         return getSequencesArray();
667
668       Vector seqs = new Vector();
669       SequenceI seq;
670       SequenceGroup hidden;
671       for (int i = 0; i < sequences.size(); i++)
672       {
673         seq = (SequenceI) sequences.elementAt(i);
674         seqs.addElement(seq);
675         hidden = seq.getHiddenSequences();
676         if(hidden!=null)
677         {
678           for(int j=0; j<hidden.getSize(false); j++)
679           {
680             seqs.addElement(hidden.getSequenceAt(j));
681           }
682         }
683       }
684       SequenceI [] result = new SequenceI[seqs.size()];
685       for(int i=0; i<seqs.size(); i++)
686         result[i] = (SequenceI)seqs.elementAt(i);
687
688       return result;
689
690     }
691
692   public CigarArray getCompactAlignment()
693   {
694     SeqCigar alseqs[] = new SeqCigar[sequences.size()];
695     for (int i=0; i<sequences.size(); i++) {
696       alseqs[i] = new SeqCigar((SequenceI) sequences.elementAt(i));
697     }
698     CigarArray cal = new CigarArray(alseqs);
699     cal.addOperation(CigarArray.M, getWidth());
700     return cal;
701   }
702
703 }