header updated
[jalview.git] / src / jalview / datamodel / AlignmentView.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
23 /**
24  * <p>Title: </p>
25  *
26  * <p>Description: </p>
27  *
28  * <p>Copyright: Copyright (c) 2004</p>
29  *
30  * <p>Company: Dundee University</p>
31  *
32  * @author not attributable
33  * @version 1.0
34  */
35 public class AlignmentView
36 {
37     /**
38      * Transient object compactly representing a 'view' of an alignment - with discontinuities marked.
39      */
40     private SeqCigar[] sequences = null;
41   private int[] contigs = null;
42   private int width=0;
43   public AlignmentView(CigarArray seqcigararray)
44   {
45     if (!seqcigararray.isSeqCigarArray())
46       throw new Error("Implementation Error - can only make an alignment view from a CigarArray of sequences.");
47     //contigs = seqcigararray.applyDeletions();
48     contigs = seqcigararray.getDeletedRegions();
49     sequences = seqcigararray.getSeqCigarArray();
50     width = seqcigararray.getWidth(); // visible width
51   }
52
53   public void setSequences(SeqCigar[] sequences)
54   {
55     this.sequences = sequences;
56   }
57
58   public void setContigs(int[] contigs)
59   {
60     this.contigs = contigs;
61   }
62
63   public SeqCigar[] getSequences()
64   {
65     return sequences;
66   }
67
68   public int[] getContigs()
69   {
70     return contigs;
71   }
72   /**
73    * get the full alignment and a columnselection object marking the hidden regions
74    * @param gapCharacter char
75    * @return Object[] { SequenceI[], ColumnSelection}
76    */
77   public Object[] getAlignmentAndColumnSelection(char gapCharacter) {
78     ColumnSelection colsel = new ColumnSelection();
79
80     return new Object[] { SeqCigar.createAlignmentSequences(sequences, gapCharacter, colsel, contigs), colsel};
81   }
82   /**
83    * getSequenceStrings
84    *
85    * @param c char
86    * @return String[]
87    */
88   public String[] getSequenceStrings(char c)
89   {
90     String[] seqs=new String[sequences.length];
91     for (int n=0; n<sequences.length; n++) {
92       seqs[n] = sequences[n].getSequenceString(c);
93     }
94     return seqs;
95   }
96   /**
97    *
98    * @return visible number of columns in alignment view
99    */
100   public int getWidth() {
101     return width;
102   }
103
104   protected void setWidth(int width) {
105     this.width = width;
106   }
107   /**
108    * get the contiguous subalignments in an alignment view.
109    * @param gapCharacter char
110    * @return SequenceI[][]
111    */
112   public SequenceI[][] getVisibleContigs(char gapCharacter) {
113     SequenceI[][] smsa;
114     int njobs = 1;
115     if (sequences==null || width<=0)
116       return null;
117     if (contigs != null && contigs.length > 0)
118     {
119       int start = 0;
120       njobs = 0;
121       int fwidth = width;
122       for (int contig = 0; contig < contigs.length; contig += 3)
123       {
124         if ( (contigs[contig + 1] - start) > 0)
125         {
126           njobs++;
127         }
128         fwidth += contigs[contig + 2]; // end up with full region width (including hidden regions)
129         start = contigs[contig + 1] + contigs[contig + 2];
130       }
131       if (start < fwidth)
132       {
133         njobs++;
134       }
135       smsa = new SequenceI[njobs][];
136       start = 0;
137       int j = 0;
138       for (int contig = 0; contig < contigs.length; contig += 3)
139       {
140         if (contigs[contig + 1] - start > 0)
141         {
142           SequenceI mseq[] = new SequenceI[sequences.length];
143           for (int s = 0; s < mseq.length; s++)
144           {
145             mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,
146                 contigs[contig + 1]);
147           }
148           smsa[j] = mseq;
149           j++;
150         }
151         start = contigs[contig + 1] + contigs[contig + 2];
152       }
153       if (start < fwidth)
154       {
155         SequenceI mseq[] = new SequenceI[sequences.length];
156         for (int s = 0; s < mseq.length; s++)
157         {
158           mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,
159               fwidth + 1);
160         }
161         smsa[j] = mseq;
162         j++;
163       }
164     }
165     else
166     {
167       smsa = new SequenceI[1][];
168       smsa[0] = new SequenceI[sequences.length];
169       for (int s = 0; s < sequences.length; s++)
170       {
171         smsa[0][s] = sequences[s].getSeq(gapCharacter);
172       }
173     }
174     return smsa;
175   }
176   /**
177    * return full msa and hidden regions with visible blocks replaced with new sub alignments
178    * @param nvismsa SequenceI[][]
179    * @param orders AlignmentOrder[] corresponding to each SequenceI[] block.
180    * @return Object[]
181    */
182   public Object[] getUpdatedView(SequenceI[][] nvismsa, AlignmentOrder[] orders, char gapCharacter) {
183     if (sequences == null || width <= 0)
184     {
185       throw new Error("empty view cannot be updated.");
186     }
187     if (nvismsa == null)
188       throw new Error(
189           "nvismsa==null. use getAlignmentAndColumnSelection() instead.");
190     if (contigs != null && contigs.length > 0)
191     {
192       SequenceI[] alignment = new SequenceI[sequences.length];
193       ColumnSelection columnselection = new ColumnSelection();
194       if (contigs != null && contigs.length > 0)
195       {
196         int start = 0;
197         int nwidth = 0;
198         int owidth = width;
199         int j = 0;
200         for (int contig = 0; contig < contigs.length; contig += 3)
201         {
202           owidth += contigs[contig + 2]; // recover final column width
203           if (contigs[contig + 1] - start > 0)
204           {
205             int swidth = 0; // subalignment width
206             if (nvismsa[j] != null)
207             {
208               SequenceI mseq[] = nvismsa[j];
209               AlignmentOrder order=(orders==null) ? null : orders[j];
210               j++;
211               if (mseq.length!=sequences.length)
212                 throw new Error("Mismatch between number of sequences in block "+j+" ("+mseq.length+") and the original view ("+sequences.length+")");
213               swidth = mseq[0].getLength(); // JBPNote: could ensure padded here.
214               for (int s = 0; s < mseq.length; s++)
215               {
216                 if (alignment[s] == null)
217                 {
218                   alignment[s] = mseq[s];
219                 }
220                 else
221                 {
222                   alignment[s].setSequence(alignment[s].getSequence() +
223                                            mseq[s].getSequence());
224                   if (mseq[s].getStart() <= mseq[s].getEnd())
225                   {
226                     alignment[s].setEnd(mseq[s].getEnd());
227                   }
228                   if (order!=null) {
229                     order.updateSequence(mseq[s], alignment[s]);
230                   }
231                 }
232               }
233             }
234             else
235             {
236               // recover original alignment block or place gaps
237               if (true)
238               {
239                 // recover input data
240                 for (int s = 0; s < sequences.length; s++)
241                 {
242                   SequenceI oseq = sequences[s].getSeq(gapCharacter).getSubSequence(start,
243                       contigs[contig + 1]);
244                   if (swidth < oseq.getLength())
245                   {
246                     swidth = oseq.getLength();
247                   }
248                   if (alignment[s] == null)
249                   {
250                     alignment[s] = oseq;
251                   }
252                   else
253                   {
254                     alignment[s].setSequence(alignment[s].getSequence() +
255                                              oseq.getSequence());
256                     if (oseq.getEnd() >= oseq.getStart())
257                     {
258                       alignment[s].setEnd(oseq.getEnd());
259                     }
260                   }
261                 }
262
263               }
264               j++;
265             }
266             nwidth += swidth;
267           }
268           // advance to begining of visible region
269           start = contigs[contig + 1] + contigs[contig + 2];
270           // add hidden segment to right of next region
271           for (int s = 0; s < sequences.length; s++)
272           {
273             SequenceI hseq = sequences[s].getSeq(gapCharacter).getSubSequence(contigs[contig +
274                 1], start);
275             if (alignment[s] == null)
276             {
277               alignment[s] = hseq;
278             }
279             else
280             {
281               alignment[s].setSequence(alignment[s].getSequence() +
282                                        hseq.getSequence());
283               if (hseq.getEnd() >= hseq.getStart())
284               {
285                 alignment[s].setEnd(hseq.getEnd());
286               }
287             }
288           }
289           // mark hidden segment as hidden in the new alignment
290           columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
291           nwidth += contigs[contig + 2];
292         }
293         // Do final segment - if it exists
294         if (j < nvismsa.length)
295         {
296           int swidth = 0;
297           if (nvismsa[j] != null)
298           {
299             SequenceI mseq[] = nvismsa[j];
300             AlignmentOrder order = (orders!=null) ? orders[j] : null;
301             swidth = mseq[0].getLength();
302             for (int s = 0; s < mseq.length; s++)
303             {
304               if (alignment[s] == null)
305               {
306                 alignment[s] = mseq[s];
307               }
308               else
309               {
310                 alignment[s].setSequence(alignment[s].getSequence() +
311                                          mseq[s].getSequence());
312                 if (mseq[s].getEnd() >= mseq[s].getStart())
313                 {
314                   alignment[s].setEnd(mseq[s].getEnd());
315                 }
316                 if (order!=null) {
317                   order.updateSequence(mseq[s], alignment[s]);
318                 }
319               }
320             }
321           }
322           else
323           {
324             if (start < owidth)
325             {
326               // recover input data or place gaps
327               if (true)
328               {
329                 // recover input data
330                 for (int s = 0; s < sequences.length; s++)
331                 {
332                   SequenceI oseq = sequences[s].getSeq(gapCharacter).getSubSequence(start,
333                       owidth + 1);
334                   if (swidth < oseq.getLength())
335                   {
336                     swidth = oseq.getLength();
337                   }
338                   if (alignment[s] == null)
339                   {
340                     alignment[s] = oseq;
341                   }
342                   else
343                   {
344                     alignment[s].setSequence(alignment[s].getSequence() +
345                                              oseq.getSequence());
346                     if (oseq.getEnd() >= oseq.getStart())
347                     {
348                       alignment[s].setEnd(oseq.getEnd());
349                     }
350                   }
351                 }
352                 nwidth += swidth;
353               }
354               else
355               {
356                 // place gaps.
357                 throw new Error("Padding not yet implemented.");
358               }
359             }
360           }
361         }
362       }
363       return new Object[] { alignment, columnselection};
364     } else {
365       if (nvismsa.length!=1)
366         throw new Error("Mismatch between visible blocks to update and number of contigs in view (contigs=0,blocks="+nvismsa.length);
367       if (nvismsa[0]!=null)
368         return new Object[] { nvismsa[0], new ColumnSelection()};
369       else
370         return getAlignmentAndColumnSelection(gapCharacter);
371     }
372   }
373
374 }