1dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/*
2dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Licensed to the Apache Software Foundation (ASF) under one or more
3dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * contributor license agreements.  See the NOTICE file distributed with
4dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * this work for additional information regarding copyright ownership.
5dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ASF licenses this file to You under the Apache License, Version 2.0
6dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (the "License"); you may not use this file except in compliance with
7dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the License.  You may obtain a copy of the License at
8dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
9dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *      http://www.apache.org/licenses/LICENSE-2.0
10dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
11dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Unless required by applicable law or agreed to in writing, software
12dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * distributed under the License is distributed on an "AS IS" BASIS,
13dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * See the License for the specific language governing permissions and
15dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * limitations under the License.
16dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
17dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
18dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpackage org.apache.commons.math.fraction;
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.Serializable;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.math.BigInteger;
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.text.FieldPosition;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.text.NumberFormat;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.text.ParseException;
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.text.ParsePosition;
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.util.Locale;
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.MathRuntimeException;
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.util.LocalizedFormats;
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Formats a BigFraction number in proper format or improper format.
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The number format for each of the whole number, numerator and,
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * denominator can be configured.
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * </p>
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @since 2.0
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 août 2010) $
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class BigFractionFormat extends AbstractFormat implements Serializable {
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Serializable version identifier */
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final long serialVersionUID = -2932167925527338976L;
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create an improper formatting instance with the default number format
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * for the numerator and denominator.
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigFractionFormat() {
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create an improper formatting instance with a custom number format for
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * both the numerator and denominator.
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param format the custom format for both the numerator and denominator.
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigFractionFormat(final NumberFormat format) {
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super(format);
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Create an improper formatting instance with a custom number format for
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * the numerator and a custom number format for the denominator.
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param numeratorFormat the custom format for the numerator.
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param denominatorFormat the custom format for the denominator.
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigFractionFormat(final NumberFormat numeratorFormat,
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                             final NumberFormat denominatorFormat) {
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super(numeratorFormat, denominatorFormat);
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Get the set of locales for which complex formats are available.  This
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * is the same set as the {@link NumberFormat} set.
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return available complex format locales.
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static Locale[] getAvailableLocales() {
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return NumberFormat.getAvailableLocales();
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * This static method calls formatBigFraction() on a default instance of
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * BigFractionFormat.
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param f BigFraction object to format
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return A formatted BigFraction in proper form.
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static String formatBigFraction(final BigFraction f) {
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return getImproperInstance().format(f);
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the default complex format for the current locale.
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the default complex format.
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static BigFractionFormat getImproperInstance() {
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return getImproperInstance(Locale.getDefault());
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the default complex format for the given locale.
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param locale the specific locale used by the format.
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the complex format specific to the given locale.
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static BigFractionFormat getImproperInstance(final Locale locale) {
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigFractionFormat(getDefaultNumberFormat(locale));
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the default complex format for the current locale.
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the default complex format.
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static BigFractionFormat getProperInstance() {
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return getProperInstance(Locale.getDefault());
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the default complex format for the given locale.
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param locale the specific locale used by the format.
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the complex format specific to the given locale.
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static BigFractionFormat getProperInstance(final Locale locale) {
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new ProperBigFractionFormat(getDefaultNumberFormat(locale));
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Formats a {@link BigFraction} object to produce a string.  The BigFraction is
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * output in improper format.
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param BigFraction the object to format.
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param toAppendTo where the text is to be appended
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param pos On input: an alignment field, if desired. On output: the
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *            offsets of the alignment field
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the value passed in as toAppendTo.
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public StringBuffer format(final BigFraction BigFraction,
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                               final StringBuffer toAppendTo, final FieldPosition pos) {
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        pos.setBeginIndex(0);
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        pos.setEndIndex(0);
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        getNumeratorFormat().format(BigFraction.getNumerator(), toAppendTo, pos);
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        toAppendTo.append(" / ");
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        getDenominatorFormat().format(BigFraction.getDenominator(), toAppendTo, pos);
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return toAppendTo;
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Formats an object and appends the result to a StringBuffer.
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>obj</code> must be either a  {@link BigFraction} object or a
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * {@link BigInteger} object or a {@link Number} object. Any other type of
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * object will result in an {@link IllegalArgumentException} being thrown.
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param obj the object to format.
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param toAppendTo where the text is to be appended
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param pos On input: an alignment field, if desired. On output: the
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *            offsets of the alignment field
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the value passed in as toAppendTo.
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException is <code>obj</code> is not a valid type.
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public StringBuffer format(final Object obj,
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                               final StringBuffer toAppendTo, final FieldPosition pos) {
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final StringBuffer ret;
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (obj instanceof BigFraction) {
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            ret = format((BigFraction) obj, toAppendTo, pos);
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else if (obj instanceof BigInteger) {
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            ret = format(new BigFraction((BigInteger) obj), toAppendTo, pos);
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else if (obj instanceof Number) {
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            ret = format(new BigFraction(((Number) obj).doubleValue()),
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                         toAppendTo, pos);
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                LocalizedFormats.CANNOT_FORMAT_OBJECT_TO_FRACTION);
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return ret;
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Parses a string to produce a {@link BigFraction} object.
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param source the string to parse
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the parsed {@link BigFraction} object.
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @exception ParseException if the beginning of the specified string
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *            cannot be parsed.
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigFraction parse(final String source) throws ParseException {
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final ParsePosition parsePosition = new ParsePosition(0);
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigFraction result = parse(source, parsePosition);
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (parsePosition.getIndex() == 0) {
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createParseException(
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    parsePosition.getErrorIndex(),
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    LocalizedFormats.UNPARSEABLE_FRACTION_NUMBER, source);
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return result;
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Parses a string to produce a {@link BigFraction} object.
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * This method expects the string to be formatted as an improper BigFraction.
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param source the string to parse
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param pos input/ouput parsing parameter.
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the parsed {@link BigFraction} object.
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public BigFraction parse(final String source, final ParsePosition pos) {
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int initialIndex = pos.getIndex();
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // parse whitespace
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        parseAndIgnoreWhitespace(source, pos);
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // parse numerator
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigInteger num = parseNextBigInteger(source, pos);
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (num == null) {
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // invalid integer number
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // set index back to initial, error index should already be set
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // character examined.
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pos.setIndex(initialIndex);
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return null;
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // parse '/'
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int startIndex = pos.getIndex();
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final char c = parseNextCharacter(source, pos);
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        switch (c) {
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        case 0 :
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // no '/'
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // return num as a BigFraction
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return new BigFraction(num);
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        case '/' :
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // found '/', continue parsing denominator
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            break;
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        default :
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // invalid '/'
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // set index back to initial, error index should be the last
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // character examined.
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pos.setIndex(initialIndex);
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pos.setErrorIndex(startIndex);
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return null;
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // parse whitespace
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        parseAndIgnoreWhitespace(source, pos);
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // parse denominator
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final BigInteger den = parseNextBigInteger(source, pos);
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (den == null) {
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // invalid integer number
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // set index back to initial, error index should already be set
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            // character examined.
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pos.setIndex(initialIndex);
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return null;
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return new BigFraction(num, den);
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Parses a string to produce a <code>BigInteger</code>.
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param source the string to parse
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param pos input/ouput parsing parameter.
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return a parsed <code>BigInteger</code> or null if string does not
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * contain a BigInteger at the specified position
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    protected BigInteger parseNextBigInteger(final String source,
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                                             final ParsePosition pos) {
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int start = pos.getIndex();
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         int end = (source.charAt(start) == '-') ? (start + 1) : start;
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         while((end < source.length()) &&
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond               Character.isDigit(source.charAt(end))) {
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             ++end;
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         }
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         try {
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             BigInteger n = new BigInteger(source.substring(start, end));
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             pos.setIndex(end);
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             return n;
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         } catch (NumberFormatException nfe) {
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             pos.setErrorIndex(start);
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond             return null;
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond         }
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
292