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