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