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.data.conversion;
031
032import java.util.HashMap;
033import java.util.Map;
034import java.util.Set;
035
036import ptolemy.actor.TypedAtomicActor;
037import ptolemy.actor.TypedIOPort;
038import ptolemy.data.ArrayToken;
039import ptolemy.data.RecordToken;
040import ptolemy.data.Token;
041import ptolemy.data.type.ArrayType;
042import ptolemy.data.type.BaseType;
043import ptolemy.data.type.MonotonicFunction;
044import ptolemy.data.type.RecordType;
045import ptolemy.data.type.Type;
046import ptolemy.graph.InequalityTerm;
047import ptolemy.kernel.CompositeEntity;
048import ptolemy.kernel.util.IllegalActionException;
049import ptolemy.kernel.util.NameDuplicationException;
050
051/**
052
053   Convert an array of records to a record of arrays.
054   
055   @author Daniel Crawl
056   @version $Id: ArrayOfRecordsToRecordOfArrays.java 24234 2010-05-06 05:21:26Z welker $
057
058 */
059public class ArrayOfRecordsToRecordOfArrays extends TypedAtomicActor
060{
061    /** Construct an ArrayOfRecordsToRecordOfArrays with the given container
062     *  and name.  
063     */
064    public ArrayOfRecordsToRecordOfArrays(CompositeEntity container, String name)
065        throws NameDuplicationException, IllegalActionException
066    {
067        super(container, name);
068
069        input = new TypedIOPort(this, "input", true, false);
070        input.setTypeAtMost(new ArrayType(RecordType.EMPTY_RECORD));
071
072        output = new TypedIOPort(this, "output", false, true);
073        output.setTypeAtLeast(new FunctionTerm());
074
075        _attachText("_iconDescription",
076            "<svg>\n" + "<rect x=\"0\" y=\"0\" " +
077            "width=\"60\" height=\"20\" " + "style=\"fill:white\"/>\n" +
078            "</svg>\n");
079    }
080
081    ///////////////////////////////////////////////////////////////////
082    ////                     ports and parameters                  ////
083
084    /** The input array of records. */
085    public TypedIOPort input;
086    
087    /** The output record of arrays. */
088    public TypedIOPort output;
089
090    ///////////////////////////////////////////////////////////////////
091    ////                         public methods                    ////
092
093    /** Convert an input array of records.  */
094    public void fire() throws IllegalActionException
095    {
096        super.fire();
097
098        ArrayToken array = (ArrayToken)input.get(0);
099        int length = array.length();
100        
101        Map<String,Token[]> map = new HashMap<String,Token[]>();
102
103        RecordType elementType = (RecordType)array.getElementType();
104        Set<String> labels = elementType.labelSet();
105        for(String label : labels)
106        {
107            map.put(label, new Token[length]);
108        }
109
110        for(int i = 0; i < length; i++)
111        {
112            RecordToken element = (RecordToken)array.getElement(i);
113            for(String label : labels)
114            {
115                Token[] outArray = map.get(label);
116                //XXX need to clone the token
117                outArray[i] = element.get(label);
118            }
119        }
120
121        // replace Token[] with (Array)Token
122        Map<String,Token> outMap = new HashMap<String,Token>();
123        for(String label : labels)
124        {
125            Token[] outArray = map.get(label); 
126            outMap.put(label, new ArrayToken(outArray));
127        }
128        
129        output.broadcast(new RecordToken(outMap));
130    }
131
132    /** A class to determine the type of the output port. */
133    private class FunctionTerm extends MonotonicFunction
134    {
135        /** Get the type. Return a type representing the output record of
136         *  arrays.
137         */
138        public Object getValue()
139        {
140            Type retval = BaseType.UNKNOWN;
141            
142            Type inType = input.getType();
143            if(inType instanceof ArrayType)
144            {
145                Type inRecType = ((ArrayType)inType).getElementType();
146                if(inRecType instanceof RecordType)
147                {
148                    Set<String> labels = ((RecordType)inRecType).labelSet();
149                    Type[] outTypes = new Type[labels.size()];
150                    int i = 0;
151                    for(String label : labels)
152                    {
153                        outTypes[i] = new ArrayType(((RecordType)inRecType).get(label));
154                        i++;
155                    }
156                    retval = new RecordType(labels.toArray(new String[0]), outTypes);
157                }
158            }
159
160            //System.out.println("returning type = " + retval);
161            return retval;
162        }
163
164        /** Return the variables. Return the input port term. */
165        public InequalityTerm[] getVariables()
166        {
167            return new InequalityTerm[] { input.getTypeTerm() };
168        }
169    }
170}