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