001/*
002 * ============================================================================
003 * Copyright © 2002-2026 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 * Licensed to the public under the agreements of the GNU Lesser General Public
007 * License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *      http://www.gnu.org/licenses/lgpl.html
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 * License for the specific language governing permissions and limitations
015 * under the License.
016 */
017
018package org.tquadrat.foundation.value;
019
020import org.apiguardian.api.API;
021import org.tquadrat.foundation.annotation.ClassVersion;
022import org.tquadrat.foundation.lang.value.DimensionWithLinearConversion;
023
024import java.math.BigDecimal;
025
026import static java.lang.String.format;
027import static java.util.Arrays.stream;
028import static org.apiguardian.api.API.Status.STABLE;
029import static org.tquadrat.foundation.lang.Objects.requireNotEmptyArgument;
030
031/**
032 *  The various instances of volume …
033 *
034 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
035 *  @version $Id: Volume.java 1195 2026-04-15 21:33:40Z tquadrat $
036 *  @since 0.1.0
037 *
038 *  @UMLGraph.link
039 */
040@SuppressWarnings( "NewClassNamingConvention" )
041@ClassVersion( sourceVersion = "$Id: Volume.java 1195 2026-04-15 21:33:40Z tquadrat $" )
042@API( status = STABLE, since = "0.1.0" )
043public enum Volume implements DimensionWithLinearConversion
044{
045        /*------------------*\
046    ====** Enum Declaration **=================================================
047        \*------------------*/
048    /**
049     *  A cubic millimeter.
050     */
051    CUBIC_MILLIMETER( new BigDecimal( "0.000000001" ), "mm^3" )
052    {
053        /**
054         *  {@inheritDoc}
055         */
056        @Override
057        public final String unitSymbolForPrinting() { return "mm³"; }
058    },
059
060    /**
061     *  A micro liter.
062     */
063    MICRO_LITER( new BigDecimal( "0.000000001" ), "µl" ),
064
065    /**
066     *  A cubic centimeter.
067     */
068    CUBIC_CENTIMETER( new BigDecimal( "0.000001" ), "cm^3" )
069    {
070        /**
071         *  {@inheritDoc}
072         */
073        @Override
074        public final String unitSymbolForPrinting() { return "cm³"; }
075    },
076
077    /**
078     *  A milliliter.
079     */
080    MILLI_LITER( new BigDecimal( "0.000001" ), "ml" ),
081
082    /**
083     *  A centiliter.
084     */
085    CENTI_LITER( new BigDecimal( "0.00001" ), "cl" ),
086
087    /**
088     *  A cubic inch.
089     */
090    CUBIC_INCH( new BigDecimal( "0.000016387064" ), "in^3",1 )
091    {
092        /**
093         *  {@inheritDoc}
094         */
095        @Override
096        public final String unitSymbolForPrinting() { return "in³"; }
097    },
098
099    /**
100     *  An imperial fluid ounce.
101     */
102    FLUID_OUNCE_IMPERIAL( new BigDecimal( "0.0000284130625" ), "floz" ),
103
104    /**
105     *  A deciliter.
106     */
107    DECI_LITER( new BigDecimal( "0.0001" ), "dl" ),
108
109    /**
110     *  A pint liquid imperial.
111     */
112    PINT_LIQUID_IMPERIAL( new BigDecimal( "0.00056826128524935" ), "pt",1 ),
113
114    /**
115     *  A cubic decimeter.
116     */
117    CUBIC_DECIMETER( new BigDecimal( "0.001" ), "dm^3",1 )
118    {
119        /**
120         *  {@inheritDoc}
121         */
122        @Override
123        public final String unitSymbolForPrinting() { return "dm³"; }
124    },
125
126    /**
127     *  A liter.
128     */
129    LITER( new BigDecimal( "0.001" ), "l",1 ),
130
131    /**
132     *  A bucket ("Eimer" in German). Obviously, this is not an
133     *  official unit for a volume, but it is used quit often on a colloquial
134     *  basis in Germany and other German-speaking countries to describe the
135     *  amount of 10 litres.
136     */
137    BUCKET( new BigDecimal( "0.01" ), "Eimer" ),
138
139    /**
140     *  A US (liquid) gallon.
141     */
142    US_GALLON( new BigDecimal( "0.003785411784" ), "USGallon",1 )
143    {
144        /**
145         *  {@inheritDoc}
146         */
147        @Override
148        public final String unitSymbolForPrinting() { return "US Gallon"; }
149    },
150
151    /**
152     *  An imperial gallon.
153     */
154    GALLON( new BigDecimal( "0.00454609" ), "gal",1 ),
155
156    /**
157     *  A cubic foot.
158     */
159    CUBIC_FOOT( new BigDecimal( "0.028316846592" ), "ft^3" )
160    {
161        /**
162         *  {@inheritDoc}
163         */
164        @Override
165        public final String unitSymbolForPrinting() { return "ft³"; }
166    },
167
168    /**
169     *  A hekto liter.
170     */
171    HEKTO_LITER( new BigDecimal( "0.1" ), "hl",1 ),
172
173    /**
174     *  A barrel as used for mineral oil.
175     */
176    BARREL_OIL( new BigDecimal( "0.158987294928" ), "barrel(oil)" )
177    {
178        /**
179         *  {@inheritDoc}
180         */
181        @Override
182        public final String unitSymbolForPrinting() { return "barrel (oil)"; }
183    },
184
185    /**
186     *  An imperial barrel.
187     */
188    IMPERIAL_BARREL( new BigDecimal( "0.16365924" ), "barrel(imperial)",1 )
189    {
190        /**
191         *  {@inheritDoc}
192         */
193        @Override
194        public final String unitSymbolForPrinting() { return "barrel (imperial)"; }
195    },
196
197    /**
198     *  A cubic yard.
199     */
200    CUBIC_YARD( new BigDecimal( "0.764554857984" ), "yd^3" )
201    {
202        /**
203         *  {@inheritDoc}
204         */
205        @Override
206        public final String unitSymbolForPrinting() { return "yd³"; }
207    },
208
209    /**
210     *  A cubic meter.
211     */
212    CUBIC_METER( BigDecimal.ONE, "m^3",3 )
213    {
214        /**
215         *  {@inheritDoc}
216         */
217        @Override
218        public final String unitSymbolForPrinting() { return "m³"; }
219    },
220
221    /**
222     *  A "Festmeter"; this is used (in Germany) to specify an amount
223     *  of wood.
224     */
225    FESTMETER( BigDecimal.ONE, "Festmeter",1 ),
226
227    /**
228     *  <p>{@summary A ton as used by <i>Traveller</i>® to specify the volume
229     *  of a starship or other space going vessels or orbital installations.}
230     *  It is defined as the volume of one metric ton or 1000&nbsp;kg of liquid
231     *  hydrogen (H<sub>2</sub>) with a specific density of
232     *  71&nbsp;kg/m<sup>3</sup>.</p>
233     *  <p>The <i>Traveller</i>® literature also uses a value of
234     *  13.5&nbsp;m<sup>3</sup>, based on the dimensions used with ship floor
235     *  plans: a square on such a plan has a side length of 1.5&nbsp;m and the
236     *  room height is taken as 3&nbsp;m, with each square is the equivalent of
237     *  half a ton (or 6.75&nbsp;m<sup>3</sup>). For mapping purposes this is a
238     *  valid approximation.</p>
239     */
240    TON( new BigDecimal( "14.084507"), "ton" ),
241
242    /**
243     *  A cubic kilometer.
244     */
245    CUBIC_KILO_METER( new BigDecimal( "1000000000" ), "km^3",3 )
246    {
247        /**
248         *  {@inheritDoc}
249         */
250        @Override
251        public final String unitSymbolForPrinting() { return "km³"; }
252    },
253
254    /**
255     *  A cubic mile.
256     */
257    CUBIC_MILE( new BigDecimal( "4168181825.4406" ), "mi^3" )
258    {
259        /**
260         *  {@inheritDoc}
261         */
262        @Override
263        public final String unitSymbolForPrinting() { return "mi³"; }
264    };
265
266        /*------------*\
267    ====** Attributes **=======================================================
268        \*------------*/
269    /**
270     *  The factor.
271     */
272    private final BigDecimal m_Factor;
273
274    /**
275     *  The default precision.
276     */
277    private final int m_Precision;
278
279    /**
280     *  The unit string.
281     */
282    private final String m_UnitSymbol;
283
284        /*--------------*\
285    ====** Constructors **=====================================================
286        \*--------------*/
287    /**
288     *  Creates a new {@code Volume} instance, with a default precision of zero
289     *  mantissa digits.
290     *
291     *  @param  factor  The factor.
292     *  @param  unitSymbol    The unit symbol String.
293     */
294    private Volume( final BigDecimal factor, final String unitSymbol )
295    {
296        this( factor, unitSymbol, 0 );
297    }   //  Volume()
298
299    /**
300     *  Creates a new {@code Volume} instance.
301     *
302     *  @param  factor  The factor.
303     *  @param  unitSymbol    The unit symbol String.
304     *  @param  precision   The default precision.
305     */
306    private Volume( final BigDecimal factor, final String unitSymbol, final int precision )
307    {
308        m_Factor = factor.stripTrailingZeros();
309        m_UnitSymbol = unitSymbol;
310        m_Precision = precision;
311    }   //  Volume()
312
313        /*---------*\
314    ====** Methods **==========================================================
315        \*---------*/
316    /**
317     *  {@inheritDoc}
318     */
319    @Override
320    @SuppressWarnings( "unchecked" )
321    public final Volume baseUnit() { return CUBIC_METER; }
322
323    /**
324     *  {@inheritDoc}
325     */
326    @Override
327    public final BigDecimal factor() { return m_Factor; }
328
329    /**
330     *  Returns the {@code Volume} instance for the given unit symbol.
331     *
332     *  @param  unitSymbol  The unit symbol.
333     *  @return The respective instance.
334     *  @throws IllegalArgumentException    The given unit is unknown.
335     */
336    public static final Volume forUnit( final String unitSymbol ) throws IllegalArgumentException
337    {
338        requireNotEmptyArgument( unitSymbol, "unitSymbol" );
339
340        final var retValue = stream( values() )
341            .filter( v -> v.unitSymbol().equals( unitSymbol ) )
342            .findFirst()
343            .orElseThrow( () -> new IllegalArgumentException( format( MSG_UnknownUnit, unitSymbol ) ) );
344
345        //---* Done *----------------------------------------------------------
346        return retValue;
347    }   //  forUnit()
348
349    /**
350     *  {@inheritDoc}
351     */
352    @Override
353    public final int getPrecision() { return m_Precision; }
354
355    /**
356     *  {@inheritDoc}
357     */
358    @Override
359    public final String unitSymbol() { return m_UnitSymbol; }
360}
361//  enum Volume
362
363/*
364 *  End of File
365 */