4ae5e777ac78e1c15cbdefe91ece2a1012abba0b
[jalview.git] / src / jalview / io / ClustalFile.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 jalview.datamodel.*;
24 import jalview.util.*;
25
26 public class ClustalFile extends AlignFile
27 {
28
29   public ClustalFile()
30   {
31   }
32
33   public ClustalFile(String inFile, String type) throws IOException
34   {
35     super(inFile, type);
36   }
37
38   public ClustalFile(FileParse source) throws IOException
39   {
40     super(source);
41   }
42
43   public void initData()
44   {
45     super.initData();
46   }
47
48   public void parse() throws IOException
49   {
50     int i = 0;
51     boolean flag = false;
52     boolean rna = false;
53     boolean top = false;
54     StringBuffer pssecstr = new StringBuffer(), consstr = new StringBuffer();
55     Vector headers = new Vector();
56     Hashtable seqhash = new Hashtable();
57     StringBuffer tempseq;
58     String line, id;
59     StringTokenizer str;
60
61     try
62     {
63       while ((line = nextLine()) != null)
64       {
65         if (line.length() == 0)
66         {
67           top = true;
68         }
69         if (line.indexOf(" ") != 0)
70         {
71           str = new StringTokenizer(line, " ");
72
73           if (str.hasMoreTokens())
74           {
75             id = str.nextToken();
76
77             if (id.equalsIgnoreCase("CLUSTAL"))
78             {
79               flag = true;
80             }
81             else
82             {
83               if (flag)
84               {
85                 if (seqhash.containsKey(id))
86                 {
87                   tempseq = (StringBuffer) seqhash.get(id);
88                 }
89                 else
90                 {
91                   tempseq = new StringBuffer();
92                   seqhash.put(id, tempseq);
93                 }
94
95                 if (!(headers.contains(id)))
96                 {
97                   headers.addElement(id);
98                 }
99
100                 if (str.hasMoreTokens())
101                 {
102                   tempseq.append(str.nextToken());
103                 }
104                 top = false;
105               }
106             }
107           }
108           else
109           {
110             flag = true;
111           }
112         }
113         else
114         {
115           if (line.matches("\\s+(-|\\.|\\(|\\[|\\]|\\))+"))
116           {
117             if (top)
118             {
119               pssecstr.append(line.trim());
120             }
121             else
122             {
123               consstr.append(line.trim());
124             }
125           }
126         }
127       }
128     } catch (IOException e)
129     {
130       System.err.println("Exception parsing clustal file " + e);
131       e.printStackTrace();
132     }
133
134     if (flag)
135     {
136       this.noSeqs = headers.size();
137
138       // Add sequences to the hash
139       for (i = 0; i < headers.size(); i++)
140       {
141         if (seqhash.get(headers.elementAt(i)) != null)
142         {
143           if (maxLength < seqhash.get(headers.elementAt(i)).toString()
144                   .length())
145           {
146             maxLength = seqhash.get(headers.elementAt(i)).toString()
147                     .length();
148           }
149
150           Sequence newSeq = parseId(headers.elementAt(i).toString());
151           newSeq.setSequence(seqhash.get(headers.elementAt(i).toString())
152                   .toString());
153
154           seqs.addElement(newSeq);
155         }
156         else
157         {
158           System.err
159                   .println("Clustal File Reader: Can't find sequence for "
160                           + headers.elementAt(i));
161         }
162       }
163       AlignmentAnnotation lastssa = null;
164       if (pssecstr.length() == maxLength)
165       {
166         Vector ss = new Vector();
167         AlignmentAnnotation ssa = lastssa = StockholmFile
168                 .parseAnnotationRow(ss, "secondary structure",
169                         pssecstr.toString());
170         ssa.label = "Secondary Structure";
171         annotations.addElement(ssa);
172       }
173       if (consstr.length() == maxLength)
174       {
175         Vector ss = new Vector();
176         AlignmentAnnotation ssa = StockholmFile.parseAnnotationRow(ss,
177                 "secondary structure", consstr.toString());
178         ssa.label = "Consensus Secondary Structure";
179         if (lastssa == null
180                 || !lastssa.getRNAStruc().equals(
181                         ssa.getRNAStruc().replace('-', '.')))
182         {
183           annotations.addElement(ssa);
184         }
185       }
186     }
187   }
188
189   public String print()
190   {
191     return print(getSeqsAsArray());
192     // TODO: locaRNA style aln output
193   }
194
195   public String print(SequenceI[] s)
196   {
197     StringBuffer out = new StringBuffer("CLUSTAL" + newline + newline);
198
199     int max = 0;
200     int maxid = 0;
201
202     int i = 0;
203
204     while ((i < s.length) && (s[i] != null))
205     {
206       String tmp = printId(s[i]);
207
208       if (s[i].getSequence().length > max)
209       {
210         max = s[i].getSequence().length;
211       }
212
213       if (tmp.length() > maxid)
214       {
215         maxid = tmp.length();
216       }
217
218       i++;
219     }
220
221     if (maxid < 15)
222     {
223       maxid = 15;
224     }
225
226     maxid++;
227
228     int len = 60;
229     int nochunks = (max / len) + 1;
230
231     for (i = 0; i < nochunks; i++)
232     {
233       int j = 0;
234
235       while ((j < s.length) && (s[j] != null))
236       {
237         out.append(new Format("%-" + maxid + "s").form(printId(s[j]) + " "));
238
239         int start = i * len;
240         int end = start + len;
241
242         if ((end < s[j].getSequence().length)
243                 && (start < s[j].getSequence().length))
244         {
245           out.append(s[j].getSequenceAsString(start, end));
246         }
247         else
248         {
249           if (start < s[j].getSequence().length)
250           {
251             out.append(s[j].getSequenceAsString().substring(start));
252           }
253         }
254
255         out.append(newline);
256         j++;
257       }
258
259       out.append(newline);
260     }
261
262     return out.toString();
263   }
264 }