AnnotationId is hashcode of object
[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                 if (!isValidProteinSequence(seq.toCharArray()))\r
149                 {\r
150                     throw new IOException(AppletFormatAdapter.\r
151                                           INVALID_CHARACTERS\r
152                                           + " : " + head\r
153                                           + " : " + invalidCharacter);\r
154                 }\r
155 \r
156 \r
157                 Sequence newSeq = parseId(head);\r
158 \r
159                 newSeq.setSequence(seq);\r
160 \r
161                 seqs.addElement(newSeq);\r
162             }\r
163             else\r
164             {\r
165                 System.err.println("MSFFile Parser: Can't find sequence for " +\r
166                     headers.elementAt(i));\r
167             }\r
168         }\r
169     }\r
170 \r
171     /**\r
172      * DOCUMENT ME!\r
173      *\r
174      * @param seq DOCUMENT ME!\r
175      *\r
176      * @return DOCUMENT ME!\r
177      */\r
178     public int checkSum(String seq)\r
179     {\r
180         int check = 0;\r
181         String sequence = seq.toUpperCase();\r
182 \r
183         for (int i = 0; i < sequence.length(); i++)\r
184         {\r
185             try\r
186             {\r
187 \r
188                     int value = sequence.charAt(i);\r
189                     if (value!=-1)\r
190                     {\r
191                         check += (i % 57 +1) * value;\r
192                     }\r
193             }\r
194             catch (Exception e)\r
195             {\r
196                 System.err.println("Exception during MSF Checksum calculation");\r
197                 e.printStackTrace();\r
198             }\r
199         }\r
200 \r
201         return check % 10000;\r
202     }\r
203 \r
204 \r
205     /**\r
206      * DOCUMENT ME!\r
207      *\r
208      * @param s DOCUMENT ME!\r
209      * @param is_NA DOCUMENT ME!\r
210      *\r
211      * @return DOCUMENT ME!\r
212      */\r
213     public String print(SequenceI[] seqs)\r
214     {\r
215 \r
216       boolean is_NA = jalview.util.Comparison.isNucleotide(seqs);\r
217 \r
218       SequenceI [] s = new SequenceI[seqs.length];\r
219 \r
220         StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA") +\r
221                 "_MULTIPLE_ALIGNMENT 1.0\n\n"); // TODO: JBPNote : Jalview doesn't remember NA or AA yet.\r
222 \r
223         int max = 0;\r
224         int maxid = 0;\r
225         int i = 0;\r
226 \r
227         while ((i < seqs.length) && (seqs[i] != null))\r
228         {\r
229           // Replace all internal gaps with . and external spaces with ~\r
230           s[i] =new Sequence(seqs[i].getName(),seqs[i].getSequenceAsString().replace('-', '.'));\r
231 \r
232           StringBuffer sb = new StringBuffer();\r
233           sb.append(s[i].getSequence());\r
234 \r
235           for (int ii = 0; ii < sb.length(); ii++)\r
236           {\r
237             if (sb.charAt(ii) == '.')\r
238             {\r
239               sb.setCharAt(ii, '~');\r
240             }\r
241             else\r
242               break;\r
243           }\r
244 \r
245           for (int ii = sb.length() - 1; ii > 0; ii--)\r
246           {\r
247             if (sb.charAt(ii) == '.')\r
248             {\r
249               sb.setCharAt(ii,'~');\r
250             }\r
251             else\r
252               break;\r
253           }\r
254 \r
255             s[i].setSequence(sb.toString());\r
256 \r
257             if (s[i].getSequence().length > max)\r
258             {\r
259                 max = s[i].getSequence().length;\r
260             }\r
261 \r
262             i++;\r
263         }\r
264 \r
265         Format maxLenpad = new Format("%" + (new String("" + max)).length() +\r
266                 "d");\r
267         Format maxChkpad = new Format("%" + (new String("1" + max)).length() +\r
268                 "d");\r
269         i = 0;\r
270 \r
271         int bigChecksum = 0;\r
272         int [] checksums = new int[s.length];\r
273         while ( i < s.length )\r
274         {\r
275           checksums[i] = checkSum(s[i].getSequenceAsString());\r
276           bigChecksum += checksums[i];\r
277           i++;\r
278         }\r
279 \r
280         long maxNB = 0;\r
281         out.append("   MSF: " + s[0].getSequence().length + "   Type: " +\r
282             (is_NA ? "N" : "P") + "    Check:  " + (bigChecksum%10000) + "   ..\n\n\n");\r
283 \r
284         String[] nameBlock = new String[s.length];\r
285         String[] idBlock = new String[s.length];\r
286 \r
287         i=0;\r
288         while ((i < s.length) && (s[i] != null))\r
289         {\r
290 \r
291             nameBlock[i] = new String("  Name: " + printId(s[i])+" ");\r
292 \r
293             idBlock[i] = new String("Len: " +\r
294                     maxLenpad.form(s[i].getSequence().length) + "  Check: " +\r
295                     maxChkpad.form(checksums[i]) + "  Weight: 1.00\n");\r
296 \r
297             if (s[i].getName().length() > maxid)\r
298             {\r
299                 maxid = s[i].getName().length();\r
300             }\r
301 \r
302             if (nameBlock[i].length() > maxNB)\r
303             {\r
304                 maxNB = nameBlock[i].length();\r
305             }\r
306 \r
307             i++;\r
308         }\r
309 \r
310         if (maxid < 10)\r
311         {\r
312             maxid = 10;\r
313         }\r
314 \r
315         if (maxNB < 15)\r
316         {\r
317             maxNB = 15;\r
318         }\r
319 \r
320         Format nbFormat = new Format("%-" + maxNB + "s");\r
321 \r
322         for (i = 0; (i < s.length) && (s[i] != null); i++)\r
323         {\r
324             out.append(nbFormat.form(nameBlock[i]) + idBlock[i]);\r
325         }\r
326 \r
327         maxid++;\r
328         out.append("\n\n//\n\n");\r
329 \r
330         int len = 50;\r
331 \r
332         int nochunks = (max / len) + 1;\r
333 \r
334         if ((max % len) == 0)\r
335         {\r
336             nochunks--;\r
337         }\r
338 \r
339         for (i = 0; i < nochunks; i++)\r
340         {\r
341             int j = 0;\r
342 \r
343             while ((j < s.length) && (s[j] != null))\r
344             {\r
345                 String name = printId( s[j] );\r
346 \r
347                 out.append(new Format("%-" + maxid + "s").form(name+" "));\r
348 \r
349 \r
350                 for (int k = 0; k < 5; k++)\r
351                 {\r
352                     int start = (i * 50) + (k * 10);\r
353                     int end = start + 10;\r
354 \r
355                     if ((end < s[j].getSequence().length) &&\r
356                             (start < s[j].getSequence().length))\r
357                     {\r
358                         out.append(s[j].getSequence(start, end));\r
359 \r
360                         if (k < 4)\r
361                         {\r
362                              out.append(" ");\r
363                         }\r
364                         else\r
365                         {\r
366                             out.append("\n");\r
367                         }\r
368                     }\r
369                     else\r
370                     {\r
371                         if (start < s[j].getSequence().length)\r
372                         {\r
373                             out.append(s[j].getSequenceAsString().substring(start));\r
374                             out.append("\n");\r
375                         }\r
376                         else\r
377                         {\r
378                             if (k == 0)\r
379                             {\r
380                                 out.append("\n");\r
381                             }\r
382                         }\r
383                     }\r
384                 }\r
385 \r
386                 j++;\r
387             }\r
388 \r
389             out.append("\n");\r
390         }\r
391 \r
392         return out.toString();\r
393     }\r
394 \r
395     /**\r
396      * DOCUMENT ME!\r
397      *\r
398      * @return DOCUMENT ME!\r
399      */\r
400     public String print()\r
401     {\r
402         return print(getSeqsAsArray());\r
403     }\r
404 }\r