Jalview 2.6 source licence
[jalview.git] / src / jalview / io / MSFfile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.io;
19
20 import java.io.*;
21 import java.util.*;
22
23 import jalview.datamodel.*;
24 import jalview.util.*;
25
26 /**
27  * DOCUMENT ME!
28  * 
29  * @author $author$
30  * @version $Revision$
31  */
32 public class MSFfile extends AlignFile
33 {
34
35   /**
36    * Creates a new MSFfile object.
37    */
38   public MSFfile()
39   {
40   }
41
42   /**
43    * Creates a new MSFfile object.
44    * 
45    * @param inFile
46    *          DOCUMENT ME!
47    * @param type
48    *          DOCUMENT ME!
49    * 
50    * @throws IOException
51    *           DOCUMENT ME!
52    */
53   public MSFfile(String inFile, String type) throws IOException
54   {
55     super(inFile, type);
56   }
57
58   public MSFfile(FileParse source) throws IOException
59   {
60     super(source);
61   }
62
63   {
64     // TODO Auto-generated constructor stub
65   }
66
67   /**
68    * DOCUMENT ME!
69    */
70   public void parse() throws IOException
71   {
72     int i = 0;
73     boolean seqFlag = false;
74     String key = new String();
75     Vector headers = new Vector();
76     Hashtable seqhash = new Hashtable();
77     String line;
78
79     try
80     {
81       while ((line = nextLine()) != null)
82       {
83         StringTokenizer str = new StringTokenizer(line);
84
85         while (str.hasMoreTokens())
86         {
87           String inStr = str.nextToken();
88
89           // If line has header information add to the headers vector
90           if (inStr.indexOf("Name:") != -1)
91           {
92             key = str.nextToken();
93             headers.addElement(key);
94           }
95
96           // if line has // set SeqFlag to 1 so we know sequences are coming
97           if (inStr.indexOf("//") != -1)
98           {
99             seqFlag = true;
100           }
101
102           // Process lines as sequence lines if seqFlag is set
103           if ((inStr.indexOf("//") == -1) && (seqFlag == true))
104           {
105             // seqeunce id is the first field
106             key = inStr;
107
108             StringBuffer tempseq;
109
110             // Get sequence from hash if it exists
111             if (seqhash.containsKey(key))
112             {
113               tempseq = (StringBuffer) seqhash.get(key);
114             }
115             else
116             {
117               tempseq = new StringBuffer();
118               seqhash.put(key, tempseq);
119             }
120
121             // loop through the rest of the words
122             while (str.hasMoreTokens())
123             {
124               // append the word to the sequence
125               tempseq.append(str.nextToken());
126             }
127           }
128         }
129       }
130     } catch (IOException e)
131     {
132       System.err.println("Exception parsing MSFFile " + e);
133       e.printStackTrace();
134     }
135
136     this.noSeqs = headers.size();
137
138     // Add sequences to the hash
139     for (i = 0; i < headers.size(); i++)
140     {
141       if (seqhash.get(headers.elementAt(i)) != null)
142       {
143         String head = headers.elementAt(i).toString();
144         String seq = seqhash.get(head).toString();
145
146         if (maxLength < head.length())
147         {
148           maxLength = head.length();
149         }
150
151         // Replace ~ with a sensible gap character
152         seq = seq.replace('~', '-');
153
154         Sequence newSeq = parseId(head);
155
156         newSeq.setSequence(seq);
157
158         seqs.addElement(newSeq);
159       }
160       else
161       {
162         System.err.println("MSFFile Parser: Can't find sequence for "
163                 + headers.elementAt(i));
164       }
165     }
166   }
167
168   /**
169    * DOCUMENT ME!
170    * 
171    * @param seq
172    *          DOCUMENT ME!
173    * 
174    * @return DOCUMENT ME!
175    */
176   public int checkSum(String seq)
177   {
178     int check = 0;
179     String sequence = seq.toUpperCase();
180
181     for (int i = 0; i < sequence.length(); i++)
182     {
183       try
184       {
185
186         int value = sequence.charAt(i);
187         if (value != -1)
188         {
189           check += (i % 57 + 1) * value;
190         }
191       } catch (Exception e)
192       {
193         System.err.println("Exception during MSF Checksum calculation");
194         e.printStackTrace();
195       }
196     }
197
198     return check % 10000;
199   }
200
201   /**
202    * DOCUMENT ME!
203    * 
204    * @param s
205    *          DOCUMENT ME!
206    * @param is_NA
207    *          DOCUMENT ME!
208    * 
209    * @return DOCUMENT ME!
210    */
211   public String print(SequenceI[] seqs)
212   {
213
214     boolean is_NA = jalview.util.Comparison.isNucleotide(seqs);
215
216     SequenceI[] s = new SequenceI[seqs.length];
217
218     StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA")
219             + "_MULTIPLE_ALIGNMENT 1.0\n\n"); // TODO: JBPNote : Jalview doesn't
220     // remember NA or AA yet.
221
222     int max = 0;
223     int maxid = 0;
224     int i = 0;
225
226     while ((i < seqs.length) && (seqs[i] != null))
227     {
228       // Replace all internal gaps with . and external spaces with ~
229       s[i] = new Sequence(seqs[i].getName(), seqs[i].getSequenceAsString()
230               .replace('-', '.'));
231
232       StringBuffer sb = new StringBuffer();
233       sb.append(s[i].getSequence());
234
235       for (int ii = 0; ii < sb.length(); ii++)
236       {
237         if (sb.charAt(ii) == '.')
238         {
239           sb.setCharAt(ii, '~');
240         }
241         else
242         {
243           break;
244         }
245       }
246
247       for (int ii = sb.length() - 1; ii > 0; ii--)
248       {
249         if (sb.charAt(ii) == '.')
250         {
251           sb.setCharAt(ii, '~');
252         }
253         else
254         {
255           break;
256         }
257       }
258
259       s[i].setSequence(sb.toString());
260
261       if (s[i].getSequence().length > max)
262       {
263         max = s[i].getSequence().length;
264       }
265
266       i++;
267     }
268
269     Format maxLenpad = new Format("%" + (new String("" + max)).length()
270             + "d");
271     Format maxChkpad = new Format("%" + (new String("1" + max)).length()
272             + "d");
273     i = 0;
274
275     int bigChecksum = 0;
276     int[] checksums = new int[s.length];
277     while (i < s.length)
278     {
279       checksums[i] = checkSum(s[i].getSequenceAsString());
280       bigChecksum += checksums[i];
281       i++;
282     }
283
284     long maxNB = 0;
285     out.append("   MSF: " + s[0].getSequence().length + "   Type: "
286             + (is_NA ? "N" : "P") + "    Check:  " + (bigChecksum % 10000)
287             + "   ..\n\n\n");
288
289     String[] nameBlock = new String[s.length];
290     String[] idBlock = new String[s.length];
291
292     i = 0;
293     while ((i < s.length) && (s[i] != null))
294     {
295
296       nameBlock[i] = new String("  Name: " + printId(s[i]) + " ");
297
298       idBlock[i] = new String("Len: "
299               + maxLenpad.form(s[i].getSequence().length) + "  Check: "
300               + maxChkpad.form(checksums[i]) + "  Weight: 1.00\n");
301
302       if (s[i].getName().length() > maxid)
303       {
304         maxid = s[i].getName().length();
305       }
306
307       if (nameBlock[i].length() > maxNB)
308       {
309         maxNB = nameBlock[i].length();
310       }
311
312       i++;
313     }
314
315     if (maxid < 10)
316     {
317       maxid = 10;
318     }
319
320     if (maxNB < 15)
321     {
322       maxNB = 15;
323     }
324
325     Format nbFormat = new Format("%-" + maxNB + "s");
326
327     for (i = 0; (i < s.length) && (s[i] != null); i++)
328     {
329       out.append(nbFormat.form(nameBlock[i]) + idBlock[i]);
330     }
331
332     maxid++;
333     out.append("\n\n//\n\n");
334
335     int len = 50;
336
337     int nochunks = (max / len) + 1;
338
339     if ((max % len) == 0)
340     {
341       nochunks--;
342     }
343
344     for (i = 0; i < nochunks; i++)
345     {
346       int j = 0;
347
348       while ((j < s.length) && (s[j] != null))
349       {
350         String name = printId(s[j]);
351
352         out.append(new Format("%-" + maxid + "s").form(name + " "));
353
354         for (int k = 0; k < 5; k++)
355         {
356           int start = (i * 50) + (k * 10);
357           int end = start + 10;
358
359           if ((end < s[j].getSequence().length)
360                   && (start < s[j].getSequence().length))
361           {
362             out.append(s[j].getSequence(start, end));
363
364             if (k < 4)
365             {
366               out.append(" ");
367             }
368             else
369             {
370               out.append("\n");
371             }
372           }
373           else
374           {
375             if (start < s[j].getSequence().length)
376             {
377               out.append(s[j].getSequenceAsString().substring(start));
378               out.append("\n");
379             }
380             else
381             {
382               if (k == 0)
383               {
384                 out.append("\n");
385               }
386             }
387           }
388         }
389
390         j++;
391       }
392
393       out.append("\n");
394     }
395
396     return out.toString();
397   }
398
399   /**
400    * DOCUMENT ME!
401    * 
402    * @return DOCUMENT ME!
403    */
404   public String print()
405   {
406     return print(getSeqsAsArray());
407   }
408 }