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