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