Formatted source
[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 public class MSFfile extends AlignFile {\r
31     private static com.stevesoft.pat.Regex gapre = new com.stevesoft.pat.Regex("\\~",\r
32             "-");\r
33     private static com.stevesoft.pat.Regex re2gap = new com.stevesoft.pat.Regex(\r
34             "[" + jalview.util.Comparison.GapChars + "]", "\\~");\r
35 \r
36     public MSFfile() {\r
37     }\r
38 \r
39     public MSFfile(String inStr) {\r
40         super(inStr);\r
41     }\r
42 \r
43     public MSFfile(String inFile, String type) throws IOException {\r
44         super(inFile, type);\r
45     }\r
46 \r
47     public void parse() {\r
48         int i = 0;\r
49         boolean seqFlag = false;\r
50         String key = new String();\r
51         Vector headers = new Vector();\r
52         Hashtable seqhash = new Hashtable();\r
53         String line;\r
54 \r
55         try {\r
56             while ((line = nextLine()) != null) {\r
57                 StringTokenizer str = new StringTokenizer(line);\r
58 \r
59                 while (str.hasMoreTokens()) {\r
60                     String inStr = str.nextToken();\r
61 \r
62                     //If line has header information add to the headers vector\r
63                     if (inStr.indexOf("Name:") != -1) {\r
64                         key = str.nextToken();\r
65                         headers.addElement(key);\r
66                     }\r
67 \r
68                     //if line has // set SeqFlag to 1 so we know sequences are coming\r
69                     if (inStr.indexOf("//") != -1) {\r
70                         seqFlag = true;\r
71                     }\r
72 \r
73                     //Process lines as sequence lines if seqFlag is set\r
74                     if ((inStr.indexOf("//") == -1) && (seqFlag == true)) {\r
75                         //seqeunce id is the first field\r
76                         key = inStr;\r
77 \r
78                         StringBuffer tempseq;\r
79 \r
80                         //Get sequence from hash if it exists\r
81                         if (seqhash.containsKey(key)) {\r
82                             tempseq = (StringBuffer) seqhash.get(key);\r
83                         } else {\r
84                             tempseq = new StringBuffer();\r
85                             seqhash.put(key, tempseq);\r
86                         }\r
87 \r
88                         //loop through the rest of the words\r
89                         while (str.hasMoreTokens()) {\r
90                             //append the word to the sequence\r
91                             tempseq.append(str.nextToken());\r
92                         }\r
93                     }\r
94                 }\r
95             }\r
96         } catch (IOException e) {\r
97             System.err.println("Exception parsing MSFFile " + e);\r
98             e.printStackTrace();\r
99         }\r
100 \r
101         this.noSeqs = headers.size();\r
102 \r
103         //Add sequences to the hash\r
104         for (i = 0; i < headers.size(); i++) {\r
105             if (seqhash.get(headers.elementAt(i)) != null) {\r
106                 String head = headers.elementAt(i).toString();\r
107                 String seq = seqhash.get(head).toString();\r
108 \r
109                 int start = 1;\r
110                 int end = seq.length();\r
111 \r
112                 if (maxLength < head.length()) {\r
113                     maxLength = head.length();\r
114                 }\r
115 \r
116                 if (head.indexOf("/") > 0) {\r
117                     StringTokenizer st = new StringTokenizer(head, "/");\r
118 \r
119                     if (st.countTokens() == 2) {\r
120                         head = st.nextToken();\r
121 \r
122                         String tmp = st.nextToken();\r
123                         st = new StringTokenizer(tmp, "-");\r
124 \r
125                         if (st.countTokens() == 2) {\r
126                             start = Integer.valueOf(st.nextToken()).intValue();\r
127                             end = Integer.valueOf(st.nextToken()).intValue();\r
128                         }\r
129                     }\r
130                 }\r
131 \r
132                 // Replace ~ with a sensible gap character\r
133                 seq = gapre.replaceAll(seq);\r
134 \r
135                 Sequence newSeq = new Sequence(head, seq, start, end);\r
136 \r
137                 seqs.addElement(newSeq);\r
138             } else {\r
139                 System.err.println("MSFFile Parser: Can't find sequence for " +\r
140                     headers.elementAt(i));\r
141             }\r
142         }\r
143     }\r
144 \r
145     public static int checkSum(String seq) {\r
146         //String chars =  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.*~&@";\r
147         int check = 0;\r
148 \r
149         String index = "--------------------------------------&---*---.-----------------@ABCDEFGHIJKLMNOPQRSTUVWXYZ------ABCDEFGHIJKLMNOPQRSTUVWXYZ----@";\r
150         index += "--------------------------------------------------------------------------------------------------------------------------------";\r
151 \r
152         for (int i = 0; i < seq.length(); i++) {\r
153             try {\r
154                 if (i < seq.length()) {\r
155                     int pos = index.indexOf(seq.substring(i, i + 1));\r
156 \r
157                     if (!index.substring(pos, pos + 1).equals("_")) {\r
158                         check += (((i % 57) + 1) * pos);\r
159                     }\r
160                 }\r
161             } catch (Exception e) {\r
162                 System.err.println("Exception during MSF Checksum calculation");\r
163                 e.printStackTrace();\r
164             }\r
165         }\r
166 \r
167         return check % 10000;\r
168     }\r
169 \r
170     public static String print(SequenceI[] s) {\r
171         return print(s, false);\r
172     }\r
173 \r
174     public static String print(SequenceI[] s, boolean is_NA) {\r
175         StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA") +\r
176                 "_MULTIPLE_ALIGNMENT 1.0\n\n"); // TODO: JBPNote : Jalview doesn't remember NA or AA yet.\r
177 \r
178         int max = 0;\r
179         int maxid = 0;\r
180         int i = 0;\r
181         String big = "";\r
182 \r
183         while ((i < s.length) && (s[i] != null)) {\r
184             String sq;\r
185             big += (sq = s[i].getSequence());\r
186 \r
187             if (sq.length() > max) {\r
188                 max = sq.length();\r
189             }\r
190 \r
191             i++;\r
192         }\r
193 \r
194         Format maxLenpad = new Format("%" + (new String("" + max)).length() +\r
195                 "d");\r
196         Format maxChkpad = new Format("%" + (new String("1" + max)).length() +\r
197                 "d");\r
198         i = 0;\r
199 \r
200         long bigcheck = checkSum(big);\r
201         long maxNB = 0;\r
202         out.append("   MSF: " + s[0].getSequence().length() + "   Type: " +\r
203             (is_NA ? "N" : "P") + "    Check:  " + bigcheck + "   ..\n\n\n");\r
204 \r
205         String[] nameBlock = new String[s.length];\r
206         String[] idBlock = new String[s.length];\r
207 \r
208         while ((i < s.length) && (s[i] != null)) {\r
209             String seq = s[i].getSequence();\r
210             String name = s[i].getName() + "/" + s[i].getStart() + "-" +\r
211                 s[i].getEnd();\r
212             int check = checkSum(s[i].getSequence());\r
213             nameBlock[i] = new String("  Name: " + name + " ");\r
214             idBlock[i] = new String("Len: " +\r
215                     maxLenpad.form(s[i].getSequence().length()) + "  Check:" +\r
216                     maxChkpad.form(check) + "  Weight: 1.00\n");\r
217 \r
218             if (name.length() > maxid) {\r
219                 maxid = name.length();\r
220             }\r
221 \r
222             if (nameBlock[i].length() > maxNB) {\r
223                 maxNB = nameBlock[i].length();\r
224             }\r
225 \r
226             i++;\r
227         }\r
228 \r
229         if (maxid < 10) {\r
230             maxid = 10;\r
231         }\r
232 \r
233         if (maxNB < 15) {\r
234             maxNB = 15;\r
235         }\r
236 \r
237         Format nbFormat = new Format("%-" + maxNB + "s");\r
238 \r
239         for (i = 0; (i < s.length) && (s[i] != null); i++) {\r
240             out.append(nbFormat.form(nameBlock[i]) + idBlock[i]);\r
241         }\r
242 \r
243         maxid++;\r
244         out.append("\n\n//\n\n");\r
245 \r
246         int len = 50;\r
247 \r
248         int nochunks = (max / len) + 1;\r
249 \r
250         if ((max % len) == 0) {\r
251             nochunks--;\r
252         }\r
253 \r
254         for (i = 0; i < nochunks; i++) {\r
255             int j = 0;\r
256 \r
257             while ((j < s.length) && (s[j] != null)) {\r
258                 String name = s[j].getName();\r
259                 out.append(new Format("%-" + maxid + "s").form(name + "/" +\r
260                         s[j].getStart() + "-" + s[j].getEnd()) + " ");\r
261 \r
262                 for (int k = 0; k < 5; k++) {\r
263                     int start = (i * 50) + (k * 10);\r
264                     int end = start + 10;\r
265 \r
266                     if ((end < s[j].getSequence().length()) &&\r
267                             (start < s[j].getSequence().length())) {\r
268                         out.append(re2gap.replaceAll(s[j].getSequence()\r
269                                                          .substring(start, end)));\r
270 \r
271                         if (k < 4) {\r
272                             // out.append(" ");\r
273                         } else {\r
274                             out.append("\n");\r
275                         }\r
276                     } else {\r
277                         if (start < s[j].getSequence().length()) {\r
278                             out.append(re2gap.replaceAll(\r
279                                     s[j].getSequence().substring(start)));\r
280                             out.append("\n");\r
281                         } else {\r
282                             if (k == 0) {\r
283                                 out.append("\n");\r
284                             }\r
285                         }\r
286                     }\r
287                 }\r
288 \r
289                 j++;\r
290             }\r
291 \r
292             out.append("\n");\r
293         }\r
294 \r
295         return out.toString();\r
296     }\r
297 \r
298     public String print() {\r
299         return print(getSeqsAsArray());\r
300     }\r
301 }\r