001/*
002 * Units of Measurement API
003 * Copyright (c) 2014-2023, Jean-Marie Dautelle, Werner Keil, Otavio Santana.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-385 nor the names of its contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package javax.measure.test.quantity;
031
032import javax.measure.Quantity;
033import javax.measure.Unit;
034import javax.measure.quantity.Dimensionless;
035import javax.measure.test.TestUnit;
036import javax.measure.test.unit.BaseUnit;
037
038/**
039 * @author Werner Keil
040 * @version 2.0
041 * @since 1.0
042 */
043public abstract class TestQuantity<Q extends Quantity<Q>> implements Quantity<Q>, Comparable<Quantity<Q>> {
044
045    @SuppressWarnings("rawtypes")
046        public static final Quantity<Dimensionless> ONE = new DimensionlessQuantity(1d, (BaseUnit) TestUnit.ONE);
047
048    protected double scalar; // value in reference value
049    protected double value; // value in value (Unit unit)
050    protected TestUnit<Q> unit; // unit
051    private final Class<Q> type; // quantity type
052    private final Scale scale;
053
054    protected TestQuantity(Class<Q> type, Scale scale) {
055        this.type = type;
056        this.scale = scale;
057    }
058
059    protected TestQuantity(Class<Q> type) {
060        this(type, Scale.ABSOLUTE);
061    }
062
063    public Class<Q> getType() {
064        return this.type;
065    }
066
067    public TestQuantity<Q> add(TestQuantity<Q> dn, TestQuantity<Q> d1, TestQuantity<Q> d2, TestUnit<Q> au) {
068        if (d1.unit == d2.unit) {
069            dn.unit = d1.unit;
070            dn.scalar = d1.scalar + d2.scalar;
071            dn.value = d1.value + d2.value;
072        } else {
073            dn.unit = au;
074            dn.scalar = d1.scalar + d2.scalar;
075            dn.value = dn.scalar;
076        }
077        return dn;
078    }
079
080    public TestQuantity<Q> subtract(TestQuantity<Q> dn, TestQuantity<Q> d1, TestQuantity<Q> d2, TestUnit<Q> au) {
081        if (d1.unit == d2.unit) {
082            dn.unit = d1.unit;
083            dn.scalar = d1.scalar - d2.scalar;
084            dn.value = d1.value - d2.value;
085        } else {
086            dn.unit = au;
087            dn.scalar = d1.scalar - d2.scalar;
088            dn.value = dn.scalar;
089        }
090        return dn;
091    }
092
093    public boolean eq(TestQuantity<Q> d1) {
094        return (scalar == d1.scalar);
095    }
096
097    public boolean ne(TestQuantity<Q> d1) {
098        return (scalar != d1.scalar);
099    }
100
101    public boolean gt(TestQuantity<Q> d1) {
102        return (scalar > d1.scalar);
103    }
104
105    public boolean lt(TestQuantity<Q> d1) {
106        return (scalar < d1.scalar);
107    }
108
109    public boolean ge(TestQuantity<Q> d1) {
110        return (scalar >= d1.scalar);
111    }
112
113    public boolean le(TestQuantity<Q> d1) {
114        return (scalar <= d1.scalar);
115    }
116
117    @Override
118    public String toString() {
119        return (Double.valueOf(value)).toString() + ' ' + String.valueOf(unit);
120    }
121
122    /**
123     * Compares this quantity to the specified Measurement quantity. The default implementation compares the {@link Quantity#getValue()} of both this
124     * quantity and the specified Quantity stated in the same unit (this quantity's {@link #getUnit() unit}).
125     *
126     * @return a negative integer, zero, or a positive integer as this quantity is less than, equal to, or greater than the specified Quantity
127     *         quantity.
128     */
129    public int compareTo(Quantity<Q> that) {
130        return Double.compare(value, that.getValue().doubleValue());
131    }
132
133    protected String showInUnits(TestUnit<?> u, int precision) {
134        double result = scalar / u.getMultFactor();
135
136        String str = (Double.valueOf(result)).toString();
137        char cs[] = str.toCharArray();
138        int i = 0;
139        while (i < cs.length && (cs[i] >= '0' && cs[i] <= '9' || cs[i] == '.')) {
140            i++;
141        }
142        Double bd = new Double(new String(cs, 0, i));
143        // BigDecimal bd2 = bd.setScale(precision, RoundingMode.HALF_UP);
144        // str = bd2.toString();
145        str = bd.toString();
146
147        String exp = "";
148        if (i < cs.length) {
149            exp = new String(cs, i, cs.length - i);
150        }
151        return str + exp + ' ' + u.getName();
152    }
153
154    public Number getValue() {
155        return value;
156    }
157
158    public Unit<Q> getUnit() {
159        return unit;
160    }
161
162    public Scale getScale() {
163        return scale;
164    }
165    
166    @Override
167    public boolean isEquivalentTo(Quantity<Q> that) {
168        return this.compareTo(that) == 0;
169    }
170}