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