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