Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.datamodel

File Alignment.java

 

Coverage histogram

../../img/srcFileCovDistChart7.png
28% of files have more coverage

Code metrics

328
583
92
1
2,013
1,454
289
0.5
6.34
92
3.14

Classes

Class Line # Actions
Alignment 50 583 289 355
0.6460618464.6%
 

Contributing tests

This file is covered by 398 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.datamodel;
22   
23    import jalview.analysis.AlignmentUtils;
24    import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
25    import jalview.io.FastaFile;
26    import jalview.util.Comparison;
27    import jalview.util.LinkedIdentityHashSet;
28    import jalview.util.MessageManager;
29   
30    import java.util.ArrayList;
31    import java.util.Arrays;
32    import java.util.BitSet;
33    import java.util.Collections;
34    import java.util.Enumeration;
35    import java.util.HashSet;
36    import java.util.Hashtable;
37    import java.util.Iterator;
38    import java.util.List;
39    import java.util.Map;
40    import java.util.Set;
41    import java.util.Vector;
42   
43    /**
44    * Data structure to hold and manipulate a multiple sequence alignment
45    */
46    /**
47    * @author JimP
48    *
49    */
 
50    public class Alignment implements AlignmentI
51    {
52    private Alignment dataset;
53   
54    private List<SequenceI> sequences;
55   
56    protected List<SequenceGroup> groups;
57   
58    protected char gapCharacter = '-';
59   
60    private boolean nucleotide = true;
61   
62    public boolean hasRNAStructure = false;
63   
64    public AlignmentAnnotation[] annotations;
65   
66    HiddenSequences hiddenSequences;
67   
68    HiddenColumns hiddenCols;
69   
70    public Hashtable alignmentProperties;
71   
72    private List<AlignedCodonFrame> codonFrameList;
73   
 
74  1211 toggle private void initAlignment(SequenceI[] seqs)
75    {
76  1211 groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
77  1211 hiddenSequences = new HiddenSequences(this);
78  1211 hiddenCols = new HiddenColumns();
79  1211 codonFrameList = new ArrayList<>();
80   
81  1211 nucleotide = Comparison.isNucleotide(seqs);
82   
83  1211 sequences = Collections.synchronizedList(new ArrayList<SequenceI>());
84   
85  30776 for (int i = 0; i < seqs.length; i++)
86    {
87  29565 sequences.add(seqs[i]);
88    }
89   
90    }
91   
92    /**
93    * Make a 'copy' alignment - sequences have new copies of features and
94    * annotations, but share the original dataset sequences.
95    */
 
96  4 toggle public Alignment(AlignmentI al)
97    {
98  4 SequenceI[] seqs = al.getSequencesArray();
99  19 for (int i = 0; i < seqs.length; i++)
100    {
101  15 seqs[i] = new Sequence(seqs[i]);
102    }
103   
104  4 initAlignment(seqs);
105   
106    /*
107    * Share the same dataset sequence mappings (if any).
108    */
109  4 if (dataset == null && al.getDataset() == null)
110    {
111  1 this.setCodonFrames(al.getCodonFrames());
112    }
113    }
114   
115    /**
116    * Make an alignment from an array of Sequences.
117    *
118    * @param sequences
119    */
 
120  1205 toggle public Alignment(SequenceI[] seqs)
121    {
122  1205 initAlignment(seqs);
123    }
124   
125    /**
126    * Make a new alignment from an array of SeqCigars
127    *
128    * @param seqs
129    * SeqCigar[]
130    */
 
131  2 toggle public Alignment(SeqCigar[] alseqs)
132    {
133  2 SequenceI[] seqs = SeqCigar.createAlignmentSequences(alseqs,
134    gapCharacter, new HiddenColumns(), null);
135  2 initAlignment(seqs);
136    }
137   
138    /**
139    * Make a new alignment from an CigarArray JBPNote - can only do this when
140    * compactAlignment does not contain hidden regions. JBPNote - must also check
141    * that compactAlignment resolves to a set of SeqCigars - or construct them
142    * appropriately.
143    *
144    * @param compactAlignment
145    * CigarArray
146    */
 
147  0 toggle public static AlignmentI createAlignment(CigarArray compactAlignment)
148    {
149  0 throw new Error(MessageManager
150    .getString("error.alignment_cigararray_not_implemented"));
151    // this(compactAlignment.refCigars);
152    }
153   
 
154  64102 toggle @Override
155    public List<SequenceI> getSequences()
156    {
157  64102 return sequences;
158    }
159   
 
160  12 toggle @Override
161    public List<SequenceI> getSequences(
162    Map<SequenceI, SequenceCollectionI> hiddenReps)
163    {
164    // TODO: in jalview 2.8 we don't do anything with hiddenreps - fix design to
165    // work on this.
166  12 return sequences;
167    }
168   
 
169  27154 toggle @Override
170    public SequenceI[] getSequencesArray()
171    {
172  27154 if (sequences == null)
173    {
174  0 return null;
175    }
176  27154 synchronized (sequences)
177    {
178  27154 return sequences.toArray(new SequenceI[sequences.size()]);
179    }
180    }
181   
182    /**
183    * Returns a map of lists of sequences keyed by sequence name.
184    *
185    * @return
186    */
 
187  0 toggle @Override
188    public Map<String, List<SequenceI>> getSequencesByName()
189    {
190  0 return AlignmentUtils.getSequencesByName(this);
191    }
192   
 
193  723331 toggle @Override
194    public SequenceI getSequenceAt(int i)
195    {
196  723331 synchronized (sequences)
197    {
198  723334 if (i > -1 && i < sequences.size())
199    {
200  723322 return sequences.get(i);
201    }
202    }
203   
204  12 return null;
205    }
206   
 
207  0 toggle @Override
208    public SequenceI getSequenceAtAbsoluteIndex(int i)
209    {
210  0 SequenceI seq = null;
211  0 if (getHiddenSequences().getSize() > 0)
212    {
213  0 seq = getHiddenSequences().getHiddenSequence(i);
214  0 if (seq == null)
215    {
216    // didn't find the sequence in the hidden sequences, get it from the
217    // alignment
218  0 int index = getHiddenSequences().findIndexWithoutHiddenSeqs(i);
219  0 seq = getSequenceAt(index);
220    }
221    }
222    else
223    {
224  0 seq = getSequenceAt(i);
225    }
226  0 return seq;
227    }
228   
229    /**
230    * Adds a sequence to the alignment. Recalculates maxLength and size. Note
231    * this currently does not recalculate whether or not the alignment is
232    * nucleotide, so mixed alignments may have undefined behaviour.
233    *
234    * @param snew
235    */
 
236  240 toggle @Override
237    public void addSequence(SequenceI snew)
238    {
239  240 if (dataset != null)
240    {
241   
242    // maintain dataset integrity
243  12 SequenceI dsseq = snew.getDatasetSequence();
244  12 if (dsseq == null)
245    {
246    // derive new sequence
247  5 SequenceI adding = snew.deriveSequence();
248  5 snew = adding;
249  5 dsseq = snew.getDatasetSequence();
250    }
251  12 if (getDataset().findIndex(dsseq) == -1)
252    {
253  11 getDataset().addSequence(dsseq);
254    }
255   
256    }
257  240 if (sequences == null)
258    {
259  0 initAlignment(new SequenceI[] { snew });
260    }
261    else
262    {
263  240 synchronized (sequences)
264    {
265  240 sequences.add(snew);
266    }
267    }
268  240 if (hiddenSequences != null)
269    {
270  240 hiddenSequences.adjustHeightSequenceAdded();
271    }
272    }
273   
 
274  0 toggle @Override
275    public SequenceI replaceSequenceAt(int i, SequenceI snew)
276    {
277  0 synchronized (sequences)
278    {
279  0 if (sequences.size() > i)
280    {
281  0 return sequences.set(i, snew);
282   
283    }
284    else
285    {
286  0 sequences.add(snew);
287  0 hiddenSequences.adjustHeightSequenceAdded();
288    }
289  0 return null;
290    }
291    }
292   
293    /**
294    * DOCUMENT ME!
295    *
296    * @return DOCUMENT ME!
297    */
 
298  4948 toggle @Override
299    public List<SequenceGroup> getGroups()
300    {
301  4948 return groups;
302    }
303   
 
304  977 toggle @Override
305    public void finalize() throws Throwable
306    {
307  977 if (getDataset() != null)
308    {
309  245 getDataset().removeAlignmentRef();
310    }
311   
312  977 nullReferences();
313  977 super.finalize();
314    }
315   
316    /**
317    * Defensively nulls out references in case this object is not garbage
318    * collected
319    */
 
320  1191 toggle void nullReferences()
321    {
322  1191 dataset = null;
323  1191 sequences = null;
324  1191 groups = null;
325  1191 annotations = null;
326  1191 hiddenSequences = null;
327    }
328   
329    /**
330    * decrement the alignmentRefs counter by one and null references if it goes
331    * to zero.
332    *
333    * @throws Throwable
334    */
 
335  245 toggle private void removeAlignmentRef() throws Throwable
336    {
337  245 if (--alignmentRefs == 0)
338    {
339  214 nullReferences();
340    }
341    }
342   
 
343  11 toggle @Override
344    public void deleteSequence(SequenceI s)
345    {
346  11 synchronized (sequences)
347    {
348  11 deleteSequence(findIndex(s));
349    }
350    }
351   
 
352  16 toggle @Override
353    public void deleteSequence(int i)
354    {
355  16 synchronized (sequences)
356    {
357  16 if (i > -1 && i < getHeight())
358    {
359  14 sequences.remove(i);
360  14 hiddenSequences.adjustHeightSequenceDeleted(i);
361    }
362    }
363    }
364   
 
365  616 toggle @Override
366    public void deleteHiddenSequence(int i)
367    {
368  616 synchronized (sequences)
369    {
370  616 if (i > -1 && i < getHeight())
371    {
372  616 sequences.remove(i);
373    }
374    }
375    }
376   
377    /*
378    * (non-Javadoc)
379    *
380    * @see jalview.datamodel.AlignmentI#findGroup(jalview.datamodel.SequenceI)
381    */
 
382  19 toggle @Override
383    public SequenceGroup findGroup(SequenceI seq, int position)
384    {
385  19 synchronized (groups)
386    {
387  19 for (SequenceGroup sg : groups)
388    {
389  23 if (sg.getSequences(null).contains(seq))
390    {
391  16 if (position >= sg.getStartRes() && position <= sg.getEndRes())
392    {
393  10 return sg;
394    }
395    }
396    }
397    }
398  9 return null;
399    }
400   
401    /*
402    * (non-Javadoc)
403    *
404    * @see
405    * jalview.datamodel.AlignmentI#findAllGroups(jalview.datamodel.SequenceI)
406    */
 
407  9508 toggle @Override
408    public SequenceGroup[] findAllGroups(SequenceI s)
409    {
410  9508 ArrayList<SequenceGroup> temp = new ArrayList<>();
411   
412  9508 synchronized (groups)
413    {
414  9508 int gSize = groups.size();
415  14824 for (int i = 0; i < gSize; i++)
416    {
417  5316 SequenceGroup sg = groups.get(i);
418  5316 if (sg == null || sg.getSequences() == null)
419    {
420  0 this.deleteGroup(sg);
421  0 gSize--;
422  0 continue;
423    }
424   
425  5316 if (sg.getSequences().contains(s))
426    {
427  4613 temp.add(sg);
428    }
429    }
430    }
431  9508 SequenceGroup[] ret = new SequenceGroup[temp.size()];
432  9508 return temp.toArray(ret);
433    }
434   
435    /** */
 
436  114 toggle @Override
437    public void addGroup(SequenceGroup sg)
438    {
439  114 synchronized (groups)
440    {
441  114 if (!groups.contains(sg))
442    {
443  105 if (hiddenSequences.getSize() > 0)
444    {
445  0 int i, iSize = sg.getSize();
446  0 for (i = 0; i < iSize; i++)
447    {
448  0 if (!sequences.contains(sg.getSequenceAt(i)))
449    {
450  0 sg.deleteSequence(sg.getSequenceAt(i), false);
451  0 iSize--;
452  0 i--;
453    }
454    }
455   
456  0 if (sg.getSize() < 1)
457    {
458  0 return;
459    }
460    }
461  105 sg.setContext(this, true);
462  105 groups.add(sg);
463    }
464    }
465    }
466   
467    /**
468    * remove any annotation that references gp
469    *
470    * @param gp
471    * (if null, removes all group associated annotation)
472    */
 
473  0 toggle private void removeAnnotationForGroup(SequenceGroup gp)
474    {
475  0 if (annotations == null || annotations.length == 0)
476    {
477  0 return;
478    }
479    // remove annotation very quickly
480  0 AlignmentAnnotation[] t,
481    todelete = new AlignmentAnnotation[annotations.length],
482    tokeep = new AlignmentAnnotation[annotations.length];
483  0 int i, p, k;
484  0 if (gp == null)
485    {
486  0 for (i = 0, p = 0, k = 0; i < annotations.length; i++)
487    {
488  0 if (annotations[i].groupRef != null)
489    {
490  0 todelete[p++] = annotations[i];
491    }
492    else
493    {
494  0 tokeep[k++] = annotations[i];
495    }
496    }
497    }
498    else
499    {
500  0 for (i = 0, p = 0, k = 0; i < annotations.length; i++)
501    {
502  0 if (annotations[i].groupRef == gp)
503    {
504  0 todelete[p++] = annotations[i];
505    }
506    else
507    {
508  0 tokeep[k++] = annotations[i];
509    }
510    }
511    }
512  0 if (p > 0)
513    {
514    // clear out the group associated annotation.
515  0 for (i = 0; i < p; i++)
516    {
517  0 unhookAnnotation(todelete[i]);
518  0 todelete[i] = null;
519    }
520  0 t = new AlignmentAnnotation[k];
521  0 for (i = 0; i < k; i++)
522    {
523  0 t[i] = tokeep[i];
524    }
525  0 annotations = t;
526    }
527    }
528   
 
529  0 toggle @Override
530    public void deleteAllGroups()
531    {
532  0 synchronized (groups)
533    {
534  0 if (annotations != null)
535    {
536  0 removeAnnotationForGroup(null);
537    }
538  0 for (SequenceGroup sg : groups)
539    {
540  0 sg.setContext(null, false);
541    }
542  0 groups.clear();
543    }
544    }
545   
546    /** */
 
547  0 toggle @Override
548    public void deleteGroup(SequenceGroup g)
549    {
550  0 synchronized (groups)
551    {
552  0 if (groups.contains(g))
553    {
554  0 removeAnnotationForGroup(g);
555  0 groups.remove(g);
556  0 g.setContext(null, false);
557    }
558    }
559    }
560   
561    /** */
 
562  283 toggle @Override
563    public SequenceI findName(String name)
564    {
565  283 return findName(name, false);
566    }
567   
568    /*
569    * (non-Javadoc)
570    *
571    * @see jalview.datamodel.AlignmentI#findName(java.lang.String, boolean)
572    */
 
573  969 toggle @Override
574    public SequenceI findName(String token, boolean b)
575    {
576  969 return findName(null, token, b);
577    }
578   
579    /*
580    * (non-Javadoc)
581    *
582    * @see jalview.datamodel.AlignmentI#findName(SequenceI, java.lang.String,
583    * boolean)
584    */
 
585  1498 toggle @Override
586    public SequenceI findName(SequenceI startAfter, String token, boolean b)
587    {
588   
589  1498 int i = 0;
590  1498 SequenceI sq = null;
591  1498 String sqname = null;
592  1498 if (startAfter != null)
593    {
594    // try to find the sequence in the alignment
595  529 boolean matched = false;
596  4762 while (i < sequences.size())
597    {
598  4747 if (getSequenceAt(i++) == startAfter)
599    {
600  514 matched = true;
601  514 break;
602    }
603    }
604  529 if (!matched)
605    {
606  15 i = 0;
607    }
608    }
609  12656 while (i < sequences.size())
610    {
611  12098 sq = getSequenceAt(i);
612  12098 sqname = sq.getName();
613  12098 if (sqname.equals(token) // exact match
614    || (b && // allow imperfect matches - case varies
615    (sqname.equalsIgnoreCase(token))))
616    {
617  940 return getSequenceAt(i);
618    }
619   
620  11158 i++;
621    }
622   
623  558 return null;
624    }
625   
 
626  11 toggle @Override
627    public SequenceI[] findSequenceMatch(String name)
628    {
629  11 Vector matches = new Vector();
630  11 int i = 0;
631   
632  64 while (i < sequences.size())
633    {
634  53 if (getSequenceAt(i).getName().equals(name))
635    {
636  5 matches.addElement(getSequenceAt(i));
637    }
638  53 i++;
639    }
640   
641  11 SequenceI[] result = new SequenceI[matches.size()];
642  16 for (i = 0; i < result.length; i++)
643    {
644  5 result[i] = (SequenceI) matches.elementAt(i);
645    }
646   
647  11 return result;
648   
649    }
650   
651    /*
652    * (non-Javadoc)
653    *
654    * @see jalview.datamodel.AlignmentI#findIndex(jalview.datamodel.SequenceI)
655    */
 
656  1446 toggle @Override
657    public int findIndex(SequenceI s)
658    {
659  1446 int i = 0;
660   
661  65711 while (i < sequences.size())
662    {
663  65492 if (s == getSequenceAt(i))
664    {
665  1227 return i;
666    }
667   
668  64265 i++;
669    }
670   
671  219 return -1;
672    }
673   
674    /*
675    * (non-Javadoc)
676    *
677    * @see
678    * jalview.datamodel.AlignmentI#findIndex(jalview.datamodel.SearchResults)
679    */
 
680  3 toggle @Override
681    public int findIndex(SearchResultsI results)
682    {
683  3 int i = 0;
684   
685  10 while (i < sequences.size())
686    {
687  8 if (results.involvesSequence(getSequenceAt(i)))
688    {
689  1 return i;
690    }
691  7 i++;
692    }
693  2 return -1;
694    }
695   
 
696  16085 toggle @Override
697    public int getHeight()
698    {
699  16085 return sequences.size();
700    }
701   
 
702  10 toggle @Override
703    public int getAbsoluteHeight()
704    {
705  10 return sequences.size() + getHiddenSequences().getSize();
706    }
707   
 
708  8180 toggle @Override
709    public int getWidth()
710    {
711  8180 int maxLength = -1;
712   
713  588469 for (int i = 0; i < sequences.size(); i++)
714    {
715  580289 maxLength = Math.max(maxLength, getSequenceAt(i).getLength());
716    }
717  8180 return maxLength;
718    }
719   
720    /**
721    * DOCUMENT ME!
722    *
723    * @param gc
724    * DOCUMENT ME!
725    */
 
726  270 toggle @Override
727    public void setGapCharacter(char gc)
728    {
729  270 gapCharacter = gc;
730  270 synchronized (sequences)
731    {
732  270 for (SequenceI seq : sequences)
733    {
734  2370 seq.setSequence(seq.getSequenceAsString().replace('.', gc)
735    .replace('-', gc).replace(' ', gc));
736    }
737    }
738    }
739   
740    /**
741    * DOCUMENT ME!
742    *
743    * @return DOCUMENT ME!
744    */
 
745  305 toggle @Override
746    public char getGapCharacter()
747    {
748  305 return gapCharacter;
749    }
750   
751    /*
752    * (non-Javadoc)
753    *
754    * @see jalview.datamodel.AlignmentI#isAligned()
755    */
 
756  0 toggle @Override
757    public boolean isAligned()
758    {
759  0 return isAligned(false);
760    }
761   
762    /*
763    * (non-Javadoc)
764    *
765    * @see jalview.datamodel.AlignmentI#isAligned(boolean)
766    */
 
767  0 toggle @Override
768    public boolean isAligned(boolean includeHidden)
769    {
770  0 int width = getWidth();
771  0 if (hiddenSequences == null || hiddenSequences.getSize() == 0)
772    {
773  0 includeHidden = true; // no hidden sequences to check against.
774    }
775  0 for (int i = 0; i < sequences.size(); i++)
776    {
777  0 if (includeHidden || !hiddenSequences.isHidden(getSequenceAt(i)))
778    {
779  0 if (getSequenceAt(i).getLength() != width)
780    {
781  0 return false;
782    }
783    }
784    }
785   
786  0 return true;
787    }
788   
 
789  0 toggle @Override
790    public boolean isHidden(int alignmentIndex)
791    {
792  0 return (getHiddenSequences().getHiddenSequence(alignmentIndex) != null);
793    }
794   
795    /**
796    * Delete all annotations, including auto-calculated if the flag is set true.
797    * Returns true if at least one annotation was deleted, else false.
798    *
799    * @param includingAutoCalculated
800    * @return
801    */
 
802  2 toggle @Override
803    public boolean deleteAllAnnotations(boolean includingAutoCalculated)
804    {
805  2 boolean result = false;
806  2 for (AlignmentAnnotation alan : getAlignmentAnnotation())
807    {
808  8 if (!alan.autoCalculated || includingAutoCalculated)
809    {
810  7 deleteAnnotation(alan);
811  7 result = true;
812    }
813    }
814  2 return result;
815    }
816   
817    /*
818    * (non-Javadoc)
819    *
820    * @seejalview.datamodel.AlignmentI#deleteAnnotation(jalview.datamodel.
821    * AlignmentAnnotation)
822    */
 
823  7 toggle @Override
824    public boolean deleteAnnotation(AlignmentAnnotation aa)
825    {
826  7 return deleteAnnotation(aa, true);
827    }
828   
 
829  128 toggle @Override
830    public boolean deleteAnnotation(AlignmentAnnotation aa, boolean unhook)
831    {
832  128 int aSize = 1;
833   
834  128 if (annotations != null)
835    {
836  128 aSize = annotations.length;
837    }
838   
839  128 if (aSize < 1)
840    {
841  0 return false;
842    }
843   
844  128 AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize - 1];
845   
846  128 boolean swap = false;
847  128 int tIndex = 0;
848   
849  1109 for (int i = 0; i < aSize; i++)
850    {
851  981 if (annotations[i] == aa)
852    {
853  128 swap = true;
854  128 continue;
855    }
856  853 if (tIndex < temp.length)
857    {
858  853 temp[tIndex++] = annotations[i];
859    }
860    }
861   
862  128 if (swap)
863    {
864  128 annotations = temp;
865  128 if (unhook)
866    {
867  7 unhookAnnotation(aa);
868    }
869    }
870  128 return swap;
871    }
872   
873    /**
874    * remove any object references associated with this annotation
875    *
876    * @param aa
877    */
 
878  7 toggle private void unhookAnnotation(AlignmentAnnotation aa)
879    {
880  7 if (aa.sequenceRef != null)
881    {
882  6 aa.sequenceRef.removeAlignmentAnnotation(aa);
883    }
884  7 if (aa.groupRef != null)
885    {
886    // probably need to do more here in the future (post 2.5.0)
887  0 aa.groupRef = null;
888    }
889    }
890   
891    /*
892    * (non-Javadoc)
893    *
894    * @seejalview.datamodel.AlignmentI#addAnnotation(jalview.datamodel.
895    * AlignmentAnnotation)
896    */
 
897  2037 toggle @Override
898    public void addAnnotation(AlignmentAnnotation aa)
899    {
900  2038 addAnnotation(aa, -1);
901    }
902   
903    /*
904    * (non-Javadoc)
905    *
906    * @seejalview.datamodel.AlignmentI#addAnnotation(jalview.datamodel.
907    * AlignmentAnnotation, int)
908    */
 
909  2194 toggle @Override
910    public void addAnnotation(AlignmentAnnotation aa, int pos)
911    {
912  2195 if (aa.getRNAStruc() != null)
913    {
914  398 hasRNAStructure = true;
915    }
916   
917  2195 int aSize = 1;
918  2195 if (annotations != null)
919    {
920  1890 aSize = annotations.length + 1;
921    }
922   
923  2195 AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];
924  2194 int i = 0;
925  2194 if (pos == -1 || pos >= aSize)
926    {
927  2038 temp[aSize - 1] = aa;
928    }
929    else
930    {
931  157 temp[pos] = aa;
932    }
933  2194 if (aSize > 1)
934    {
935  1884 int p = 0;
936  21007 for (i = 0; i < (aSize - 1); i++, p++)
937    {
938  19123 if (p == pos)
939    {
940  66 p++;
941    }
942  19123 if (p < temp.length)
943    {
944  19123 temp[p] = annotations[i];
945    }
946    }
947    }
948   
949  2195 annotations = temp;
950    }
951   
 
952  193 toggle @Override
953    public void setAnnotationIndex(AlignmentAnnotation aa, int index)
954    {
955  193 if (aa == null || annotations == null || annotations.length - 1 < index)
956    {
957  0 return;
958    }
959   
960  193 int aSize = annotations.length;
961  193 AlignmentAnnotation[] temp = new AlignmentAnnotation[aSize];
962   
963  193 temp[index] = aa;
964   
965  3139 for (int i = 0; i < aSize; i++)
966    {
967  2946 if (i == index)
968    {
969  193 continue;
970    }
971   
972  2753 if (i < index)
973    {
974  2633 temp[i] = annotations[i];
975    }
976    else
977    {
978  120 temp[i] = annotations[i - 1];
979    }
980    }
981   
982  193 annotations = temp;
983    }
984   
 
985  30531 toggle @Override
986    /**
987    * returns all annotation on the alignment
988    */
989    public AlignmentAnnotation[] getAlignmentAnnotation()
990    {
991  30530 return annotations;
992    }
993   
 
994  6225 toggle @Override
995    public boolean isNucleotide()
996    {
997  6225 return nucleotide;
998    }
999   
 
1000  514 toggle @Override
1001    public boolean hasRNAStructure()
1002    {
1003    // TODO can it happen that structure is removed from alignment?
1004  514 return hasRNAStructure;
1005    }
1006   
 
1007  356 toggle @Override
1008    public void setDataset(AlignmentI data)
1009    {
1010  356 if (dataset == null && data == null)
1011    {
1012  314 createDatasetAlignment();
1013    }
1014  42 else if (dataset == null && data != null)
1015    {
1016  27 if (data == this)
1017    {
1018  1 throw new IllegalArgumentException("Circular dataset reference");
1019    }
1020  26 if (!(data instanceof Alignment))
1021    {
1022  0 throw new Error(
1023    "Implementation Error: jalview.datamodel.Alignment does not yet support other implementations of AlignmentI as its dataset reference");
1024    }
1025  26 dataset = (Alignment) data;
1026  370 for (int i = 0; i < getHeight(); i++)
1027    {
1028  344 SequenceI currentSeq = getSequenceAt(i);
1029  344 SequenceI dsq = currentSeq.getDatasetSequence();
1030  344 if (dsq == null)
1031    {
1032  0 dsq = currentSeq.createDatasetSequence();
1033  0 dataset.addSequence(dsq);
1034    }
1035    else
1036    {
1037  344 while (dsq.getDatasetSequence() != null)
1038    {
1039  0 dsq = dsq.getDatasetSequence();
1040    }
1041  344 if (dataset.findIndex(dsq) == -1)
1042    {
1043  174 dataset.addSequence(dsq);
1044    }
1045    }
1046    }
1047    }
1048  355 dataset.addAlignmentRef();
1049    }
1050   
1051    /**
1052    * add dataset sequences to seq for currentSeq and any sequences it references
1053    */
 
1054  2313 toggle private void resolveAndAddDatasetSeq(SequenceI currentSeq,
1055    Set<SequenceI> seqs, boolean createDatasetSequence)
1056    {
1057  2313 SequenceI alignedSeq = currentSeq;
1058  2313 if (currentSeq.getDatasetSequence() != null)
1059    {
1060  1074 currentSeq = currentSeq.getDatasetSequence();
1061    }
1062    else
1063    {
1064  1239 if (createDatasetSequence)
1065    {
1066  1239 currentSeq = currentSeq.createDatasetSequence();
1067    }
1068    }
1069   
1070  2313 List<SequenceI> toProcess = new ArrayList<>();
1071  2313 toProcess.add(currentSeq);
1072  4632 while (toProcess.size() > 0)
1073    {
1074    // use a queue ?
1075  2319 SequenceI curDs = toProcess.remove(0);
1076   
1077  2319 if (!seqs.add(curDs))
1078    {
1079  108 continue;
1080    }
1081    // iterate over database references, making sure we add forward referenced
1082    // sequences
1083  2211 if (curDs.getDBRefs() != null)
1084    {
1085  696 for (DBRefEntry dbr : curDs.getDBRefs())
1086    {
1087  838 if (dbr.getMap() != null && dbr.getMap().getTo() != null)
1088    {
1089  6 if (dbr.getMap().getTo() == alignedSeq)
1090    {
1091    /*
1092    * update mapping to be to the newly created dataset sequence
1093    */
1094  2 dbr.getMap().setTo(currentSeq);
1095    }
1096  6 if (dbr.getMap().getTo().getDatasetSequence() != null)
1097    {
1098  0 throw new Error("Implementation error: Map.getTo() for dbref "
1099    + dbr + " from " + curDs.getName()
1100    + " is not a dataset sequence.");
1101    }
1102    // we recurse to add all forward references to dataset sequences via
1103    // DBRefs/etc
1104  6 toProcess.add(dbr.getMap().getTo());
1105    }
1106    }
1107    }
1108    }
1109    }
1110   
1111    /**
1112    * Creates a new dataset for this alignment. Can only be done once - if
1113    * dataset is not null this will not be performed.
1114    */
 
1115  328 toggle public void createDatasetAlignment()
1116    {
1117  328 if (dataset != null)
1118    {
1119  0 return;
1120    }
1121    // try to avoid using SequenceI.equals at this stage, it will be expensive
1122  328 Set<SequenceI> seqs = new LinkedIdentityHashSet<>();
1123   
1124  2641 for (int i = 0; i < getHeight(); i++)
1125    {
1126  2313 SequenceI currentSeq = getSequenceAt(i);
1127  2313 resolveAndAddDatasetSeq(currentSeq, seqs, true);
1128    }
1129   
1130    // verify all mappings are in dataset
1131  328 for (AlignedCodonFrame cf : codonFrameList)
1132    {
1133  3 for (SequenceToSequenceMapping ssm : cf.getMappings())
1134    {
1135  1 if (!seqs.contains(ssm.getFromSeq()))
1136    {
1137  0 resolveAndAddDatasetSeq(ssm.getFromSeq(), seqs, false);
1138    }
1139  1 if (!seqs.contains(ssm.getMapping().getTo()))
1140    {
1141  0 resolveAndAddDatasetSeq(ssm.getMapping().getTo(), seqs, false);
1142    }
1143    }
1144    }
1145    // finally construct dataset
1146  328 dataset = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
1147    // move mappings to the dataset alignment
1148  328 dataset.codonFrameList = this.codonFrameList;
1149  328 this.codonFrameList = null;
1150    }
1151   
1152    /**
1153    * reference count for number of alignments referencing this one.
1154    */
1155    int alignmentRefs = 0;
1156   
1157    /**
1158    * increase reference count to this alignment.
1159    */
 
1160  355 toggle private void addAlignmentRef()
1161    {
1162  355 alignmentRefs++;
1163    }
1164   
 
1165  2757 toggle @Override
1166    public Alignment getDataset()
1167    {
1168  2757 return dataset;
1169    }
1170   
 
1171  368 toggle @Override
1172    public boolean padGaps()
1173    {
1174  368 boolean modified = false;
1175   
1176    // Remove excess gaps from the end of alignment
1177  368 int maxLength = -1;
1178   
1179  368 SequenceI current;
1180  4818 for (int i = 0; i < sequences.size(); i++)
1181    {
1182  4450 current = getSequenceAt(i);
1183  11562 for (int j = current.getLength(); j > maxLength; j--)
1184    {
1185  7756 if (j > maxLength
1186    && !jalview.util.Comparison.isGap(current.getCharAt(j)))
1187    {
1188  644 maxLength = j;
1189  644 break;
1190    }
1191    }
1192    }
1193   
1194  368 maxLength++;
1195   
1196  368 int cLength;
1197  4818 for (int i = 0; i < sequences.size(); i++)
1198    {
1199  4450 current = getSequenceAt(i);
1200  4450 cLength = current.getLength();
1201   
1202  4450 if (cLength < maxLength)
1203    {
1204  115 current.insertCharAt(cLength, maxLength - cLength, gapCharacter);
1205  115 modified = true;
1206    }
1207  4335 else if (current.getLength() > maxLength)
1208    {
1209  94 current.deleteChars(maxLength, current.getLength());
1210    }
1211    }
1212  368 return modified;
1213    }
1214   
1215    /**
1216    * Justify the sequences to the left or right by deleting and inserting gaps
1217    * before the initial residue or after the terminal residue
1218    *
1219    * @param right
1220    * true if alignment padded to right, false to justify to left
1221    * @return true if alignment was changed
1222    */
 
1223  0 toggle @Override
1224    public boolean justify(boolean right)
1225    {
1226  0 boolean modified = false;
1227   
1228    // Remove excess gaps from the end of alignment
1229  0 int maxLength = -1;
1230  0 int ends[] = new int[sequences.size() * 2];
1231  0 SequenceI current;
1232  0 for (int i = 0; i < sequences.size(); i++)
1233    {
1234  0 current = getSequenceAt(i);
1235    // This should really be a sequence method
1236  0 ends[i * 2] = current.findIndex(current.getStart());
1237  0 ends[i * 2 + 1] = current
1238    .findIndex(current.getStart() + current.getLength());
1239  0 boolean hitres = false;
1240  0 for (int j = 0, rs = 0, ssiz = current.getLength(); j < ssiz; j++)
1241    {
1242  0 if (!jalview.util.Comparison.isGap(current.getCharAt(j)))
1243    {
1244  0 if (!hitres)
1245    {
1246  0 ends[i * 2] = j;
1247  0 hitres = true;
1248    }
1249    else
1250    {
1251  0 ends[i * 2 + 1] = j;
1252  0 if (j - ends[i * 2] > maxLength)
1253    {
1254  0 maxLength = j - ends[i * 2];
1255    }
1256    }
1257    }
1258    }
1259    }
1260   
1261  0 maxLength++;
1262    // now edit the flanking gaps to justify to either left or right
1263  0 int cLength, extent, diff;
1264  0 for (int i = 0; i < sequences.size(); i++)
1265    {
1266  0 current = getSequenceAt(i);
1267   
1268  0 cLength = 1 + ends[i * 2 + 1] - ends[i * 2];
1269  0 diff = maxLength - cLength; // number of gaps to indent
1270  0 extent = current.getLength();
1271  0 if (right)
1272    {
1273    // right justify
1274  0 if (extent > ends[i * 2 + 1])
1275    {
1276  0 current.deleteChars(ends[i * 2 + 1] + 1, extent);
1277  0 modified = true;
1278    }
1279  0 if (ends[i * 2] > diff)
1280    {
1281  0 current.deleteChars(0, ends[i * 2] - diff);
1282  0 modified = true;
1283    }
1284    else
1285    {
1286  0 if (ends[i * 2] < diff)
1287    {
1288  0 current.insertCharAt(0, diff - ends[i * 2], gapCharacter);
1289  0 modified = true;
1290    }
1291    }
1292    }
1293    else
1294    {
1295    // left justify
1296  0 if (ends[i * 2] > 0)
1297    {
1298  0 current.deleteChars(0, ends[i * 2]);
1299  0 modified = true;
1300  0 ends[i * 2 + 1] -= ends[i * 2];
1301  0 extent -= ends[i * 2];
1302    }
1303  0 if (extent > maxLength)
1304    {
1305  0 current.deleteChars(maxLength + 1, extent);
1306  0 modified = true;
1307    }
1308    else
1309    {
1310  0 if (extent < maxLength)
1311    {
1312  0 current.insertCharAt(extent, maxLength - extent, gapCharacter);
1313  0 modified = true;
1314    }
1315    }
1316    }
1317    }
1318  0 return modified;
1319    }
1320   
 
1321  9833 toggle @Override
1322    public HiddenSequences getHiddenSequences()
1323    {
1324  9833 return hiddenSequences;
1325    }
1326   
 
1327  17485 toggle @Override
1328    public HiddenColumns getHiddenColumns()
1329    {
1330  17485 return hiddenCols;
1331    }
1332   
 
1333  0 toggle @Override
1334    public CigarArray getCompactAlignment()
1335    {
1336  0 synchronized (sequences)
1337    {
1338  0 SeqCigar alseqs[] = new SeqCigar[sequences.size()];
1339  0 int i = 0;
1340  0 for (SequenceI seq : sequences)
1341    {
1342  0 alseqs[i++] = new SeqCigar(seq);
1343    }
1344  0 CigarArray cal = new CigarArray(alseqs);
1345  0 cal.addOperation(CigarArray.M, getWidth());
1346  0 return cal;
1347    }
1348    }
1349   
 
1350  131 toggle @Override
1351    public void setProperty(Object key, Object value)
1352    {
1353  131 if (alignmentProperties == null)
1354    {
1355  9 alignmentProperties = new Hashtable();
1356    }
1357   
1358  131 alignmentProperties.put(key, value);
1359    }
1360   
 
1361  0 toggle @Override
1362    public Object getProperty(Object key)
1363    {
1364  0 if (alignmentProperties != null)
1365    {
1366  0 return alignmentProperties.get(key);
1367    }
1368    else
1369    {
1370  0 return null;
1371    }
1372    }
1373   
 
1374  350 toggle @Override
1375    public Hashtable getProperties()
1376    {
1377  350 return alignmentProperties;
1378    }
1379   
1380    /**
1381    * Adds the given mapping to the stored set. Note this may be held on the
1382    * dataset alignment.
1383    */
 
1384  80 toggle @Override
1385    public void addCodonFrame(AlignedCodonFrame codons)
1386    {
1387  80 List<AlignedCodonFrame> acfs = getCodonFrames();
1388  80 if (codons != null && acfs != null && !acfs.contains(codons))
1389    {
1390  77 acfs.add(codons);
1391    }
1392    }
1393   
1394    /*
1395    * (non-Javadoc)
1396    *
1397    * @see
1398    * jalview.datamodel.AlignmentI#getCodonFrame(jalview.datamodel.SequenceI)
1399    */
 
1400  49 toggle @Override
1401    public List<AlignedCodonFrame> getCodonFrame(SequenceI seq)
1402    {
1403  49 if (seq == null)
1404    {
1405  0 return null;
1406    }
1407  49 List<AlignedCodonFrame> cframes = new ArrayList<>();
1408  49 for (AlignedCodonFrame acf : getCodonFrames())
1409    {
1410  103 if (acf.involvesSequence(seq))
1411    {
1412  44 cframes.add(acf);
1413    }
1414    }
1415  49 return cframes;
1416    }
1417   
1418    /**
1419    * Sets the codon frame mappings (replacing any existing mappings). Note the
1420    * mappings are set on the dataset alignment instead if there is one.
1421    *
1422    * @see jalview.datamodel.AlignmentI#setCodonFrames()
1423    */
 
1424  37 toggle @Override
1425    public void setCodonFrames(List<AlignedCodonFrame> acfs)
1426    {
1427  37 if (dataset != null)
1428    {
1429  17 dataset.setCodonFrames(acfs);
1430    }
1431    else
1432    {
1433  20 this.codonFrameList = acfs;
1434    }
1435    }
1436   
1437    /**
1438    * Returns the set of codon frame mappings. Any changes to the returned set
1439    * will affect the alignment. The mappings are held on (and read from) the
1440    * dataset alignment if there is one.
1441    *
1442    * @see jalview.datamodel.AlignmentI#getCodonFrames()
1443    */
 
1444  3404 toggle @Override
1445    public List<AlignedCodonFrame> getCodonFrames()
1446    {
1447    // TODO: Fix this method to fix failing AlignedCodonFrame tests
1448    // this behaviour is currently incorrect. method should return codon frames
1449    // for just the alignment,
1450    // selected from dataset
1451  3404 return dataset != null ? dataset.getCodonFrames() : codonFrameList;
1452    }
1453   
1454    /**
1455    * Removes the given mapping from the stored set. Note that the mappings are
1456    * held on the dataset alignment if there is one.
1457    */
 
1458  0 toggle @Override
1459    public boolean removeCodonFrame(AlignedCodonFrame codons)
1460    {
1461  0 List<AlignedCodonFrame> acfs = getCodonFrames();
1462  0 if (codons == null || acfs == null)
1463    {
1464  0 return false;
1465    }
1466  0 return acfs.remove(codons);
1467    }
1468   
 
1469  1 toggle @Override
1470    public void append(AlignmentI toappend)
1471    {
1472    // TODO JAL-1270 needs test coverage
1473    // currently tested for use in jalview.gui.SequenceFetcher
1474  1 char oldc = toappend.getGapCharacter();
1475  1 boolean samegap = oldc == getGapCharacter();
1476  1 boolean hashidden = toappend.getHiddenSequences() != null
1477    && toappend.getHiddenSequences().hiddenSequences != null;
1478    // get all sequences including any hidden ones
1479  1 List<SequenceI> sqs = (hashidden)
1480    ? toappend.getHiddenSequences().getFullAlignment()
1481    .getSequences()
1482    : toappend.getSequences();
1483  1 if (sqs != null)
1484    {
1485    // avoid self append deadlock by
1486  1 List<SequenceI> toappendsq = new ArrayList<>();
1487  1 synchronized (sqs)
1488    {
1489  1 for (SequenceI addedsq : sqs)
1490    {
1491  1 if (!samegap)
1492    {
1493  1 addedsq.replace(oldc, gapCharacter);
1494    }
1495  1 toappendsq.add(addedsq);
1496    }
1497    }
1498  1 for (SequenceI addedsq : toappendsq)
1499    {
1500  1 addSequence(addedsq);
1501    }
1502    }
1503  1 AlignmentAnnotation[] alan = toappend.getAlignmentAnnotation();
1504  1 for (int a = 0; alan != null && a < alan.length; a++)
1505    {
1506  0 addAnnotation(alan[a]);
1507    }
1508   
1509    // use add method
1510  1 getCodonFrames().addAll(toappend.getCodonFrames());
1511   
1512  1 List<SequenceGroup> sg = toappend.getGroups();
1513  1 if (sg != null)
1514    {
1515  1 for (SequenceGroup _sg : sg)
1516    {
1517  0 addGroup(_sg);
1518    }
1519    }
1520  1 if (toappend.getHiddenSequences() != null)
1521    {
1522  1 HiddenSequences hs = toappend.getHiddenSequences();
1523  1 if (hiddenSequences == null)
1524    {
1525  0 hiddenSequences = new HiddenSequences(this);
1526    }
1527  1 if (hs.hiddenSequences != null)
1528    {
1529  0 for (int s = 0; s < hs.hiddenSequences.length; s++)
1530    {
1531    // hide the newly appended sequence in the alignment
1532  0 if (hs.hiddenSequences[s] != null)
1533    {
1534  0 hiddenSequences.hideSequence(hs.hiddenSequences[s]);
1535    }
1536    }
1537    }
1538    }
1539  1 if (toappend.getProperties() != null)
1540    {
1541    // we really can't do very much here - just try to concatenate strings
1542    // where property collisions occur.
1543  0 Enumeration key = toappend.getProperties().keys();
1544  0 while (key.hasMoreElements())
1545    {
1546  0 Object k = key.nextElement();
1547  0 Object ourval = this.getProperty(k);
1548  0 Object toapprop = toappend.getProperty(k);
1549  0 if (ourval != null)
1550    {
1551  0 if (ourval.getClass().equals(toapprop.getClass())
1552    && !ourval.equals(toapprop))
1553    {
1554  0 if (ourval instanceof String)
1555    {
1556    // append strings
1557  0 this.setProperty(k,
1558    ((String) ourval) + "; " + ((String) toapprop));
1559    }
1560    else
1561    {
1562  0 if (ourval instanceof Vector)
1563    {
1564    // append vectors
1565  0 Enumeration theirv = ((Vector) toapprop).elements();
1566  0 while (theirv.hasMoreElements())
1567    {
1568  0 ((Vector) ourval).addElement(theirv);
1569    }
1570    }
1571    }
1572    }
1573    }
1574    else
1575    {
1576    // just add new property directly
1577  0 setProperty(k, toapprop);
1578    }
1579   
1580    }
1581    }
1582    }
1583   
 
1584  19 toggle @Override
1585    public AlignmentAnnotation findOrCreateAnnotation(String name,
1586    String calcId, boolean autoCalc, SequenceI seqRef,
1587    SequenceGroup groupRef)
1588    {
1589  19 if (annotations != null)
1590    {
1591  18 for (AlignmentAnnotation annot : getAlignmentAnnotation())
1592    {
1593  192 if (annot.autoCalculated == autoCalc && (name.equals(annot.label))
1594    && (calcId == null || annot.getCalcId().equals(calcId))
1595    && annot.sequenceRef == seqRef
1596    && annot.groupRef == groupRef)
1597    {
1598  0 return annot;
1599    }
1600    }
1601    }
1602  19 AlignmentAnnotation annot = new AlignmentAnnotation(name, name,
1603    new Annotation[1], 0f, 0f, AlignmentAnnotation.BAR_GRAPH);
1604  19 annot.hasText = false;
1605  19 if (calcId != null)
1606    {
1607  18 annot.setCalcId(new String(calcId));
1608    }
1609  19 annot.autoCalculated = autoCalc;
1610  19 if (seqRef != null)
1611    {
1612  16 annot.setSequenceRef(seqRef);
1613    }
1614  19 annot.groupRef = groupRef;
1615  19 addAnnotation(annot);
1616   
1617  18 return annot;
1618    }
1619   
 
1620  230 toggle @Override
1621    public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
1622    {
1623  230 AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation();
1624  230 if (alignmentAnnotation != null)
1625    {
1626  223 return AlignmentAnnotation.findAnnotation(
1627    Arrays.asList(getAlignmentAnnotation()), calcId);
1628    }
1629  7 return Arrays.asList(new AlignmentAnnotation[] {});
1630    }
1631   
 
1632  17 toggle @Override
1633    public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
1634    String calcId, String label)
1635    {
1636  17 return AlignmentAnnotation.findAnnotations(
1637    Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
1638    }
1639   
 
1640  0 toggle @Override
1641    public void moveSelectedSequencesByOne(SequenceGroup sg,
1642    Map<SequenceI, SequenceCollectionI> map, boolean up)
1643    {
1644  0 synchronized (sequences)
1645    {
1646  0 if (up)
1647    {
1648   
1649  0 for (int i = 1, iSize = sequences.size(); i < iSize; i++)
1650    {
1651  0 SequenceI seq = sequences.get(i);
1652  0 if (!sg.getSequences(map).contains(seq))
1653    {
1654  0 continue;
1655    }
1656   
1657  0 SequenceI temp = sequences.get(i - 1);
1658  0 if (sg.getSequences(null).contains(temp))
1659    {
1660  0 continue;
1661    }
1662   
1663  0 sequences.set(i, temp);
1664  0 sequences.set(i - 1, seq);
1665    }
1666    }
1667    else
1668    {
1669  0 for (int i = sequences.size() - 2; i > -1; i--)
1670    {
1671  0 SequenceI seq = sequences.get(i);
1672  0 if (!sg.getSequences(map).contains(seq))
1673    {
1674  0 continue;
1675    }
1676   
1677  0 SequenceI temp = sequences.get(i + 1);
1678  0 if (sg.getSequences(map).contains(temp))
1679    {
1680  0 continue;
1681    }
1682   
1683  0 sequences.set(i, temp);
1684  0 sequences.set(i + 1, seq);
1685    }
1686    }
1687   
1688    }
1689    }
1690   
 
1691  0 toggle @Override
1692    public void validateAnnotation(AlignmentAnnotation alignmentAnnotation)
1693    {
1694  0 alignmentAnnotation.validateRangeAndDisplay();
1695  0 if (isNucleotide() && alignmentAnnotation.isValidStruc())
1696    {
1697  0 hasRNAStructure = true;
1698    }
1699    }
1700   
1701    private SequenceI seqrep = null;
1702   
1703    /**
1704    *
1705    * @return the representative sequence for this group
1706    */
 
1707  13447 toggle @Override
1708    public SequenceI getSeqrep()
1709    {
1710  13447 return seqrep;
1711    }
1712   
1713    /**
1714    * set the representative sequence for this group. Note - this affects the
1715    * interpretation of the Hidereps attribute.
1716    *
1717    * @param seqrep
1718    * the seqrep to set (null means no sequence representative)
1719    */
 
1720  280 toggle @Override
1721    public void setSeqrep(SequenceI seqrep)
1722    {
1723  280 this.seqrep = seqrep;
1724    }
1725   
1726    /**
1727    *
1728    * @return true if group has a sequence representative
1729    */
 
1730  7380 toggle @Override
1731    public boolean hasSeqrep()
1732    {
1733  7380 return seqrep != null;
1734    }
1735   
 
1736  19 toggle @Override
1737    public int getEndRes()
1738    {
1739  19 return getWidth() - 1;
1740    }
1741   
 
1742  19 toggle @Override
1743    public int getStartRes()
1744    {
1745  19 return 0;
1746    }
1747   
1748    /*
1749    * In the case of AlignmentI - returns the dataset for the alignment, if set
1750    * (non-Javadoc)
1751    *
1752    * @see jalview.datamodel.AnnotatedCollectionI#getContext()
1753    */
 
1754  468 toggle @Override
1755    public AnnotatedCollectionI getContext()
1756    {
1757  468 return dataset;
1758    }
1759   
1760    /**
1761    * Align this alignment like the given (mapped) one.
1762    */
 
1763  0 toggle @Override
1764    public int alignAs(AlignmentI al)
1765    {
1766    /*
1767    * Currently retains unmapped gaps (in introns), regaps mapped regions
1768    * (exons)
1769    */
1770  0 return alignAs(al, false, true);
1771    }
1772   
1773    /**
1774    * Align this alignment 'the same as' the given one. Mapped sequences only are
1775    * realigned. If both of the same type (nucleotide/protein) then align both
1776    * identically. If this is nucleotide and the other is protein, make 3 gaps
1777    * for each gap in the protein sequences. If this is protein and the other is
1778    * nucleotide, insert a gap for each 3 gaps (or part thereof) between
1779    * nucleotide bases. If this is protein and the other is nucleotide, gaps
1780    * protein to match the relative ordering of codons in the nucleotide.
1781    *
1782    * Parameters control whether gaps in exon (mapped) and intron (unmapped)
1783    * regions are preserved. Gaps that connect introns to exons are treated
1784    * conservatively, i.e. only preserved if both intron and exon gaps are
1785    * preserved. TODO: check caveats below where the implementation fails
1786    *
1787    * @param al
1788    * - must have same dataset, and sequences in al must have equivalent
1789    * dataset sequence and start/end bounds under given mapping
1790    * @param preserveMappedGaps
1791    * if true, gaps within and between mapped codons are preserved
1792    * @param preserveUnmappedGaps
1793    * if true, gaps within and between unmapped codons are preserved
1794    */
1795    // @Override
 
1796  6 toggle public int alignAs(AlignmentI al, boolean preserveMappedGaps,
1797    boolean preserveUnmappedGaps)
1798    {
1799    // TODO should this method signature be the one in the interface?
1800    // JBPComment - yes - neither flag is used, so should be deleted.
1801  6 boolean thisIsNucleotide = this.isNucleotide();
1802  6 boolean thatIsProtein = !al.isNucleotide();
1803  6 if (!thatIsProtein && !thisIsNucleotide)
1804    {
1805  1 return AlignmentUtils.alignProteinAsDna(this, al);
1806    }
1807  5 else if (thatIsProtein && thisIsNucleotide)
1808    {
1809  4 return AlignmentUtils.alignCdsAsProtein(this, al);
1810    }
1811  1 return AlignmentUtils.alignAs(this, al);
1812    }
1813   
1814    /**
1815    * Returns the alignment in Fasta format. Behaviour of this method is not
1816    * guaranteed between versions.
1817    */
 
1818  2 toggle @Override
1819    public String toString()
1820    {
1821  2 return new FastaFile().print(getSequencesArray(), true);
1822    }
1823   
1824    /**
1825    * Returns the set of distinct sequence names. No ordering is guaranteed.
1826    */
 
1827  0 toggle @Override
1828    public Set<String> getSequenceNames()
1829    {
1830  0 Set<String> names = new HashSet<>();
1831  0 for (SequenceI seq : getSequences())
1832    {
1833  0 names.add(seq.getName());
1834    }
1835  0 return names;
1836    }
1837   
 
1838  71 toggle @Override
1839    public boolean hasValidSequence()
1840    {
1841  71 boolean hasValidSeq = false;
1842  71 for (SequenceI seq : getSequences())
1843    {
1844  71 if ((seq.getEnd() - seq.getStart()) > 0)
1845    {
1846  71 hasValidSeq = true;
1847  71 break;
1848    }
1849    }
1850  71 return hasValidSeq;
1851    }
1852   
1853    /**
1854    * Update any mappings to 'virtual' sequences to compatible real ones, if
1855    * present in the added sequences. Returns a count of mappings updated.
1856    *
1857    * @param seqs
1858    * @return
1859    */
 
1860  1 toggle @Override
1861    public int realiseMappings(List<SequenceI> seqs)
1862    {
1863  1 int count = 0;
1864  1 for (SequenceI seq : seqs)
1865    {
1866  4 for (AlignedCodonFrame mapping : getCodonFrames())
1867    {
1868  0 count += mapping.realiseWith(seq);
1869    }
1870    }
1871  1 return count;
1872    }
1873   
1874    /**
1875    * Returns the first AlignedCodonFrame that has a mapping between the given
1876    * dataset sequences
1877    *
1878    * @param mapFrom
1879    * @param mapTo
1880    * @return
1881    */
 
1882  16 toggle @Override
1883    public AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo)
1884    {
1885  16 for (AlignedCodonFrame acf : getCodonFrames())
1886    {
1887  2 if (acf.getAaForDnaSeq(mapFrom) == mapTo)
1888    {
1889  1 return acf;
1890    }
1891    }
1892  15 return null;
1893    }
1894   
 
1895  30 toggle @Override
1896    public void setHiddenColumns(HiddenColumns cols)
1897    {
1898  30 hiddenCols = cols;
1899    }
1900   
 
1901  0 toggle @Override
1902    public void setupJPredAlignment()
1903    {
1904  0 SequenceI repseq = getSequenceAt(0);
1905  0 setSeqrep(repseq);
1906  0 HiddenColumns cs = new HiddenColumns();
1907  0 cs.hideList(repseq.getInsertions());
1908  0 setHiddenColumns(cs);
1909    }
1910   
 
1911  2 toggle @Override
1912    public HiddenColumns propagateInsertions(SequenceI profileseq,
1913    AlignmentView input)
1914    {
1915  2 int profsqpos = 0;
1916   
1917  2 char gc = getGapCharacter();
1918  2 Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc);
1919  2 HiddenColumns nview = (HiddenColumns) alandhidden[1];
1920  2 SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos];
1921  2 return propagateInsertions(profileseq, origseq, nview);
1922    }
1923   
1924    /**
1925    *
1926    * @param profileseq
1927    * sequence in al which corresponds to origseq
1928    * @param al
1929    * alignment which is to have gaps inserted into it
1930    * @param origseq
1931    * sequence corresponding to profileseq which defines gap map for
1932    * modifying al
1933    */
 
1934  2 toggle private HiddenColumns propagateInsertions(SequenceI profileseq,
1935    SequenceI origseq, HiddenColumns hc)
1936    {
1937    // take the set of hidden columns, and the set of gaps in origseq,
1938    // and remove all the hidden gaps from hiddenColumns
1939   
1940    // first get the gaps as a Bitset
1941    // then calculate hidden ^ not(gap)
1942  2 BitSet gaps = origseq.gapBitset();
1943  2 hc.andNot(gaps);
1944   
1945    // for each sequence in the alignment, except the profile sequence,
1946    // insert gaps corresponding to each hidden region but where each hidden
1947    // column region is shifted backwards by the number of preceding visible
1948    // gaps update hidden columns at the same time
1949  2 HiddenColumns newhidden = new HiddenColumns();
1950   
1951  2 int numGapsBefore = 0;
1952  2 int gapPosition = 0;
1953  2 Iterator<int[]> it = hc.iterator();
1954  4 while (it.hasNext())
1955    {
1956  2 int[] region = it.next();
1957   
1958    // get region coordinates accounting for gaps
1959    // we can rely on gaps not being *in* hidden regions because we already
1960    // removed those
1961  26 while (gapPosition < region[0])
1962    {
1963  24 gapPosition++;
1964  24 if (gaps.get(gapPosition))
1965    {
1966  8 numGapsBefore++;
1967    }
1968    }
1969   
1970  2 int left = region[0] - numGapsBefore;
1971  2 int right = region[1] - numGapsBefore;
1972   
1973  2 newhidden.hideColumns(left, right);
1974  2 padGaps(left, right, profileseq);
1975    }
1976  2 return newhidden;
1977    }
1978   
1979    /**
1980    * Pad gaps in all sequences in alignment except profileseq
1981    *
1982    * @param left
1983    * position of first gap to insert
1984    * @param right
1985    * position of last gap to insert
1986    * @param profileseq
1987    * sequence not to pad
1988    */
 
1989  2 toggle private void padGaps(int left, int right, SequenceI profileseq)
1990    {
1991  2 char gc = getGapCharacter();
1992   
1993    // make a string with number of gaps = length of hidden region
1994  2 StringBuilder sb = new StringBuilder();
1995  7 for (int g = 0; g < right - left + 1; g++)
1996    {
1997  5 sb.append(gc);
1998    }
1999   
2000    // loop over the sequences and pad with gaps where required
2001  22 for (int s = 0, ns = getHeight(); s < ns; s++)
2002    {
2003  20 SequenceI sqobj = getSequenceAt(s);
2004  20 if ((sqobj != profileseq) && (sqobj.getLength() >= left))
2005    {
2006  15 String sq = sqobj.getSequenceAsString();
2007  15 sqobj.setSequence(
2008    sq.substring(0, left) + sb.toString() + sq.substring(left));
2009    }
2010    }
2011    }
2012   
2013    }