JAL-1807 explicit imports (jalview.io.*)
[jalview.git] / src / jalview / io / packed / ParsePackedSet.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.packed;
22
23 import jalview.datamodel.AlignmentI;
24 import jalview.io.AnnotationFile;
25 import jalview.io.AppletFormatAdapter;
26 import jalview.io.FeaturesFile;
27 import jalview.io.FileParse;
28 import jalview.io.FormatAdapter;
29 import jalview.io.IdentifyFile;
30 import jalview.io.NewickFile;
31 import jalview.io.packed.DataProvider.JvDataType;
32
33 import java.io.BufferedReader;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.Hashtable;
37 import java.util.List;
38
39 public class ParsePackedSet
40 {
41
42   /**
43    * return results as a series of jalview.datamodel objects suitable for
44    * display
45    * 
46    * @param context
47    *          - context which is updated with new data
48    * @param files
49    *          - source data
50    * @return list of data objects added to context
51    * @throws Exception
52    */
53   public Object[] getAlignment(JalviewDataset context,
54           Iterable<DataProvider> files) throws Exception
55   {
56     List<Object> rslt = new ArrayList<Object>();
57     if (context == null)
58     {
59       context = new JalviewDataset();
60     }
61     boolean deuniquify = false;
62     for (DataProvider dta : files)
63     {
64       Exception exerror = null;
65       String errmsg = null;
66       FileParse src = dta.getDataSource();
67       if (dta.getType().equals(DataProvider.JvDataType.ALIGNMENT))
68       {
69         String fmt = null;
70         try
71         {
72           fmt = new IdentifyFile().Identify(src, false);
73         } catch (Exception ex)
74         {
75           exerror = ex;
76           errmsg = "Couldn't identify alignment format.";
77         }
78
79         if (fmt != null)
80         {
81           if (!FormatAdapter.isValidIOFormat(fmt, false))
82           {
83             errmsg = fmt;
84             exerror = null;
85           }
86           else
87           {
88             // parse the alignment
89             AlignmentI al = null;
90             try
91             {
92               al = new FormatAdapter().readFromFile(src, fmt);
93             } catch (Exception e)
94             {
95               errmsg = "Failed to parse alignment from result set";
96               exerror = e;
97             }
98             if (al != null)
99             {
100               // deuniquify and construct/merge additional dataset entries if
101               // necessary.
102               context.addAlignment(al);
103               context.updateSetModified(true);
104               rslt.add(al);
105               deuniquify = true;
106             }
107           }
108         }
109       }
110       if (dta.getType().equals(JvDataType.ANNOTATION))
111       {
112         if (!context.hasAlignments())
113         {
114           errmsg = "No alignment or sequence dataset to associate annotation with.";
115           // could duplicate the dataset reference here as default behaviour for
116           // sequence associated annotation ?
117         }
118         try
119         {
120           BufferedReader br;
121           if (src.getReader() instanceof BufferedReader)
122           {
123             br = (BufferedReader) src.getReader();
124           }
125           else
126           {
127             br = new BufferedReader(src.getReader());
128           }
129           // TODO: add columnSelection to context
130           if (new AnnotationFile().parseAnnotationFrom(
131                   context.getLastAlignment(), null, br))
132           {
133             context.updateSetModified(true);
134           }
135           else
136           {
137             errmsg = "Annotation file contained no data.";
138           }
139
140         } catch (Exception e)
141         {
142           errmsg = ((errmsg == null) ? "" : errmsg)
143                   + "Failed to parse the annotation file associated with the alignment.";
144           exerror = e;
145         }
146       }
147       if (dta.getType().equals(JvDataType.SEQASSOCATED))
148       {
149         if (!context.hasSequenceAssoc())
150         {
151           errmsg = "No sequence to associate data with.";
152
153         }
154         errmsg = "parsing of sequence associated data is not implemented";
155         exerror = new Exception(errmsg);
156       }
157       if (dta.getType().equals(JvDataType.FEATURES))
158       {
159         // check the context has a place to store feature rendering definitions,
160         // if not, create one.
161         if (context.featureColours == null)
162         {
163           context.featureColours = new Hashtable();
164         }
165         try
166         {
167           FeaturesFile ff = new FeaturesFile(src);
168           context.updateSetModified(ff.parse(context.getLastAlignment(),
169                   context.featureColours, false, context.relaxedIdMatching));
170         } catch (Exception e)
171         {
172           errmsg = ("Failed to parse the Features file associated with the alignment.");
173           exerror = e;
174         }
175       }
176       if (dta.getType().equals(JvDataType.TREE))
177       {
178         try
179         {
180           NewickFile nf = new NewickFile(src);
181           if (!nf.isValid())
182           {
183             nf.close();
184             nf = null;
185           }
186           else
187           {
188             // do association to current alignment.
189
190             context.addTreeFromFile(nf);
191             rslt.add(nf);
192             context.updateSetModified(true);
193           }
194         } catch (Exception e)
195         {
196           errmsg = ("Failed to parse the treeFile associated with the result.");
197           exerror = e;
198         }
199
200       }
201       if (exerror != null)
202       {
203         if (errmsg != null && errmsg.length() > 0)
204         {
205           throw new IOException(errmsg, exerror);
206         }
207         else
208         {
209           throw new IOException(errmsg, exerror);
210         }
211       }
212       else
213       {
214         if (errmsg != null && errmsg.length() > 0)
215         {
216           throw new IOException(errmsg);
217         }
218       }
219     }
220     if (deuniquify)
221     {
222       context.getLastAlignmentSet().deuniquifyAlignment();
223     }
224     return rslt.toArray();
225   }
226
227   /**
228    * simple command line test. Arguments should be one or more pairs of
229    * <DataProvider.JvDataType> <Filename> arguments. The routine will attempt to
230    * read each source in turn, and report what kind of Jalview datamodel objects
231    * would be created.
232    * 
233    * @param args
234    */
235   public static void main(String args[])
236   {
237     // make data providers from the set of keys/files
238     int i = 0;
239     List<DataProvider> dp = new ArrayList<DataProvider>();
240     while ((i + 1) < args.length)
241     {
242       String type = args[i++];
243       final String file = args[i++];
244       final JvDataType jtype = DataProvider.JvDataType.valueOf(type
245               .toUpperCase());
246       if (jtype != null)
247       {
248         final FileParse fp;
249         try
250         {
251           fp = new FileParse(file, AppletFormatAdapter.checkProtocol(file));
252         } catch (Exception e)
253         {
254           System.err.println("Couldn't handle datasource of type " + jtype
255                   + " using URI " + file);
256           e.printStackTrace();
257           return;
258         }
259         dp.add(new SimpleDataProvider(jtype, fp, null));
260       }
261       else
262       {
263         System.out.println("Couldn't parse source type token '"
264                 + type.toUpperCase() + "'");
265       }
266     }
267     if (i < args.length)
268     {
269       System.out.print("** WARNING\nIgnoring unused arguments:\n");
270       while (i < args.length)
271       {
272         System.out.print(" " + args[i]);
273       }
274       System.out.print("\n");
275
276     }
277     System.out.println("Now trying to parse set:");
278     JalviewDataset context;
279     Object[] newdm;
280     ParsePackedSet pps;
281     try
282     {
283       newdm = (pps = new ParsePackedSet()).getAlignment(
284               context = new JalviewDataset(), dp);
285     } catch (Exception e)
286     {
287       System.out.println("Test failed for these arguments.\n");
288       e.printStackTrace(System.out);
289       return;
290     }
291     if (newdm != null)
292     {
293       for (Object o : newdm)
294       {
295         System.out.println("Will need to create an " + o.getClass());
296       }
297
298       // now test uniquify/deuniquify stuff
299       // uniquify alignment and write alignment, annotation, features, and trees
300       // to buffers.
301       // import with deuniquify info, and compare results to input.
302
303     }
304     else
305     {
306       if (context.getLastAlignmentSet().isModified())
307       {
308         System.err
309                 .println("Initial alignment set was modified and any associated views should be updated.");
310       }
311     }
312   }
313 }