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