001/*
002 * Copyright (c) 2015 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-10-28 21:10:03 +0000 (Wed, 28 Oct 2015) $' 
007 * '$Revision: 34138 $'
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.date;
030
031import java.util.ArrayList;
032import java.util.Date;
033import java.util.List;
034
035import org.apache.commons.lang.time.DateUtils;
036
037import ptolemy.actor.TypedAtomicActor;
038import ptolemy.actor.TypedIOPort;
039import ptolemy.actor.parameters.PortParameter;
040import ptolemy.data.ArrayToken;
041import ptolemy.data.DateToken;
042import ptolemy.data.IntToken;
043import ptolemy.data.StringToken;
044import ptolemy.data.Token;
045import ptolemy.data.expr.StringParameter;
046import ptolemy.data.type.ArrayType;
047import ptolemy.data.type.BaseType;
048import ptolemy.kernel.CompositeEntity;
049import ptolemy.kernel.util.IllegalActionException;
050import ptolemy.kernel.util.NameDuplicationException;
051import ptolemy.kernel.util.SingletonAttribute;
052
053/** An actor that generates a sequence of dates between a starting and stopping
054 *  date.
055 * 
056 *  @author Daniel Crawl
057 *  @version $Id: DateSequence.java 34138 2015-10-28 21:10:03Z crawl $
058 */
059public class DateSequence extends TypedAtomicActor {
060
061        public DateSequence(CompositeEntity container, String name)
062                        throws IllegalActionException, NameDuplicationException {
063
064                super(container, name);
065                
066                start = new TypedIOPort(this, "start", true, false);
067                start.setTypeEquals(BaseType.DATE);
068                new SingletonAttribute(start, "_showName");
069                
070                stop = new TypedIOPort(this, "stop", true, false);
071                stop.setTypeEquals(BaseType.DATE);
072                new SingletonAttribute(stop, "_showName");
073
074                step = new PortParameter(this, "step");
075                step.setTypeEquals(BaseType.INT);
076                new SingletonAttribute(step.getPort(), "_showName");
077
078                stepUnits = new StringParameter(this, "stepUnits");
079                for(Units unit : Units.values()) {
080                        stepUnits.addChoice(unit.toString());
081                }
082
083                output = new TypedIOPort(this, "output", false, true);
084                output.setTypeEquals(new ArrayType(BaseType.DATE));
085        }
086        
087        @Override
088        public void fire() throws IllegalActionException {
089                
090                super.fire();
091                
092                step.update();
093                
094                Token token = start.get(0);
095                if(token == null) {
096                        throw new IllegalActionException(this, "Missing value for start.");
097                }
098                Date startDate = new Date(((DateToken)token).getValue());
099
100                token = stop.get(0);
101                if(token == null) {
102                        throw new IllegalActionException(this, "Missing value for stop.");
103                }
104                Date endDate = new Date(((DateToken)token).getValue());
105                                
106                token = step.getToken();
107                if(token == null) {
108                        throw new IllegalActionException(this, "Missing value for step.");
109                }
110                int stepVal = ((IntToken)token).intValue();
111                
112                token = stepUnits.getToken();
113                if(token == null) {
114                        throw new IllegalActionException(this, "Missing value for stepUnits.");
115                }
116                String unitsStr = ((StringToken)token).stringValue(); 
117                
118                // sanity checks
119                if(startDate.after(endDate)) {
120                        throw new IllegalActionException(this, "End date (" +
121                                endDate +
122                                ") must be equal to or after start date (" +
123                                startDate +
124                                ").");
125                }
126
127                if(stepVal < 1) {
128                        throw new IllegalActionException(this, "Step size must be at least 1."); 
129                }               
130
131                Units units = Units.valueOf(unitsStr);
132                if(units == null) {
133                        throw new IllegalActionException(this, "Unknown typed of step units: " + unitsStr);
134                }
135
136                // create sequence of dates
137                List<Token> tokens = new ArrayList<Token>();
138                Date curDate = startDate;
139                
140                while(curDate.before(endDate) || curDate.equals(endDate)) {
141                        
142                        tokens.add(new DateToken(curDate.getTime()));
143                        
144                        // increment the current date
145                        switch(units) {
146                        case Second:
147                                curDate = DateUtils.addSeconds(curDate, stepVal);
148                                break;
149                        case Minute:
150                                curDate = DateUtils.addMinutes(curDate, stepVal);
151                                break;
152                        case Hour:
153                                curDate = DateUtils.addHours(curDate, stepVal);
154                                break;
155                        case Day:
156                                curDate = DateUtils.addDays(curDate, stepVal);
157                                break;
158                        case Month:
159                                curDate = DateUtils.addMonths(curDate, stepVal);
160                                break;
161                        case Year:
162                                curDate = DateUtils.addYears(curDate, stepVal);
163                                break;
164                        }
165                }
166                
167                output.broadcast(new ArrayToken(tokens.toArray(new Token[tokens.size()])));
168                
169        }
170        
171        /** The starting date. */
172        public TypedIOPort start;
173        
174        /** The stopping date. */
175        public TypedIOPort stop;
176        
177        /** The increment between steps. */
178        public PortParameter step;
179        
180        /** The units of the incremental step. */
181        public StringParameter stepUnits;
182
183        /** The sequence of dates. */
184        public TypedIOPort output;
185        
186        /** Enumeration of unit types. */
187        private enum Units { Year, Month, Day, Hour, Minute, Second };
188        
189}