001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2018, 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, Indriya nor the names of their 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 tech.units.indriya.format;
031
032import java.io.IOException;
033import java.math.BigDecimal;
034import java.text.ParsePosition;
035import javax.measure.Quantity;
036import javax.measure.Unit;
037import javax.measure.format.MeasurementParseException;
038
039import tech.units.indriya.AbstractQuantity;
040import tech.units.indriya.AbstractUnit;
041import tech.units.indriya.ComparableQuantity;
042import tech.units.indriya.quantity.NumberQuantity;
043import tech.units.indriya.quantity.Quantities;
044
045/**
046 * A simple implementation of QuantityFormat
047 * @version 0.9
048 * @since 2.0
049 */
050@SuppressWarnings("rawtypes")
051public class SimpleQuantityFormat extends AbstractQuantityFormat {
052        /**
053         * Holds the default format instance.
054         */
055        private static final SimpleQuantityFormat DEFAULT = new SimpleQuantityFormat();
056
057        /**
058         * The pattern string of this formatter. This is always a non-localized pattern.
059         * May not be null. See class documentation for details.
060         * 
061         * @serial
062         */
063        private String pattern;
064
065        /**
066        *
067        */
068        private static final long serialVersionUID = 2758248665095734058L;
069
070        /**
071         * Constructs a <code>SimpleQuantityFormat</code> using the given pattern.
072         * <p>
073         * 
074         * @param pattern
075         *            the pattern describing the quantity and unit format
076         * @exception NullPointerException
077         *                if the given pattern is null
078         * @exception IllegalArgumentException
079         *                if the given pattern is invalid
080         */
081        public SimpleQuantityFormat(String pattern) {
082                this.pattern = pattern;
083        }
084
085        /**
086         * Constructs a <code>SimpleQuantityFormat</code> using the default pattern. For
087         * full coverage, use the factory methods.
088         */
089        public SimpleQuantityFormat() {
090                this("");
091        }
092
093        @Override
094        public Appendable format(Quantity quantity, Appendable dest) throws IOException {
095                Unit unit = quantity.getUnit();
096
097                dest.append(quantity.getValue().toString());
098                if (quantity.getUnit().equals(AbstractUnit.ONE))
099                        return dest;
100                dest.append(' ');
101                return SimpleUnitFormat.getInstance().format(unit, dest);
102        }
103
104        @SuppressWarnings("unchecked")
105        @Override
106        public ComparableQuantity<?> parse(CharSequence csq, ParsePosition cursor) throws MeasurementParseException {
107                int startDecimal = cursor.getIndex();
108                while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) {
109                        startDecimal++;
110                }
111                int endDecimal = startDecimal + 1;
112                while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) {
113                        endDecimal++;
114                }
115                BigDecimal decimal = new BigDecimal(csq.subSequence(startDecimal, endDecimal).toString());
116                cursor.setIndex(endDecimal + 1);
117                Unit unit = SimpleUnitFormat.getInstance().parse(csq, cursor);
118                return Quantities.getQuantity(decimal, unit);
119        }
120
121        @SuppressWarnings("unchecked")
122        @Override
123        AbstractQuantity<?> parse(CharSequence csq, int index) throws MeasurementParseException {
124                int startDecimal = index; // cursor.getIndex();
125                while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) {
126                        startDecimal++;
127                }
128                int endDecimal = startDecimal + 1;
129                while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) {
130                        endDecimal++;
131                }
132                Double decimal = new Double(csq.subSequence(startDecimal, endDecimal).toString());
133                Unit unit = SimpleUnitFormat.getInstance().parse(csq, index);
134                return NumberQuantity.of(decimal, unit);
135        }
136
137        @Override
138        public ComparableQuantity<?> parse(CharSequence csq) throws MeasurementParseException {
139                return parse(csq, new ParsePosition(0));
140        }
141
142        /**
143         * Returns the quantity format for the default locale. The default format
144         * assumes the quantity is composed of a decimal number and a {@link Unit}
145         * separated by whitespace(s).
146         *
147         * @return <code>MeasureFormat.getInstance(NumberFormat.getInstance(), UnitFormat.getInstance())</code>
148         */
149        public static SimpleQuantityFormat getInstance() {
150                return DEFAULT;
151        }
152        
153        /**
154         * Returns a <code>SimpleQuantityFormat</code> using the given pattern.
155         * <p>
156         * 
157         * @param pattern
158         *            the pattern describing the quantity and unit format
159         *
160         * @return <code>MeasureFormat.getInstance(NumberFormat.getInstance(), UnitFormat.getInstance())</code>
161         */
162        public static SimpleQuantityFormat getInstance(String pattern) {
163                return new SimpleQuantityFormat(pattern);
164        }
165
166        public String getPattern() {
167                return pattern;
168        }
169}