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