001/**
002 * ScalarParam -- A parameter that contains a single scalar value.
003 *
004 * Copyright (C) 2003-2017, by Joseph A. Huwaldt. All rights reserved.
005 *
006 * This library is free software; you can redistribute it and/or modify it under the terms
007 * of the GNU Lesser General Public License as published by the Free Software Foundation;
008 * either version 2 of the License, or (at your option) any later version.
009 *
010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
012 * PARTICULAR PURPOSE. See the GNU Library General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License along with
015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html
017 */
018package jahuwaldt.js.datareader;
019
020import jahuwaldt.js.param.Parameter;
021import java.text.MessageFormat;
022import java.util.Objects;
023import static java.util.Objects.requireNonNull;
024import javax.measure.converter.ConversionException;
025import javax.measure.quantity.Quantity;
026import javax.measure.unit.Unit;
027import javolution.context.ObjectFactory;
028import javolution.text.Text;
029
030/**
031 * A class that represents a scalar data value in a case.
032 *
033 * <p> Modified by: Joseph A. Huwaldt </p>
034 *
035 * @author Joseph A. Huwaldt, Date: March 5, 2003
036 * @version March 18, 2017
037 * @param <Q> Unit quantity type.
038 */
039public final class ScalarParam<Q extends Quantity> extends UnitParameter<Q, ScalarParam> {
040
041    //  The Parameter object backing this ScalarParam object.
042    private Parameter<Q> _param;
043
044    //////////////////////
045    // Factory Creation //
046    //////////////////////
047    /**
048     * Returns a new, preallocated or recycled <code>ScalarParam</code> instance (on the
049     * stack when executing in a <code>StackContext</code>) with the specified name, no
050     * units, and a value of 0.
051     *
052     * @param name The name to be assigned to this parameter (may not be
053     *             <code>null</code>).
054     */
055    private static ScalarParam newInstance(CharSequence name) {
056        ScalarParam o = FACTORY.object();
057        try {
058            o.setName(name);
059        } catch (NullPointerException e) {
060            FACTORY.recycle(o);
061            throw e;
062        }
063        return o;
064    }
065
066    private static <Q extends Quantity> ScalarParam<Q> copyOf(ScalarParam<Q> original) {
067        ScalarParam<Q> measure = FACTORY.object();
068        measure._param = original._param.copy();
069        measure._unit = original._unit;
070        return measure;
071    }
072
073    private static final ObjectFactory<ScalarParam> FACTORY = new ObjectFactory<ScalarParam>() {
074        @Override
075        protected ScalarParam create() {
076            return new ScalarParam();
077        }
078
079        @Override
080        protected void cleanup(ScalarParam obj) {
081            obj.reset();
082        }
083    };
084
085    /**
086     * Resets the internal state of this object to its default values.
087     */
088    @Override
089    protected void reset() {
090        super.reset();
091        _param = null;
092    }
093
094    /**
095     * Returns a copy of this parameter
096     * {@link javolution.context.AllocatorContext allocated} by the calling thread
097     * (possibly on the stack).
098     *
099     * @return an identical and independent copy of this parameter.
100     */
101    @Override
102    public ScalarParam<Q> copy() {
103        return copyOf(this);
104    }
105
106    /**
107     * Recycles a parameter instance immediately (on the stack when executing in a
108     * StackContext).
109     *
110     * @param instance The instance to be recycled immediately.
111     */
112    public static void recycle(ScalarParam instance) {
113        FACTORY.recycle(instance);
114    }
115
116    /**
117     * Do not allow the default constructor to be used.
118     */
119    private ScalarParam() {
120    }
121
122    /**
123     * Returns a scalar with the specified name, value and units.
124     *
125     * @param <Q>   The unit quantity type for this parameter.
126     * @param name  The name of the parameter (may not be null).
127     * @param value The value to assign to this scalar in the specified units.
128     * @param unit  The units for this scalar (may not be null).
129     * @return A new scalar with the specified value and units.
130     */
131    public static <Q extends Quantity> ScalarParam<Q> valueOf(CharSequence name, double value, Unit<Q> unit) {
132
133        ScalarParam<Q> param = ScalarParam.newInstance(requireNonNull(name));
134        param._unit = requireNonNull(unit);
135        param._param = Parameter.valueOf(value, unit);
136
137        return param;
138    }
139
140    /**
141     * Returns the parameter equivalent to this parameter but stated in the specified
142     * unit.
143     *
144     * @param unit The unit of the parameter to be returned (may not be null).
145     * @return A parameter equivalent to this parameter but stated in the specified unit.
146     * @throws ConversionException if the current model does not allows for conversion to
147     * the specified unit.
148     */
149    @Override
150    public ScalarParam<Q> to(Unit<Q> unit) throws ConversionException {
151        if (Objects.equals(_unit, requireNonNull(unit)))
152            return this;
153        ScalarParam<Q> result = ScalarParam.newInstance(getName());
154        result._unit = unit;
155        result._param = _param.to(unit);
156        return result;
157    }
158
159    /**
160     * Returns the parameter that has the same values as this parameter but with the units
161     * changed (<em>without</em> converting the values).
162     *
163     * @param unit The unit of the parameter to be returned (may not be null).
164     * @return a parameter equivalent to this parameter but stated in the specified unit.
165     * @throws ConversionException if the current model does not allows for conversion to
166     * the specified unit.
167     */
168    @Override
169    public <R extends Quantity> ScalarParam<R> changeTo(Unit<R> unit) throws ConversionException {
170        requireNonNull(unit, MessageFormat.format(RESOURCES.getString("paramNullErr"),"unit"));
171        if (Objects.equals(_unit, unit))
172            return (ScalarParam<R>)this;
173        ScalarParam<R> result = (ScalarParam<R>)FACTORY.object();
174        result._unit = unit;
175        result._param = Parameter.valueOf(getValue(), unit);
176        return result;
177    }
178
179    /**
180     * Return the value of this parameter in reference SI units.
181     * 
182     * @return The value of this parameter in reference SI units.
183     */
184    public double getValueSI() {
185        Unit<Q> SIUnit = (Unit<Q>)getUnit().getStandardUnit();
186        return _param.getValue(SIUnit);
187    }
188
189    /**
190     * Returns the value for this parameter stated in this parameter's
191     * {@link #getUnit unit}.
192     *
193     * @return the value of the parameter.
194     */
195    public double getValue() {
196        return _param.getValue();
197    }
198
199    /**
200     * Compares the specified object with this parameter for strict equality same value,
201     * same units, same name, same user data.
202     *
203     * @param obj the object to compare with.
204     * @return <code>true</code> if this parameter is identical to that parameter;
205     *         <code>false</code> otherwise.
206     */
207    @Override
208    public boolean equals(Object obj) {
209        if (this == obj)
210            return true;
211        if ((obj == null) || (obj.getClass() != this.getClass()))
212            return false;
213
214        ScalarParam that = (ScalarParam)obj;
215        if (!this._param.equals(that._param))
216            return false;
217
218        return super.equals(obj);
219    }
220
221    /**
222     * Returns the hash code for this <code>UnitParameter</code>.
223     *
224     * @return the hash code value.
225     */
226    @Override
227    public int hashCode() {
228        int hash = super.hashCode();
229
230        hash = hash * 31 + _param.hashCode();
231
232        return hash;
233    }
234
235    /**
236     * Create a Text representation of this parameter which consists of the parameter's
237     * name, value and unit.
238     * 
239     * @return The Text representation of this parameter.
240     */
241    @Override
242    public Text toText() {
243        return _param.toText();
244    }
245
246    /**
247     * Create a String representation of this parameter which consists of the parameter's
248     * name + value + units.
249     * 
250     * @return A String representation of this parameter.
251     */
252    @Override
253    public String toString() {
254        return toText().toString();
255    }
256}