dcbe37df9fca26ab37b8a3aeda5775b07138fc3e
[jalview.git] / src / jalview / io / MSFfile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.io;
19
20 import java.io.*;
21 import java.util.*;
22
23 import javax.xml.parsers.ParserConfigurationException;
24
25 import org.xml.sax.SAXException;
26
27 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
28 import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed;
29 import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied;
30 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
31
32 import jalview.datamodel.*;
33 import jalview.util.*;
34
35 /**
36  * DOCUMENT ME!
37  * 
38  * @author $author$
39  * @version $Revision$
40  */
41 public class MSFfile extends AlignFile
42 {
43
44   /**
45    * Creates a new MSFfile object.
46    */
47   public MSFfile()
48   {
49   }
50
51   /**
52    * Creates a new MSFfile object.
53    * 
54    * @param inFile
55    *          DOCUMENT ME!
56    * @param type
57    *          DOCUMENT ME!
58  * @throws Exception 
59    */
60   public MSFfile(String inFile, String type) throws Exception
61   {
62     super(inFile, type);
63   }
64
65   public MSFfile(FileParse source) throws Exception
66   {
67     super(source);
68   }
69
70   {
71     // TODO Auto-generated constructor stub
72   }
73
74   /**
75    * DOCUMENT ME!
76    */
77   public void parse() throws IOException
78   {
79     int i = 0;
80     boolean seqFlag = false;
81     String key = new String();
82     Vector headers = new Vector();
83     Hashtable seqhash = new Hashtable();
84     String line;
85
86     try
87     {
88       while ((line = nextLine()) != null)
89       {
90         StringTokenizer str = new StringTokenizer(line);
91
92         while (str.hasMoreTokens())
93         {
94           String inStr = str.nextToken();
95
96           // If line has header information add to the headers vector
97           if (inStr.indexOf("Name:") != -1)
98           {
99             key = str.nextToken();
100             headers.addElement(key);
101           }
102
103           // if line has // set SeqFlag to 1 so we know sequences are coming
104           if (inStr.indexOf("//") != -1)
105           {
106             seqFlag = true;
107           }
108
109           // Process lines as sequence lines if seqFlag is set
110           if ((inStr.indexOf("//") == -1) && (seqFlag == true))
111           {
112             // seqeunce id is the first field
113             key = inStr;
114
115             StringBuffer tempseq;
116
117             // Get sequence from hash if it exists
118             if (seqhash.containsKey(key))
119             {
120               tempseq = (StringBuffer) seqhash.get(key);
121             }
122             else
123             {
124               tempseq = new StringBuffer();
125               seqhash.put(key, tempseq);
126             }
127
128             // loop through the rest of the words
129             while (str.hasMoreTokens())
130             {
131               // append the word to the sequence
132               tempseq.append(str.nextToken());
133             }
134           }
135         }
136       }
137     } catch (IOException e)
138     {
139       System.err.println("Exception parsing MSFFile " + e);
140       e.printStackTrace();
141     }
142
143     this.noSeqs = headers.size();
144
145     // Add sequences to the hash
146     for (i = 0; i < headers.size(); i++)
147     {
148       if (seqhash.get(headers.elementAt(i)) != null)
149       {
150         String head = headers.elementAt(i).toString();
151         String seq = seqhash.get(head).toString();
152
153         if (maxLength < head.length())
154         {
155           maxLength = head.length();
156         }
157
158         // Replace ~ with a sensible gap character
159         seq = seq.replace('~', '-');
160
161         Sequence newSeq = parseId(head);
162
163         newSeq.setSequence(seq);
164
165         seqs.addElement(newSeq);
166       }
167       else
168       {
169         System.err.println("MSFFile Parser: Can't find sequence for "
170                 + headers.elementAt(i));
171       }
172     }
173   }
174
175   /**
176    * DOCUMENT ME!
177    * 
178    * @param seq
179    *          DOCUMENT ME!
180    * 
181    * @return DOCUMENT ME!
182    */
183   public int checkSum(String seq)
184   {
185     int check = 0;
186     String sequence = seq.toUpperCase();
187
188     for (int i = 0; i < sequence.length(); i++)
189     {
190       try
191       {
192
193         int value = sequence.charAt(i);
194         if (value != -1)
195         {
196           check += (i % 57 + 1) * value;
197         }
198       } catch (Exception e)
199       {
200         System.err.println("Exception during MSF Checksum calculation");
201         e.printStackTrace();
202       }
203     }
204
205     return check % 10000;
206   }
207
208   /**
209    * DOCUMENT ME!
210    * 
211    * @param s
212    *          DOCUMENT ME!
213    * @param is_NA
214    *          DOCUMENT ME!
215    * 
216    * @return DOCUMENT ME!
217    */
218   public String print(SequenceI[] seqs)
219   {
220
221     boolean is_NA = jalview.util.Comparison.isNucleotide(seqs);
222
223     SequenceI[] s = new SequenceI[seqs.length];
224
225     StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA")
226             + "_MULTIPLE_ALIGNMENT 1.0");
227     // TODO: JBPNote : Jalview doesn't remember NA or AA yet.
228     out.append(newline);
229     out.append(newline);
230     int max = 0;
231     int maxid = 0;
232     int i = 0;
233
234     while ((i < seqs.length) && (seqs[i] != null))
235     {
236       // Replace all internal gaps with . and external spaces with ~
237       s[i] = new Sequence(seqs[i].getName(), seqs[i].getSequenceAsString()
238               .replace('-', '.'), seqs[i].getStart(), seqs[i].getEnd());
239
240       StringBuffer sb = new StringBuffer();
241       sb.append(s[i].getSequence());
242
243       for (int ii = 0; ii < sb.length(); ii++)
244       {
245         if (sb.charAt(ii) == '.')
246         {
247           sb.setCharAt(ii, '~');
248         }
249         else
250         {
251           break;
252         }
253       }
254
255       for (int ii = sb.length() - 1; ii > 0; ii--)
256       {
257         if (sb.charAt(ii) == '.')
258         {
259           sb.setCharAt(ii, '~');
260         }
261         else
262         {
263           break;
264         }
265       }
266
267       s[i].setSequence(sb.toString());
268
269       if (s[i].getSequence().length > max)
270       {
271         max = s[i].getSequence().length;
272       }
273
274       i++;
275     }
276
277     Format maxLenpad = new Format("%" + (new String("" + max)).length()
278             + "d");
279     Format maxChkpad = new Format("%" + (new String("1" + max)).length()
280             + "d");
281     i = 0;
282
283     int bigChecksum = 0;
284     int[] checksums = new int[s.length];
285     while (i < s.length)
286     {
287       checksums[i] = checkSum(s[i].getSequenceAsString());
288       bigChecksum += checksums[i];
289       i++;
290     }
291
292     long maxNB = 0;
293     out.append("   MSF: " + s[0].getSequence().length + "   Type: "
294             + (is_NA ? "N" : "P") + "    Check:  " + (bigChecksum % 10000)
295             + "   ..");
296     out.append(newline);
297     out.append(newline);
298     out.append(newline);
299
300     String[] nameBlock = new String[s.length];
301     String[] idBlock = new String[s.length];
302
303     i = 0;
304     while ((i < s.length) && (s[i] != null))
305     {
306
307       nameBlock[i] = new String("  Name: " + printId(s[i]) + " ");
308
309       idBlock[i] = new String("Len: "
310               + maxLenpad.form(s[i].getSequence().length) + "  Check: "
311               + maxChkpad.form(checksums[i]) + "  Weight: 1.00" + newline);
312
313       if (s[i].getName().length() > maxid)
314       {
315         maxid = s[i].getName().length();
316       }
317
318       if (nameBlock[i].length() > maxNB)
319       {
320         maxNB = nameBlock[i].length();
321       }
322
323       i++;
324     }
325
326     if (maxid < 10)
327     {
328       maxid = 10;
329     }
330
331     if (maxNB < 15)
332     {
333       maxNB = 15;
334     }
335
336     Format nbFormat = new Format("%-" + maxNB + "s");
337
338     for (i = 0; (i < s.length) && (s[i] != null); i++)
339     {
340       out.append(nbFormat.form(nameBlock[i]) + idBlock[i]);
341     }
342
343     maxid++;
344     out.append(newline);
345     out.append(newline);
346     out.append("//");
347     out.append(newline);
348     out.append(newline);
349     int len = 50;
350
351     int nochunks = (max / len) + 1;
352
353     if ((max % len) == 0)
354     {
355       nochunks--;
356     }
357
358     for (i = 0; i < nochunks; i++)
359     {
360       int j = 0;
361
362       while ((j < s.length) && (s[j] != null))
363       {
364         String name = printId(s[j]);
365
366         out.append(new Format("%-" + maxid + "s").form(name + " "));
367
368         for (int k = 0; k < 5; k++)
369         {
370           int start = (i * 50) + (k * 10);
371           int end = start + 10;
372
373           if ((end < s[j].getSequence().length)
374                   && (start < s[j].getSequence().length))
375           {
376             out.append(s[j].getSequence(start, end));
377
378             if (k < 4)
379             {
380               out.append(" ");
381             }
382             else
383             {
384               out.append(newline);
385             }
386           }
387           else
388           {
389             if (start < s[j].getSequence().length)
390             {
391               out.append(s[j].getSequenceAsString().substring(start));
392               out.append(newline);
393             }
394             else
395             {
396               if (k == 0)
397               {
398                 out.append(newline);
399               }
400             }
401           }
402         }
403
404         j++;
405       }
406
407       out.append(newline);
408     }
409
410     return out.toString();
411   }
412
413   /**
414    * DOCUMENT ME!
415    * 
416    * @return DOCUMENT ME!
417    */
418   public String print()
419   {
420     return print(getSeqsAsArray());
421   }
422 }