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