af835ca420c111db7eccd8c953eae42a6bce3509
[jalview.git] / src / jalview / io / AlignFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
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
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.Alignment;
24 import jalview.datamodel.AlignmentAnnotation;
25 import jalview.datamodel.Sequence;
26 import jalview.datamodel.SequenceI;
27 import jalview.util.MessageManager;
28
29 import java.io.IOException;
30 import java.util.Enumeration;
31 import java.util.Hashtable;
32 import java.util.Vector;
33
34 /**
35  * DOCUMENT ME!
36  * 
37  * @author $author$
38  * @version $Revision$
39  */
40 public abstract class AlignFile extends FileParse
41 {
42   int noSeqs = 0;
43
44   int maxLength = 0;
45
46   /**
47    * Sequences to be added to form a new alignment.
48    */
49   protected Vector<SequenceI> seqs;
50
51   /**
52    * annotation to be added to generated alignment object
53    */
54   protected Vector<AlignmentAnnotation> annotations;
55
56   /**
57    * Properties to be added to generated alignment object
58    */
59   protected Hashtable properties;
60
61   long start;
62
63   long end;
64
65   boolean jvSuffix = true;
66
67   private boolean parseCalled;
68
69   /**
70    * Creates a new AlignFile object.
71    */
72   public AlignFile()
73   {
74     // Shouldn't we init data structures (JBPNote: not sure - initData is for
75     // initialising the structures used for reading from a datasource, and the
76     // bare constructor hasn't got any datasource)
77     initData();
78   }
79
80   /**
81    * Constructor which parses the data from a file of some specified type.
82    * 
83    * @param inFile
84    *          Filename to read from.
85    * @param type
86    *          What type of file to read from (File, URL)
87    */
88   public AlignFile(String inFile, String type) throws IOException
89   {
90     this(true, inFile, type);
91   }
92   
93   /**
94    * Constructor which (optionally delays) parsing of data from a file of some specified type.
95    * 
96    * @param parseImmediately
97    *          if false, need to call 'doParse()' to begin parsing data
98    * @param inFile
99    *          Filename to read from.
100    * @param type
101    *          What type of file to read from (File, URL)
102    * @throws IOException
103    */
104   public AlignFile(boolean parseImmediately, String inFile, String type) throws IOException
105   {
106     super(inFile, type);
107     initData();
108     if (parseImmediately) {
109       doParse();
110     }
111   }
112   /**
113    * Attempt to read from the position where some other parsing process left
114    * off.
115    * 
116    * @param source
117    * @throws IOException
118    */
119   public AlignFile(FileParse source) throws IOException
120   {
121     this(true,source);
122   }
123   /**
124    * Construct a new parser to read from the position where some other parsing process left
125    * 
126    * @param parseImmediately
127    *          if false, need to call 'doParse()' to begin parsing data
128    * @param source
129    */
130   public AlignFile(boolean parseImmediately, FileParse source) throws IOException
131   {
132     super(source);
133     initData();
134     if (parseImmediately) {
135       doParse();
136     }
137   }
138   /**
139    * called if parsing was delayed till after parser was constructed
140    * @throws IOException
141    */
142   public void doParse() throws IOException
143   {
144     if (parseCalled)
145     {
146       throw new IOException(
147               "Implementation error: Parser called twice for same data.\n"
148                       + "Need to call initData() again before parsing can be reattempted.");
149     }
150     parseCalled=true;
151     parse();
152     // sets the index of each sequence in the alignment
153     for (int i = 0, c = seqs.size(); i < c; i++)
154     {
155       seqs.get(i).setIndex(i);
156     }
157   }
158
159
160   /**
161    * Return the seqs Vector
162    */
163   public Vector<SequenceI> getSeqs()
164   {
165     return seqs;
166   }
167
168   /**
169    * Return the Sequences in the seqs Vector as an array of Sequences
170    */
171   public SequenceI[] getSeqsAsArray()
172   {
173     SequenceI[] s = new SequenceI[seqs.size()];
174
175     for (int i = 0; i < seqs.size(); i++)
176     {
177       s[i] = (SequenceI) seqs.elementAt(i);
178     }
179
180     return s;
181   }
182
183   /**
184    * called by AppletFormatAdapter to generate an annotated alignment, rather
185    * than bare sequences.
186    * 
187    * @param al
188    */
189   public void addAnnotations(Alignment al)
190   {
191     addProperties(al);
192     for (int i = 0; i < annotations.size(); i++)
193     {
194       // detect if annotations.elementAt(i) rna secondary structure
195       // if so then do:
196       /*
197        * SequenceFeature[] pairArray =
198        * Rna.GetBasePairsFromAlignmentAnnotation(annotations.elementAt(i));
199        * Rna.HelixMap(pairArray);
200        */
201       AlignmentAnnotation an = (AlignmentAnnotation) annotations
202               .elementAt(i);
203       an.validateRangeAndDisplay();
204       al.addAnnotation(an);
205     }
206
207   }
208
209   /**
210    * Add any additional information extracted from the file to the alignment
211    * properties.
212    * 
213    * @note implicitly called by addAnnotations()
214    * @param al
215    */
216   public void addProperties(Alignment al)
217   {
218     if (properties != null && properties.size() > 0)
219     {
220       Enumeration keys = properties.keys();
221       Enumeration vals = properties.elements();
222       while (keys.hasMoreElements())
223       {
224         al.setProperty(keys.nextElement(), vals.nextElement());
225       }
226     }
227   }
228
229   /**
230    * Store a non-null key-value pair in a hashtable used to set alignment
231    * properties note: null keys will raise an error, null values will result in
232    * the key/value pair being silently ignored.
233    * 
234    * @param key
235    *          - non-null key object
236    * @param value
237    *          - non-null value
238    */
239   protected void setAlignmentProperty(Object key, Object value)
240   {
241     if (key == null)
242     {
243       throw new Error(MessageManager.getString("error.implementation_error_cannot_have_null_alignment"));
244     }
245     if (value == null)
246     {
247       return; // null properties are ignored.
248     }
249     if (properties == null)
250     {
251       properties = new Hashtable();
252     }
253     properties.put(key, value);
254   }
255
256   protected Object getAlignmentProperty(Object key)
257   {
258     if (properties != null && key != null)
259     {
260       return properties.get(key);
261     }
262     return null;
263   }
264
265   /**
266    * Initialise objects to store sequence data in.
267    */
268   protected void initData()
269   {
270     seqs = new Vector();
271     annotations = new Vector();
272     parseCalled=false;
273   }
274
275   /**
276    * DOCUMENT ME!
277    * 
278    * @param s
279    *          DOCUMENT ME!
280    */
281   protected void setSeqs(SequenceI[] s)
282   {
283     seqs = new Vector();
284
285     for (int i = 0; i < s.length; i++)
286     {
287       seqs.addElement(s[i]);
288     }
289   }
290
291   /**
292    * This method must be implemented to parse the contents of the file.
293    */
294   public abstract void parse() throws IOException;
295
296   /**
297    * Print out in alignment file format the Sequences in the seqs Vector.
298    */
299   public abstract String print();
300
301   public void addJVSuffix(boolean b)
302   {
303     jvSuffix = b;
304   }
305
306   /**
307    * A general parser for ids.
308    * 
309    * @String id Id to be parsed
310    */
311   Sequence parseId(String id)
312   {
313     Sequence seq = null;
314     id = id.trim();
315     int space = id.indexOf(" ");
316     if (space > -1)
317     {
318       seq = new Sequence(id.substring(0, space), "");
319       seq.setDescription(id.substring(space + 1));
320     }
321     else
322     {
323       seq = new Sequence(id, "");
324     }
325
326     return seq;
327   }
328
329   /**
330    * Creates the output id. Adds prefix Uniprot format source|id And suffix
331    * Jalview /start-end
332    * 
333    * @String id Id to be parsed
334    */
335   String printId(SequenceI seq)
336   {
337     return seq.getDisplayId(jvSuffix);
338   }
339
340   /**
341    * vector of String[] treeName, newickString pairs
342    */
343   Vector newickStrings = null;
344
345   protected void addNewickTree(String treeName, String newickString)
346   {
347     if (newickStrings == null)
348     {
349       newickStrings = new Vector();
350     }
351     newickStrings.addElement(new String[]
352     { treeName, newickString });
353   }
354
355   protected int getTreeCount()
356   {
357     if (newickStrings == null)
358     {
359       return 0;
360     }
361     return newickStrings.size();
362   }
363
364 }