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