001/* Modify date by adding or subtracting a value to one of the date fields.
002
003   @Copyright (c) 2008-2016 The Regents of the University of California.
004   All rights reserved.
005
006   Permission is hereby granted, without written agreement and without
007   license or royalty fees, to use, copy, modify, and distribute this
008   software and its documentation for any purpose, provided that the
009   above copyright notice and the following two paragraphs appear in all
010   copies of this software.
011
012   IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013   FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014   ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015   THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016   SUCH DAMAGE.
017
018   THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021   PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022   CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023   ENHANCEMENTS, OR MODIFICATIONS.
024
025   PT_COPYRIGHT_VERSION_2
026   COPYRIGHTENDKEY
027
028 */
029package ptolemy.actor.lib;
030
031import java.util.Calendar;
032
033import ptolemy.actor.TypedAtomicActor;
034import ptolemy.actor.TypedIOPort;
035import ptolemy.data.DateToken;
036import ptolemy.data.IntToken;
037import ptolemy.data.StringToken;
038import ptolemy.data.expr.Parameter;
039import ptolemy.data.expr.StringParameter;
040import ptolemy.data.type.BaseType;
041import ptolemy.kernel.CompositeEntity;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.NameDuplicationException;
044
045///////////////////////////////////////////////////////////////////
046//// DateElements
047
048/**
049  Modify date by adding or subtracting a value to one of the date fields.
050
051 @author Patricia Derler
052 @version $Id$
053 @since Ptolemy II 10.0
054 @Pt.ProposedRating Red (pd)
055 @Pt.AcceptedRating Red (pd)
056 */
057public class ModifyDate extends TypedAtomicActor {
058    /** Construct an actor with the given container and name.
059     *  @param container The container.
060     *  @param name The name of this actor.
061     *  @exception IllegalActionException If the actor cannot be contained
062     *   by the proposed container.
063     *  @exception NameDuplicationException If the container already has an
064     *   actor with this name.
065     */
066    public ModifyDate(CompositeEntity container, String name)
067            throws NameDuplicationException, IllegalActionException {
068        super(container, name);
069
070        input = new TypedIOPort(this, "input", true, false);
071        input.setTypeEquals(BaseType.DATE);
072
073        operation = new StringParameter(this, "operation");
074        operation.addChoice("+");
075        operation.addChoice("-");
076        operation.setToken(new StringToken("+"));
077
078        value = new TypedIOPort(this, "value", true, false);
079        value.setTypeEquals(BaseType.INT);
080
081        unit = new StringParameter(this, "unit");
082        unit.addChoice("Year");
083        unit.addChoice("Month");
084        unit.addChoice("Day");
085        unit.addChoice("Hour");
086        unit.addChoice("Minute");
087        unit.addChoice("Second");
088        unit.addChoice("Millisecond");
089        unit.addChoice("Microsecond");
090        unit.addChoice("Nanosecond");
091        unit.setToken(new StringToken("Second"));
092
093        output = new TypedIOPort(this, "output", false, true);
094        output.setTypeEquals(BaseType.DATE);
095    }
096
097    /** Input for date tokens.
098     */
099    public TypedIOPort input;
100
101    /** Parameter for operation. The operation is a choice of the string
102     *  values "+" and "-" and defaults to "+".
103     */
104    public Parameter operation;
105
106    /** Input for value in a given unit to be added or subtracted from date
107     *  token received by input.
108     */
109    public TypedIOPort value;
110
111    /** Unit of value to be added or subtracted. This can be either part of
112     *  the date, i.e. year, month, day, ... and it defaults to second.
113     */
114    public Parameter unit;
115
116    /** Output for the new date token.
117     */
118    public TypedIOPort output;
119
120    ///////////////////////////////////////////////////////////////////
121    ////                         public methods                    ////
122
123    /** Compute the absolute value of the input.  If there is no input, then
124     *  produce no output.
125     *  @exception IllegalActionException If there is no director.
126     */
127    @Override
128    public void fire() throws IllegalActionException {
129        super.fire();
130        if (input.hasToken(0)) {
131            DateToken inputToken = (DateToken) input.get(0);
132
133            DateToken token = new DateToken(inputToken.getValue(),
134                    inputToken.getPrecision(), inputToken.getTimeZone());
135
136            String operationString = ((StringToken) operation.getToken())
137                    .stringValue();
138            String unitString = ((StringToken) unit.getToken()).stringValue();
139
140            int val = ((IntToken) value.get(0)).intValue();
141            if (operationString.equals("+")) {
142                //nothing to do;
143            } else if (operationString.equals("-")) {
144                val = val * (-1);
145            } else {
146                throw new IllegalActionException(this,
147                        "Operation " + operationString + " not supported.");
148            }
149
150            boolean setUsingCalendar = true;
151            Calendar calendar = token.getCalendarInstance();
152            if (unitString.equals("Year")) {
153                calendar.add(Calendar.YEAR, val);
154            } else if (unitString.equals("Month")) {
155                calendar.add(Calendar.MONTH, val);
156            } else if (unitString.equals("Day")) {
157                calendar.add(Calendar.DAY_OF_MONTH, val);
158            } else if (unitString.equals("Hour")) {
159                calendar.add(Calendar.HOUR_OF_DAY, val);
160            } else if (unitString.equals("Minute")) {
161                calendar.add(Calendar.MINUTE, val);
162            } else if (unitString.equals("Second")) {
163                calendar.add(Calendar.SECOND, val);
164            } else if (unitString.equals("Millisecond")) {
165                calendar.add(Calendar.MILLISECOND, val);
166            } else if (unitString.equals("Microsecond")) {
167                setUsingCalendar = false;
168                token.addMicroseconds(val);
169                // Update _value and _calendar in DateToken.
170                token.setTimeInMilliseconds(token.getTimeInMilliseconds());
171            } else if (unitString.equals("Nanosecond")) {
172                setUsingCalendar = false;
173                token.addNanoseconds(val);
174                // Update _value and _calendar in DateToken.
175                token.setTimeInMilliseconds(token.getTimeInMilliseconds());
176            } else {
177                throw new IllegalActionException(this,
178                        "The unit " + unitString + " is not supported");
179            }
180
181            // If units are greater than milliseonds
182            if (setUsingCalendar) {
183                // Update _value and _calendar in DateToken.
184                token.setTimeInMilliseconds(calendar.getTimeInMillis());
185            }
186
187            output.send(0, token);
188        }
189    }
190}