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