001/*
002 * Copyright (c) 2015 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-10-21 21:56:26 +0000 (Wed, 21 Oct 2015) $' 
007 * '$Revision: 34052 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.gis.actor.windninja;
030
031import java.io.BufferedReader;
032import java.io.File;
033import java.io.FileNotFoundException;
034import java.io.FileReader;
035import java.io.FileWriter;
036import java.io.IOException;
037import java.util.ArrayList;
038import java.util.Arrays;
039import java.util.Comparator;
040
041import ptolemy.actor.lib.Transformer;
042import ptolemy.actor.parameters.PortParameter;
043import ptolemy.data.ArrayToken;
044import ptolemy.data.StringToken;
045import ptolemy.data.type.ArrayType;
046import ptolemy.data.type.BaseType;
047import ptolemy.kernel.CompositeEntity;
048import ptolemy.kernel.util.IllegalActionException;
049import ptolemy.kernel.util.NameDuplicationException;
050import ptolemy.kernel.util.SingletonAttribute;
051import ptolemy.kernel.util.Workspace;
052
053/** Combine WindNinja ATM files into a single ATM file.
054 * 
055 *  @author Daniel Crawl
056 *  @version $Id: ATMCombineFiles.java 34052 2015-10-21 21:56:26Z crawl $
057 */
058public class ATMCombineFiles extends Transformer {
059
060    public ATMCombineFiles(CompositeEntity container, String name)
061            throws IllegalActionException, NameDuplicationException {
062        super(container, name);
063        
064        input.setTypeEquals(new ArrayType(BaseType.STRING));
065        output.setTypeEquals(BaseType.STRING);
066
067        filename = new PortParameter(this, "filename");
068        filename.setTypeEquals(BaseType.STRING);
069        new SingletonAttribute(filename.getPort(), "_showName");
070    }
071
072    @Override
073    public Object clone(Workspace workspace) throws CloneNotSupportedException {
074        ATMCombineFiles newObject = (ATMCombineFiles) super.clone(workspace);
075        newObject._lines = new ArrayList<String>();
076        newObject._paths = new ArrayList<String>();
077        return newObject;
078    }
079
080    @Override
081    public void fire() throws IllegalActionException {
082        super.fire();
083        
084        _lines.clear();
085        _paths.clear();
086
087        filename.update();
088        String outFileStr = ((StringToken)filename.getToken()).stringValue();
089        File outFile = new File(outFileStr);
090        
091        ArrayToken arrayToken = (ArrayToken)input.get(0);
092        for(int i = 0; i < arrayToken.length(); i++) {
093            String fileStr = ((StringToken)arrayToken.getElement(i)).stringValue();
094            File file = new File(fileStr);
095
096            if(!file.exists()) {
097                throw new IllegalActionException(this, "ATM file does not exist: " + file);
098            }
099
100            _readATMFile(file);
101        }
102        
103        // sort the lines
104        String[] lines = _lines.toArray(new String[_lines.size()]);
105        Arrays.sort(lines, new Comparator<String>() {
106            @Override
107            public int compare(String string1, String string2) {                
108                return string1.substring(0, 10).compareTo(string2.substring(0, 10));
109            }
110        });
111        
112        try(FileWriter writer = new FileWriter(outFile);) {
113            writer.write(_firstLine);
114            writer.write("\n");
115            writer.write(_secondLine);
116            writer.write("\n");
117            
118            for(int i = 0; i < lines.length; i++) {
119                final String line = _lines.get(i);
120                final String path = _paths.get(i);
121                
122                String[] parts = line.split(" ");
123                
124                // month
125                writer.write(parts[0]);
126                writer.write(" ");
127
128                // day
129                writer.write(parts[1]);
130                writer.write(" ");
131
132                // hour and minute
133                writer.write(parts[2]);
134                writer.write(" ");
135
136                if(_firstLine.equals(_WINDS_AND_CLOUDS)) {
137                    
138                    // speed
139                    writer.write(path + File.separator + parts[3]);
140                    writer.write(" ");
141                    
142                    // direction
143                    writer.write(path + File.separator + parts[4]);
144                    writer.write(" ");
145                    
146                    // cloud cover
147                    writer.write(path + File.separator + parts[5]);
148                    writer.write(" ");                    
149                }
150                
151                writer.write("\n");
152            }
153        } catch (IOException e) {
154            throw new IllegalActionException(this, e, "Error writing to " + outFile);
155        }
156        
157        output.broadcast(new StringToken(outFileStr));
158    }
159
160    @Override
161    public void preinitialize() throws IllegalActionException {
162        super.preinitialize();
163        _firstLine = null;
164        _secondLine = null;
165    }
166
167    ////////////////////////////////////////////////////////////////////////
168    //// public fields                                                  ////
169
170    /** The name of the output file. */
171    public PortParameter filename;
172    
173    ////////////////////////////////////////////////////////////////////////
174    //// private methods                                                ////
175
176    /** Read an ATM file. */
177    private void _readATMFile(File file) throws IllegalActionException {
178        
179        try(FileReader fileReader = new FileReader(file);
180                BufferedReader reader = new BufferedReader(fileReader)) {
181
182            String line = reader.readLine();
183
184            // first line is WINDS_AND_CLOUDS
185            if(line == null) {
186                throw new IllegalActionException(this, "No lines in " + file);      
187            }
188            if(_firstLine == null) {
189                _firstLine = line;
190                
191                if(!line.equals(_WINDS_AND_CLOUDS)) {
192                    throw new IllegalActionException(this, "Unsupported ATM type: " + line);
193                }
194                
195            } else if(!_firstLine.equals(line)) {
196                throw new IllegalActionException(this,
197                        "First lines do not match: " + _firstLine + " != " +
198                                line + " in " + file);
199            }
200
201            // second line is ENGLISH (or METRIC)
202            line = reader.readLine();
203
204            if(line == null) {
205                throw new IllegalActionException(this, "No second line in " + file);        
206            }
207            if(_secondLine == null) {
208                _secondLine = line;
209                
210                if(!line.equals(_ENGLISH) && !line.equals(_METRIC)) {
211                    throw new IllegalActionException(this, "Unknow type of units: " + line); 
212                }
213                
214            } else if(!_secondLine.equals(line)) {
215                throw new IllegalActionException(this,
216                        "Second lines do not match: " + _secondLine + " != " +
217                                line + " in " + file);
218            }
219
220            while((line = reader.readLine()) != null) {
221                _lines.add(line);
222                _paths.add(file.getParent());
223            }
224        } catch (FileNotFoundException e) {
225            throw new IllegalActionException(this, e, "File not found: " + file);
226        } catch (IOException e) {
227            throw new IllegalActionException(this, e, "Error reading " + file);
228        }
229    }
230
231    ////////////////////////////////////////////////////////////////////////
232    //// private fields                                                 ////
233
234    /** The first line read from the ATM file. */
235    private String _firstLine;
236    
237    /** The second line read from the ATM file. */
238    private String _secondLine;
239    
240    /** The lines in each ATM file. */
241    private ArrayList<String> _lines = new ArrayList<String>();
242    
243    /** The directories containing each ATM file. */
244    private ArrayList<String> _paths = new ArrayList<String>();
245    
246    /** The type of ATM file specifying winds and clouds. */
247    private final static String _WINDS_AND_CLOUDS = "WINDS_AND_CLOUDS";
248
249    /** English units. */
250    private final static String _ENGLISH = "ENGLISH";
251    
252    /** Metric units. */
253    private final static String _METRIC = "METRIC";
254    
255}