/*
* Copyright (C) {1997-2001}, International Business Machines Corporation and others. All Rights Reserved.
********************************************************************************
*
* File NUMFMT.H
*
* Modification History:
*
*   Date        Name        Description
*   02/19/97    aliu        Converted from java.
*   03/18/97    clhuang     Updated per C++ implementation.
*   04/17/97    aliu        Changed DigitCount to int per code review.
*    07/20/98    stephen        JDK 1.2 sync up. Added scientific support.
*                            Changed naming conventions to match C++ guidelines
*                            Derecated Java style constants (eg, INTEGER_FIELD)
********************************************************************************
*/

#ifndef NUMFMT_H
#define NUMFMT_H


#include "unicode/utypes.h"
#include "unicode/unistr.h"
#include "unicode/format.h"

U_NAMESPACE_BEGIN

class Locale;

/**
 * Abstract base class for all number formats.  Provides interface for
 * formatting and parsing a number.  Also provides methods for
 * determining which locales have number formats, and what their names
 * are.
 * <P>
 * NumberFormat helps you to format and parse numbers for any locale.
 * Your code can be completely independent of the locale conventions
 * for decimal points, thousands-separators, or even the particular
 * decimal digits used, or whether the number format is even decimal.
 * <P>
 * To format a number for the current Locale, use one of the static
 * factory methods:
 * <pre>
 * \code
 *    double myNumber = 7.0;
 *    UnicodeString myString;
 *    UErrorCode success = U_ZERO_ERROR;
 *    NumberFormat* nf = NumberFormat::createInstance(success)
 *    nf->format(myNumber, myString);
 *    cout << " Example 1: " << myString << endl;
 * \endcode
 * </pre>
 * If you are formatting multiple numbers, it is more efficient to get
 * the format and use it multiple times so that the system doesn't
 * have to fetch the information about the local language and country
 * conventions multiple times.
 * <pre>
 * \code
 *     UnicodeString myString;
 *     UErrorCode success = U_ZERO_ERROR;
 *     nf = NumberFormat::createInstance( success );
 *     int32_t a[] = { 123, 3333, -1234567 };
 *     const int32_t a_len = sizeof(a) / sizeof(a[0]);
 *     myString.remove();
 *     for (int32_t i = 0; i < a_len; i++) {
 *         nf->format(a[i], myString);
 *         myString += " ; ";
 *     }
 *     cout << " Example 2: " << myString << endl;
 * \endcide
 * </pre>
 * To format a number for a different Locale, specify it in the
 * call to createInstance().
 * <pre>
 * \code
 *     nf = NumberFormat::createInstance( Locale::FRENCH, success );
 * \endcode
 * </pre>
 * You can use a NumberFormat to parse also.
 * <pre>
 * \code
 *    UErrorCode success;
 *    Formattable result(-999);  // initialized with error code
 *    nf->parse(myString, result, success);
 * \endcode
 * </pre>
 * Use createInstance to get the normal number format for that country.
 * There are other static factory methods available.  Use getCurrency
 * to get the currency number format for that country.  Use getPercent
 * to get a format for displaying percentages. With this format, a
 * fraction from 0.53 is displayed as 53%.
 * <P>
 * You can also control the display of numbers with such methods as
 * getMinimumFractionDigits.  If you want even more control over the
 * format or parsing, or want to give your users more control, you can
 * try casting the NumberFormat you get from the factory methods to a
 * DecimalNumberFormat. This will work for the vast majority of
 * countries; just remember to put it in a try block in case you
 * encounter an unusual one.
 * <P>
 * You can also use forms of the parse and format methods with
 * ParsePosition and FieldPosition to allow you to:
 * <ul type=round>
 *   <li>(a) progressively parse through pieces of a string.
 *   <li>(b) align the decimal point and other areas.
 * </ul>
 * For example, you can align numbers in two ways.
 * <P>
 * If you are using a monospaced font with spacing for alignment, you
 * can pass the FieldPosition in your format call, with field =
 * INTEGER_FIELD. On output, getEndIndex will be set to the offset
 * between the last character of the integer and the decimal. Add
 * (desiredSpaceCount - getEndIndex) spaces at the front of the
 * string.
 * <P>
 * If you are using proportional fonts, instead of padding with
 * spaces, measure the width of the string in pixels from the start to
 * getEndIndex.  Then move the pen by (desiredPixelWidth -
 * widthToAlignmentPoint) before drawing the text.  It also works
 * where there is no decimal, but possibly additional characters at
 * the end, e.g. with parentheses in negative numbers: "(12)" for -12.
 * @stable
 */
class U_I18N_API NumberFormat : public Format {
public:

    /**
     * Alignment Field constants used to construct a FieldPosition object.
     * Signifies that the position of the integer part or fraction part of
     * a formatted number should be returned.
     *
     * @see FieldPosition
     * @stable
     */
    enum EAlignmentFields {
        kIntegerField,
        kFractionField,


    /**
     * These constants are provided for backwards compatibility only,
     * and are deprecated.  Please use the C++ style constants defined above.
     * @stable
     */
        INTEGER_FIELD        = kIntegerField,
        FRACTION_FIELD        = kFractionField
    };

    /**
     * Destructor.
     * @stable
     */
    virtual ~NumberFormat();

    /**
     * Return true if the given Format objects are semantically equal.
     * Objects of different subclasses are considered unequal.
     * @return    true if the given Format objects are semantically equal.
     * @stable
     */
    virtual UBool operator==(const Format& other) const;

    /**
     * Format an object to produce a string.  This method handles
     * Formattable objects with numeric types. If the Formattable
     * object type is not a numeric type, then it returns a failing
     * UErrorCode.
     *
     * @param obj           The object to format.
     * @param toAppendTo    Where the text is to be appended.
     * @param pos           On input: an alignment field, if desired.
     *                      On output: the offsets of the alignment field.
     * @param status        Output param filled with success/failure status.
     * @return              The value passed in as toAppendTo (this allows chaining,
     *                      as with UnicodeString::append())
     * @stable
     */
    virtual UnicodeString& format(const Formattable& obj,
                                  UnicodeString& toAppendTo,
                                  FieldPosition& pos,
                                  UErrorCode& status) const;

    /**
     * Parse a string to produce an object.  This methods handles
     * parsing of numeric strings into Formattable objects with numeric
     * types.
     * <P>
     * Before calling, set parse_pos.index to the offset you want to
     * start parsing at in the source. After calling, parse_pos.index
     * is the end of the text you parsed.  If error occurs, index is
     * unchanged.
     * <P>
     * When parsing, leading whitespace is discarded (with successful
     * parse), while trailing whitespace is left as is.
     * <P>
     * See Format::parseObject() for more.
     *
     * @param source    The string to be parsed into an object.
     * @param result    Formattable to be set to the parse result.
     *                  If parse fails, return contents are undefined.
     * @param parse_pos The position to start parsing at. Upon return
     *                  this param is set to the position after the
     *                  last character successfully parsed. If the
     *                  source is not parsed successfully, this param
     *                  will remain unchanged.
     * @return          A newly created Formattable* object, or NULL
     *                  on failure.  The caller owns this and should
     *                  delete it when done.
     * @stable
     */
    virtual void parseObject(const UnicodeString& source,
                             Formattable& result,
                             ParsePosition& parse_pos) const;

    /**
     * Format a double number. These methods call the NumberFormat
     * pure virtual format() methods with the default FieldPosition.
     *
     * @param number    The value to be formatted.
     * @param output    Output param with the formatted string.
     * @return          A reference to 'output' param.
     * @stable
     */
    UnicodeString& format(  double number,
                            UnicodeString& output) const;

    /**
     * Format a long number. These methods call the NumberFormat
     * pure virtual format() methods with the default FieldPosition.
     *
     * @param number    The value to be formatted.
     * @param output    Output param with the formatted string.
     * @return          A reference to 'output' param.
     * @stable
     */
    UnicodeString& format(  int32_t number,
                            UnicodeString& output) const;

   /**
    * Format a double number. Concrete subclasses must implement
    * these pure virtual methods.
    *
    * @param number     The value to be formatted.
    * @param toAppendTo The string to append the formatted string to.
    *                   This is an output parameter.
    * @param pos        On input: an alignment field, if desired.
    *                   On output: the offsets of the alignment field.
    * @return           A reference to 'toAppendTo'.
    * @stable
    */
    virtual UnicodeString& format(double number,
                                  UnicodeString& toAppendTo,
                                  FieldPosition& pos) const = 0;
   /**
    * Format a long number. Concrete subclasses must implement
    * these pure virtual methods.
    *
    * @param number     The value to be formatted.
    * @param toAppendTo The string to append the formatted string to.
    *                   This is an output parameter.
    * @param pos        On input: an alignment field, if desired.
    *                   On output: the offsets of the alignment field.
    * @return           A reference to 'toAppendTo'.
    * @stable
    */
    virtual UnicodeString& format(int32_t number,
                                  UnicodeString& toAppendTo,
                                  FieldPosition& pos) const = 0;

    /**
     * Redeclared Format method.
     * @param obj      the object to be formatted.
     * @param result   Output param with the formatted string. 
     * @return         A reference to 'result'.
     * @stable
     */
    UnicodeString& format(const Formattable& obj,
                          UnicodeString& result,
                          UErrorCode& status) const;

   /**
    * Return a long if possible (e.g. within range LONG_MAX,
    * LONG_MAX], and with no decimals), otherwise a double.  If
    * IntegerOnly is set, will stop at a decimal point (or equivalent;
    * e.g. for rational numbers "1 2/3", will stop after the 1).
    * <P>
    * If no object can be parsed, index is unchanged, and NULL is
    * returned.
    * <P>
    * This is a pure virtual which concrete subclasses must implement.
    *
    * @param text           The text to be parsed.
    * @param result         Formattable to be set to the parse result.
    *                       If parse fails, return contents are undefined.
    * @param parsePosition  The position to start parsing at on input.
    *                       On output, moved to after the last successfully
    *                       parse character. On parse failure, does not change.
    * @return               A Formattable object of numeric type.  The caller
    *                       owns this an must delete it.  NULL on failure.
    * @stable
    */
    virtual void parse(const UnicodeString& text,
                       Formattable& result,
                       ParsePosition& parsePosition) const = 0;

    /**
     * Parse a string as a numeric value, and return a Formattable
     * numeric object. This method parses integers only if IntegerOnly
     * is set.
     *
     * @param text          The text to be parsed.
     * @param result        Formattable to be set to the parse result.
     *                      If parse fails, return contents are undefined.
     * @param status        Success or failure output parameter.
     * @return              A Formattable object of numeric type.  The caller
     *                      owns this an must delete it.  NULL on failure.
     * @see                 NumberFormat::isParseIntegerOnly
     * @stable
     */
    virtual void parse( const UnicodeString& text,
                        Formattable& result,
                        UErrorCode& status) const;

    /**
     * Return true if this format will parse numbers as integers
     * only.  For example in the English locale, with ParseIntegerOnly
     * true, the string "1234." would be parsed as the integer value
     * 1234 and parsing would stop at the "." character.  Of course,
     * the exact format accepted by the parse operation is locale
     * dependant and determined by sub-classes of NumberFormat.
     * @return    true if this format will parse numbers as integers
     *            only. 
     * @stable
     */
    UBool isParseIntegerOnly(void) const;

    /**
     * Sets whether or not numbers should be parsed as integers only.
     * @param value    set True, this format will parse numbers as integers
     *                 only.
     * @see isParseIntegerOnly
     * @stable
     */
    virtual void setParseIntegerOnly(UBool value);

    /**
     * Returns the default number format for the current default
     * locale.  The default format is one of the styles provided by
     * the other factory methods: getNumberInstance,
     * getCurrencyInstance or getPercentInstance.  Exactly which one
     * is locale dependant.
     * @stable
     */
    static NumberFormat* createInstance(UErrorCode&);

    /**
     * Returns the default number format for the specified locale.
     * The default format is one of the styles provided by the other
     * factory methods: getNumberInstance, getCurrencyInstance or
     * getPercentInstance.  Exactly which one is locale dependant.
     * @param inLocale    the given locale.
     * @stable
     */
    static NumberFormat* createInstance(const Locale& inLocale,
                                        UErrorCode&);

    /**
     * Returns a currency format for the current default locale.
     * @stable
     */
    static NumberFormat* createCurrencyInstance(UErrorCode&);

    /**
     * Returns a currency format for the specified locale.
     * @param inLocale    the given locale.
     * @stable
     */
    static NumberFormat* createCurrencyInstance(const Locale& inLocale,
                                                UErrorCode&);

    /**
     * Returns a percentage format for the current default locale.
     * @stable
     */
    static NumberFormat* createPercentInstance(UErrorCode&);

    /**
     * Returns a percentage format for the specified locale.
     * @param inLocale    the given locale.
     * @stable
     */
    static NumberFormat* createPercentInstance(const Locale& inLocale,
                                               UErrorCode&);

    /**
     * Returns a scientific format for the current default locale.
     * @stable
     */
    static NumberFormat* createScientificInstance(UErrorCode&);

    /**
     * Returns a scientific format for the specified locale.
     * @param inLocale    the given locale.
     * @stable
     */
    static NumberFormat* createScientificInstance(const Locale& inLocale,
                                                UErrorCode&);

    /**
     * Get the set of Locales for which NumberFormats are installed.
     * @param count    Output param to receive the size of the locales
     * @stable
     */
    static const Locale* getAvailableLocales(int32_t& count);

    /**
     * Returns true if grouping is used in this format. For example,
     * in the English locale, with grouping on, the number 1234567
     * might be formatted as "1,234,567". The grouping separator as
     * well as the size of each group is locale dependant and is
     * determined by sub-classes of NumberFormat.
     * @see setGroupingUsed
     * @stable
     */
    UBool isGroupingUsed(void) const;

    /**
     * Set whether or not grouping will be used in this format.
     * @param newValue    True, grouping will be used in this format. 
     * @see getGroupingUsed
     * @stable
     */
    virtual void setGroupingUsed(UBool newValue);

    /**
     * Returns the maximum number of digits allowed in the integer portion of a
     * number.
     * @return     the maximum number of digits allowed in the integer portion of a
     *             number.
     * @see setMaximumIntegerDigits
     * @stable
     */
    int32_t getMaximumIntegerDigits(void) const;

    /**
     * Sets the maximum number of digits allowed in the integer portion of a
     * number. maximumIntegerDigits must be >= minimumIntegerDigits.  If the
     * new value for maximumIntegerDigits is less than the current value
     * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
     * the new value.
     *
     * @param newValue    the new value for the maximum number of digits 
     *                    allowed in the integer portion of a number.
     * @see getMaximumIntegerDigits
     * @stable
     */
    virtual void setMaximumIntegerDigits(int32_t newValue);

    /**
     * Returns the minimum number of digits allowed in the integer portion of a
     * number.
     * @return    the minimum number of digits allowed in the integer portion of a
     *            number.
     * @see setMinimumIntegerDigits
     * @stable
     */
    int32_t getMinimumIntegerDigits(void) const;

    /**
     * Sets the minimum number of digits allowed in the integer portion of a
     * number. minimumIntegerDigits must be &lt;= maximumIntegerDigits.  If the
     * new value for minimumIntegerDigits exceeds the current value
     * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
     * the new value.
     * @param newValue    the new value to be set.
     * @see getMinimumIntegerDigits
     * @stable
     */
    virtual void setMinimumIntegerDigits(int32_t newValue);

    /**
     * Returns the maximum number of digits allowed in the fraction portion of a
     * number.
     * @return    the maximum number of digits allowed in the fraction portion of a
     *            number.
     * @see setMaximumFractionDigits
     * @stable
     */
    int32_t getMaximumFractionDigits(void) const;

    /**
     * Sets the maximum number of digits allowed in the fraction portion of a
     * number. maximumFractionDigits must be >= minimumFractionDigits.  If the
     * new value for maximumFractionDigits is less than the current value
     * of minimumFractionDigits, then minimumFractionDigits will also be set to
     * the new value.
     * @param newValue    the new value to be set.
     * @see getMaximumFractionDigits
     * @stable
     */
    virtual void setMaximumFractionDigits(int32_t newValue);

    /**
     * Returns the minimum number of digits allowed in the fraction portion of a
     * number.
     * @return    the minimum number of digits allowed in the fraction portion of a
     *            number.
     * @see setMinimumFractionDigits
     * @stable
     */
    int32_t getMinimumFractionDigits(void) const;

    /**
     * Sets the minimum number of digits allowed in the fraction portion of a
     * number. minimumFractionDigits must be &lt;= maximumFractionDigits.   If the
     * new value for minimumFractionDigits exceeds the current value
     * of maximumFractionDigits, then maximumIntegerDigits will also be set to
     * the new value
     * @param newValue    the new value to be set.
     * @see getMinimumFractionDigits
     * @stable
     */
    virtual void setMinimumFractionDigits(int32_t newValue);

public:

    /**
     * Return the class ID for this class.  This is useful only for
     * comparing to a return value from getDynamicClassID().  For example:
     * <pre>
     * .   Base* polymorphic_pointer = createPolymorphicObject();
     * .   if (polymorphic_pointer->getDynamicClassID() ==
     * .       Derived::getStaticClassID()) ...
     * </pre>
     * @return The class ID for all objects of this class.
     * @stable
     */
    static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; }

    /**
     * Override Calendar
     * Returns a unique class ID POLYMORPHICALLY.  Pure virtual override.
     * This method is to implement a simple version of RTTI, since not all
     * C++ compilers support genuine RTTI.  Polymorphic operator==() and
     * clone() methods call this method.
     * <P>
     * @return The class ID for this object. All objects of a
     * given class have the same class ID.  Objects of
     * other classes have different class IDs.
     * @stable
     */
    virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }

protected:

    /**
     * Default constructor for subclass use only.
     * @stable
     */
    NumberFormat();

    /**
     * Copy constructor.
     * @stable
     */
    NumberFormat(const NumberFormat&);

    /**
     * Assignment operator.
     * @stable
     */
    NumberFormat& operator=(const NumberFormat&);

protected:
    static const int32_t fgMaxIntegerDigits;
    static const int32_t fgMinIntegerDigits;

private:
    static const char fgClassID;

    enum EStyles {
        kNumberStyle,
        kCurrencyStyle,
        kPercentStyle,
        kScientificStyle,
        kStyleCount // ALWAYS LAST ENUM: number of styles
    };
    
    /**
     * Creates the specified decimal format style of the desired locale.
     * @param desiredLocale    the given locale.
     * @param choice           the given style.
     * @param success          Output param filled with success/failure status.
     * @return                 A new NumberFormat instance.
     */
    static NumberFormat* createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);

    static const int32_t    fgNumberPatternsCount;
    static const UChar* const fgLastResortNumberPatterns[];

    UBool      fGroupingUsed;
    int32_t     fMaxIntegerDigits;
    int32_t     fMinIntegerDigits;
    int32_t     fMaxFractionDigits;
    int32_t     fMinFractionDigits;
    UBool      fParseIntegerOnly;
};

// -------------------------------------

inline UBool
NumberFormat::isParseIntegerOnly() const
{
    return fParseIntegerOnly;
}

inline UnicodeString&
NumberFormat::format(const Formattable& obj,
                     UnicodeString& result,
                     UErrorCode& status) const {
    return Format::format(obj, result, status);
}

U_NAMESPACE_END

#endif // _NUMFMT
//eof
