// -*- c++ -*-

/*
 * Jakelib2 - General purpose C++ library
 * Copyright (C) 2001 Florian Wolff  (florian@donuz.de)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: NumberFormat.h,v 1.6 2003/09/16 20:16:24 florian Exp $
 */

#ifndef INCLUDE_JAKELIB2_TEXT_NUMBERFORMAT_H
# define INCLUDE_JAKELIB2_TEXT_NUMBERFORMAT_H

#include "../text/Format.h"
#include "../text/ParsePosition.h"
#include "../text/ParseException.h"
#include "../lang/Number.h"
#include "../util/Locale.h"

namespace jakelib {
  namespace util {
    class Locale;
    class Locales;
  }

  namespace text  {
    class ParsePosition;
    class ParseException;

    /**
     * 
     * @author Alex Fabijanic (FabijanicA@nucorsteel.com) (jakelib2 port)
     */
    class NumberFormat : public Format
    {
    public:

      /**
       * This is a constant used to create a FieldPosition object
       * that will return the integer portion of a formatted number.
       */
      static jint INTEGER_FIELD;

      /**
       * This is a constant used to create a FieldPosition object
       * that will return the fractional portion of a formatted number.
       */
      static jint FRACTION_FIELD;

      /**
       * This method is a specialization of the format method that performs
       * a simple formatting of the specified \c jlong number.
       *
       * @param number The \c jlong to format.
       * @return The formatted number
       */
      jakelib::lang::String* format(jlong number);

      jakelib::lang::StringBuffer* format(jakelib::lang::Object* obj, 
                                          jakelib::lang::StringBuffer* sbuf, 
                                          jakelib::text::FieldPosition* fp); 

      /**
       * This method formats the specified \c jdouble and appends it to
       * a \c StringBuffer.
       * 
       * @param number The \c jdouble to format.
       * @param sbuf The \c StringBuffer to append the formatted number to.
       * @param fp The desired \c FieldPosition.
       * @return The \c StringBuffer with the appended number.
       */
      virtual jakelib::lang::StringBuffer* format(jdouble number,
                                                  jakelib::lang::StringBuffer *sbuf,
                                                  jakelib::text::FieldPosition *fp) = 0;
      
      /**
       * This method formats the specified \c jlong and appends it to
       * a \c StringBuffer.
       * 
       * @param number The \c jlong to format.
       * @param sbuf The \c StringBuffer to append the formatted number to.
       * @param fp The desired \c FieldPosition.
       * @return The \c StringBuffer with the appended number.
       */
      virtual jakelib::lang::StringBuffer* format(jlong number,
                                                  jakelib::lang::StringBuffer* sbuf, 
                                                  jakelib::text::FieldPosition* fp) = 0;

      /**
       * This method tests the specified object for equality against this object.
       * This will be \c true if the following conditions are met:
       *  - The specified object is not \c null.
       *  - The specified object is an instance of \c NumberFormat.
       * Since this method does not test much, it is highly advised that 
       * concrete subclasses override this method.
       *
       * @param obj The \c Object to test against equality with
       *            this object. 
       * @return \c true if the specified object is equal to
       *         this object, \c false otherwise. 
       */
      jboolean equals(jakelib::lang::Object* obj);

      /**
       * This method returns a list of locales for which concrete instances
       * of <code>NumberFormat</code> subclasses may be created.
       *
       * @return The list of available locales.
       */
      static jakelib::util::Locales* getAvailableLocales();

      static NumberFormat* computeInstance(jakelib::util::Locale* loc, 
                                           jakelib::lang::String* resource, 
                                           jakelib::lang::String* def);

      /**
       * This method returns an instance of \c NumberFormat suitable
       * for formatting and parsing currency values in the default locale.
       *
       * @return An instance of \c NumberFormat for handling currencies.
       */
      static NumberFormat* getCurrencyInstance();

      /**
       * This method returns an instance of <code>NumberFormat</code> suitable
       * for formatting and parsing currency values in the specified locale.
       *
       * @return An instance of <code>NumberFormat</code> for handling currencies.
       */
      static NumberFormat* getCurrencyInstance(jakelib::util::Locale* loc);

      /**
       * This method returns a default instance for the default locale. This
       * will be a concrete subclass of NumberFormat, but the 
       * actual class returned is dependent on the locale.
       *
       * @return An instance of the default NumberFormat class.
       */
      static NumberFormat* getInstance();

      /**
       * This method returns a default instance for the specified locale. This
       * will be a concrete subclass of NumberFormat, but the 
       * actual class returned is dependent on the locale.
       *
       * @param loc The desired locale.
       *
       * @return An instance of the default NumberFormat class.
       */
      static NumberFormat* getInstance(jakelib::util::Locale* loc);

      /**
       * This method 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. 
       */
      jint getMaximumFractionDigits();

      /**
       * This method 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. 
       */
      jint getMaximumIntegerDigits();

      /**
       * This method 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. 
       */
      jint getMinimumFractionDigits();

      /**
       * This method 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. 
       */
      jint getMinimumIntegerDigits();

      /**
       * This method returns a general purpose number formatting and parsing
       * class for the default locale.  This will be a concrete subclass of
       * \c NumberFormat, but the actual class returned is dependent
       * on the locale.
       *
       * @return An instance of the default <code>NumberFormat</code> class.
       */
      static NumberFormat* getNumberInstance();

      /**
       * This method returns a default instance for the specified locale. This
       * will be a concrete subclass of \c NumberFormat, but the 
       * actual class returned is dependent on the locale.
       *
       * @param loc The desired locale.
       * @return An instance of a generic number formatter for the default locale.
       */
      static NumberFormat* getNumberInstance(jakelib::util::Locale* loc);

      /**
       * This method returns an instance of NumberFormat suitable
       * for formatting and parsing percentage values in the default locale.
       *
       * @return An instance of NumberFormat for handling percentages.
       */
      static NumberFormat* getPercentInstance();

      /**
       * This method returns an instance of \c NumberFormat suitable
       * for formatting and parsing percentage values in the specified locale.
       *
       * @param loc The desired locale.
       * @return An instance of \c NumberFormat for handling percentages.
       */
      static NumberFormat* getPercentInstance(jakelib::util::Locale* loc);

      /**
       * This method returns a hash value for this object.
       *
       * @return The hash code.
       */
      jint hashCode();

      /**
       * This method tests whether or not grouping is in use.  Grouping is
       * a method of marking separations in numbers, such as thousand separators
       * in the US English locale.  The grouping positions and symbols are all
       * locale specific.  As an example, with grouping disabled, the number one
       * million would appear as "1000000".  With grouping enabled, this number
       * might appear as "1,000,000".  (Both of these assume the US English
       * locale).
       *
       * @return \c true if grouping is enabled,
       *         \c false otherwise. 
       */
      jboolean isGroupingUsed();

      /**
       * This method tests whether or not only integer values should be parsed.
       * If this class is parsing only integers, parsing stops at the decimal
       * point.
       *
       * @return \c true if only integers are parsed,
       *         \c false otherwise. 
       */
      jboolean isParseIntegerOnly();

      /**
       * This is a default constructor for use by subclasses.
       */
      NumberFormat();

      /**
       * This method parses the specified string into a \c Number. This
       * will be a \c Long if possible, otherwise it will be a
       * \c Double. If no number can be parsed, no exception is
       * thrown. Instead, the parse position remains at its initial index.
       *
       * @param str The string to parse.
       * @param pos The desired \c ParsePosition.
       * @return The parsed \c Number
       */
      virtual jakelib::lang::Number* parse(jakelib::lang::String *str, 
                                           jakelib::text::ParsePosition *pos) = 0;

      /**
       * This method parses the specified string into a \c Number.  This
       * will be a \c Long if possible, otherwise it will be a
       * \c Double.  If no number can be parsed, an exception will be
       * thrown.
       *
       * @param str The string to parse.
       * @return The parsed \c Number
       * @exception ParseException If no number can be parsed.
       */
      jakelib::lang::Number* parse(jakelib::lang::String* str);

      /**
       * This method parses the specified string into an \c Object. This
       * will be a \c Long if possible, otherwise it will be a
       * \c Double. If no number can be parsed, no exception is
       * thrown. Instead, the parse position remains at its initial index.
       *
       * @param str The string to parse.
       * @param pos The desired ParsePosition.
       * @return The parsed Object
       */
      jakelib::lang::Object* parseObject(jakelib::lang::String* str, 
                                         jakelib::text::ParsePosition* pos);

      /**
       * This method sets the grouping behavior of this formatter.  Grouping is
       * a method of marking separations in numbers, such as thousand separators
       * in the US English locale.  The grouping positions and symbols are all
       * locale specific.  As an example, with grouping disabled, the number one
       * million would appear as "1000000".  With grouping enabled, this number
       * might appear as "1,000,000".  (Both of these assume the US English
       * locale).
       *
       * @param newValue \c true to enable grouping,
       *                 \c false to disable it. 
       */
      void setGroupingUsed(jboolean newValue);

      /**
       * This method sets the maximum number of digits allowed in the fraction
       * portion of a number to the specified value.  If this is less than the
       * current minimum allowed digits, the minimum allowed digits value will
       * be lowered to be equal to the new maximum allowed digits value.
       *
       * @param newValue The new maximum fraction digits value.
       */
      void setMaximumFractionDigits(jint newValue);

      /**
       * This method sets the maximum number of digits allowed in the integer
       * portion of a number to the specified value.  If this is less than the
       * current minimum allowed digits, the minimum allowed digits value will
       * be lowered to be equal to the new maximum allowed digits value.
       *
       * @param newValue The new maximum integer digits value.
       */
      void setMaximumIntegerDigits(jint newValue);

      /**
       * This method sets the minimum number of digits allowed in the fraction
       * portion of a number to the specified value.  If this is greater than the
       * current maximum allowed digits, the maximum allowed digits value will
       * be raised to be equal to the new minimum allowed digits value.
       *
       * @param newValue The new minimum fraction digits value.
       */
      void setMinimumFractionDigits(jint newValue);

      /**
       * This method sets the minimum number of digits allowed in the integer
       * portion of a number to the specified value.  If this is greater than the
       * current maximum allowed digits, the maximum allowed digits value will
       * be raised to be equal to the new minimum allowed digits value.
       *
       * @param newValue The new minimum integer digits value.
       */
      void setMinimumIntegerDigits(jint newValue);

      /** 
       * This method sets the parsing behavior of this object to parse only 
       * integers or not.
       *
       * @param value \c true to parse only integers,
       *              \c false otherwise. 
       */
      void setParseIntegerOnly(jboolean value);

      /**
       * This method is a specialization of the format method that performs
       * a simple formatting of the specified <code>jdouble</code> number.
       *
       * @param number The \c jdouble to format.
       * @return The formatted number
       */
      jakelib::lang::String* format(jdouble number);

    protected:

      jboolean groupingUsed;

      jint maximumFractionDigits;

      jint maximumIntegerDigits;

      jint minimumFractionDigits;

      jint minimumIntegerDigits;

      jboolean parseIntegerOnly;
  
    private:

      jbyte maxFractionDigits;

      jbyte maxIntegerDigits;

      jbyte minFractionDigits;

      jbyte minIntegerDigits;

      JAKELIB_DECLARE_CLASS(NumberFormat);
    };
    JAKELIB_DECLARE_ARRAY(NumberFormat);
  }
}
#endif

