seq size cant be less than 2 for tree
[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     /**\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))\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].getSequence().replace('-', '.'));\r
231 \r
232           StringBuffer sb = new StringBuffer(s[i].getSequence());\r
233           for (int ii = 0; ii < sb.length(); ii++)\r
234           {\r
235             if (sb.charAt(ii) == '.')\r
236             {\r
237               sb.setCharAt(ii, '~');\r
238             }\r
239             else\r
240               break;\r
241           }\r
242 \r
243           for (int ii = sb.length() - 1; ii > 0; ii--)\r
244           {\r
245             if (sb.charAt(ii) == '.')\r
246             {\r
247               sb.setCharAt(ii,'~');\r
248             }\r
249             else\r
250               break;\r
251           }\r
252 \r
253             s[i].setSequence(sb.toString());\r
254 \r
255             if (s[i].getSequence().length() > max)\r
256             {\r
257                 max = s[i].getSequence().length();\r
258             }\r
259 \r
260             i++;\r
261         }\r
262 \r
263         Format maxLenpad = new Format("%" + (new String("" + max)).length() +\r
264                 "d");\r
265         Format maxChkpad = new Format("%" + (new String("1" + max)).length() +\r
266                 "d");\r
267         i = 0;\r
268 \r
269         int bigChecksum = 0;\r
270         int [] checksums = new int[s.length];\r
271         while ( i < s.length )\r
272         {\r
273           checksums[i] = checkSum(s[i].getSequence());\r
274           bigChecksum += checksums[i];\r
275           i++;\r
276         }\r
277 \r
278         long maxNB = 0;\r
279         out.append("   MSF: " + s[0].getSequence().length() + "   Type: " +\r
280             (is_NA ? "N" : "P") + "    Check:  " + (bigChecksum%10000) + "   ..\n\n\n");\r
281 \r
282         String[] nameBlock = new String[s.length];\r
283         String[] idBlock = new String[s.length];\r
284 \r
285         i=0;\r
286         while ((i < s.length) && (s[i] != null))\r
287         {\r
288 \r
289             nameBlock[i] = new String("  Name: " + printId(s[i])+" ");\r
290 \r
291             idBlock[i] = new String("Len: " +\r
292                     maxLenpad.form(s[i].getSequence().length()) + "  Check: " +\r
293                     maxChkpad.form(checksums[i]) + "  Weight: 1.00\n");\r
294 \r
295             if (s[i].getName().length() > maxid)\r
296             {\r
297                 maxid = s[i].getName().length();\r
298             }\r
299 \r
300             if (nameBlock[i].length() > maxNB)\r
301             {\r
302                 maxNB = nameBlock[i].length();\r
303             }\r
304 \r
305             i++;\r
306         }\r
307 \r
308         if (maxid < 10)\r
309         {\r
310             maxid = 10;\r
311         }\r
312 \r
313         if (maxNB < 15)\r
314         {\r
315             maxNB = 15;\r
316         }\r
317 \r
318         Format nbFormat = new Format("%-" + maxNB + "s");\r
319 \r
320         for (i = 0; (i < s.length) && (s[i] != null); i++)\r
321         {\r
322             out.append(nbFormat.form(nameBlock[i]) + idBlock[i]);\r
323         }\r
324 \r
325         maxid++;\r
326         out.append("\n\n//\n\n");\r
327 \r
328         int len = 50;\r
329 \r
330         int nochunks = (max / len) + 1;\r
331 \r
332         if ((max % len) == 0)\r
333         {\r
334             nochunks--;\r
335         }\r
336 \r
337         for (i = 0; i < nochunks; i++)\r
338         {\r
339             int j = 0;\r
340 \r
341             while ((j < s.length) && (s[j] != null))\r
342             {\r
343                 String name = printId( s[j] );\r
344 \r
345                 out.append(new Format("%-" + maxid + "s").form(name+" "));\r
346 \r
347 \r
348                 for (int k = 0; k < 5; k++)\r
349                 {\r
350                     int start = (i * 50) + (k * 10);\r
351                     int end = start + 10;\r
352 \r
353                     if ((end < s[j].getSequence().length()) &&\r
354                             (start < s[j].getSequence().length()))\r
355                     {\r
356                         out.append(s[j].getSequence().substring(start, end));\r
357 \r
358                         if (k < 4)\r
359                         {\r
360                              out.append(" ");\r
361                         }\r
362                         else\r
363                         {\r
364                             out.append("\n");\r
365                         }\r
366                     }\r
367                     else\r
368                     {\r
369                         if (start < s[j].getSequence().length())\r
370                         {\r
371                             out.append(s[j].getSequence().substring(start));\r
372                             out.append("\n");\r
373                         }\r
374                         else\r
375                         {\r
376                             if (k == 0)\r
377                             {\r
378                                 out.append("\n");\r
379                             }\r
380                         }\r
381                     }\r
382                 }\r
383 \r
384                 j++;\r
385             }\r
386 \r
387             out.append("\n");\r
388         }\r
389 \r
390         return out.toString();\r
391     }\r
392 \r
393     /**\r
394      * DOCUMENT ME!\r
395      *\r
396      * @return DOCUMENT ME!\r
397      */\r
398     public String print()\r
399     {\r
400         return print(getSeqsAsArray());\r
401     }\r
402 }\r