001/*
002 * Copyright (c) 2009-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
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 */
029
030package org.kepler.actor.io;
031
032import java.util.Arrays;
033import java.util.LinkedList;
034import java.util.List;
035import java.util.Set;
036
037import org.geon.FileWrite;
038
039import ptolemy.data.ArrayToken;
040import ptolemy.data.DoubleToken;
041import ptolemy.data.RecordToken;
042import ptolemy.data.StringToken;
043import ptolemy.data.Token;
044import ptolemy.data.expr.StringParameter;
045import ptolemy.data.type.ArrayType;
046import ptolemy.data.type.RecordType;
047import ptolemy.kernel.CompositeEntity;
048import ptolemy.kernel.util.IllegalActionException;
049import ptolemy.kernel.util.NameDuplicationException;
050
051/**
052
053 Write an array of records to a table.
054
055 @author Daniel Crawl
056 @version $Id: ArrayOfRecordsWriter.java 24234 2010-05-06 05:21:26Z welker $
057
058 */
059
060public class ArrayOfRecordsWriter extends FileWrite
061{
062    /** Construct an ArrayOfRecordsWriter.  */
063    public ArrayOfRecordsWriter(CompositeEntity container, String name)
064        throws NameDuplicationException, IllegalActionException
065    {
066        super(container, name);
067
068        tableType = new StringParameter(this, "table type");
069        tableType.setExpression("text");
070        tableType.addChoice("text");
071        tableType.addChoice("HTML");
072
073        columns = new StringParameter(this, "columns");
074        columnNames = new StringParameter(this, "columnNames");
075
076        format = new StringParameter(this, "format");
077    }
078
079    ///////////////////////////////////////////////////////////////////
080    ////                         public methods                    ////
081
082
083    /** Read the formatting parameter. */
084    public void preinitialize() throws IllegalActionException
085    {
086        super.preinitialize();
087
088        _formatStr = format.stringValue();
089    }
090
091    /** The type of table output. */
092    public StringParameter tableType;
093
094    /** Comma-separated list of name and order of columns to output. */
095    public StringParameter columns;
096
097    /** Comma-separated list of column names to write in header of
098     *  table. Note: if not empty, the number of names must be the
099     *  same as the number of names in <i>columns</i>.
100     */
101    public StringParameter columnNames;
102
103    /** Formatting string for numeric data. */
104    public StringParameter format;
105
106    ///////////////////////////////////////////////////////////////////
107    ////                         protected methods                 ////
108
109    /** Set the type constraints and multiport property of the input
110     *  port. This is done here so that derived classes can override it.
111     */
112    protected void _setInputConstraints() throws IllegalActionException
113    {
114        input.setTypeAtMost(new ArrayType(RecordType.EMPTY_RECORD));
115    }
116    
117    /** Write the specified token to the current writer.
118     *  This is protected so that derived classes can modify the
119     *  format in which the token is written.
120     *  @param token The token to write.
121     */
122    protected void _writeToken(Token token) throws IllegalActionException 
123    {
124        ArrayToken arrayToken = (ArrayToken)token;
125
126        // determine the columns to output
127        String columnStr = ((StringToken)columns.getToken()).stringValue();
128        List<String> columnsList = null;
129        List<String> headersList = null;
130
131        // see if anything in columns parameter
132        if(columnStr.length() > 0)
133        {
134            // put the names in an ordered list
135            String[] columnsArray = columnStr.split("\\s*,\\s*");
136            columnsList = Arrays.asList(columnsArray);
137
138            String columnNamesStr = ((StringToken)columnNames.getToken()).stringValue();
139            
140            if(columnNamesStr.length() > 0)
141            {
142                String[] headersArray = columnNamesStr.split("\\s*,\\s*"); 
143
144                // make sure sizes match
145                if(headersArray.length != columnsArray.length)
146                {
147                    throw new IllegalActionException(this, "Different number " +
148                        " of columns and column names.");
149                }
150
151                headersList = Arrays.asList(headersArray);
152            }
153            else
154            {
155                headersList = columnsList;
156            }
157
158        }
159        else
160        {
161            // get the first record and put the labels in an
162            // ordered list
163            Set<String> labels = ((RecordToken)arrayToken.getElement(0)).labelSet();
164            columnsList = new LinkedList<String>(labels);
165        }
166
167        String tableTypeStr = ((StringToken)tableType.getToken()).stringValue();
168
169        if(tableTypeStr.equals("text"))
170        {
171            // output the header
172            for(String header: headersList)    
173            {
174                _writer.print(header + " ");
175            }
176            _writer.println();
177
178            // output the data
179            for(int i = 0; i < arrayToken.length(); i++)
180            {
181                RecordToken recordToken = 
182                    (RecordToken)arrayToken.getElement(i);
183                for(String str : columnsList)
184                {
185                    String output = _formatValue(recordToken.get(str));
186                    _writer.print(output + " ");
187                }
188                _writer.println();
189            }
190        }
191        else if(tableTypeStr.equals("HTML"))
192        {
193            _writer.println("<TABLE BORDER=1>");
194
195            // output the column names
196            _writer.print("<TR>");
197            for(String header : headersList)
198            {
199                _writer.print("<TD><B>" + header + "</B></TD>");
200            }
201            _writer.println("</TR>");
202
203            // output the data
204            for(int i = 0; i < arrayToken.length(); i++)
205            {
206                _writer.print("<TR>");
207                RecordToken recordToken =
208                    (RecordToken)arrayToken.getElement(i);
209                for(String str : columnsList) 
210                {
211                    String output = _formatValue(recordToken.get(str));
212                    _writer.print("<TD>" + output + "</TD>");
213                }
214                _writer.println("</TR>");
215            }
216
217            _writer.println("</TABLE>");
218        }
219        else
220        {
221            throw new IllegalActionException(this, "Unsupported table type: " +
222                tableTypeStr);
223        }
224    }
225
226    ///////////////////////////////////////////////////////////////////
227    ////                         private methods                   ////
228
229    /** Format a value based on the format parameter. */
230    private String _formatValue(Token token)
231    {
232        String retval = token.toString();
233        // XXX what about other types of tokens?
234        if(_formatStr.length() > 0 && (token instanceof DoubleToken))
235        {
236            double val = ((DoubleToken)token).doubleValue();
237            retval = String.format(_formatStr, val);
238        }
239        return retval;
240    }
241
242    /** Value of format parameter. */
243    private String _formatStr;
244}