/***************************************************************************
                          hbcivalue.h  -  description
                             -------------------
    begin                : Sat Aug 4 2001
    copyright            : (C) 2001 by fabian kaiser
    email                : fabian.kaiser@gmx.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                                                   *
 *                                                                         *
 ***************************************************************************/


#ifndef HBCIVALUE_H
#define HBCIVALUE_H

/** @file value.h
 *
 * @short HBCI::Value and its C wrapper @ref HBCI_Value. */

#ifdef __cplusplus
#include <string>

using namespace std;

namespace HBCI {

/**
 * @short Represents a monetary value in %HBCI
 * @author fabian kaiser
 */
class DLLIMPORT Value {
public:
    /** 
     * Default constructor.
     *
     * Creates an empty, invalid value. This is used as a placeholder
     * value where a valid value will be filled in later. 
     *
     * Note that simply initializing an empty value with zero doesn't
     * do the job, since a value needs to have a currency, too, and
     * this one can't be left empty. Also, initializing it with zero
     * makes a placeholder value indistinguishable from actual zero
     * value. Hence, you have to check values whether they are valid
     * before using it. */
    Value();

    /**
     * Construct a value by giving an amount and a currency.
     *
     * @param value the amount
     * @param currency the currency as ISO-4217 string, e.g. "EUR" for Euro
     */
    Value(double value, const string &currency);

    /**
     * Construct a value by parsing an %HBCI-conforming value-string. 
     *
     * See HBCI-Spec chapter II.5.3.1 on the exact format. This
     * implementation accepts the following:
     *
     * "<float>[:<CUR>]" where <float> is a floating point literal and
     * <CUR> is the three-character ISI-4217 currency string,
     * separated from the float literal by a colon ":".
     *
     * According to HBCI, <float> is of format "<digits>,[<digits>]":
     * No leading minus sign; at least one digit left of the decimal
     * delimiter; comma (not point!) as decimal delimiter; comma is
     * mandatory (!); only as many digits after the comma as ISO-4217
     * says for the given currency; total length not more than 15
     * characters.
     *
     * This implementation is a little bit less restrictive about the
     * format and accepts also the following
     * "[-]<digits>[<,.>[<digits>]]": Optional leading minus sign; at
     * least one digit left of decimal delimiter; comma or point as
     * decimal delimiter; if there are no digits on the right of the
     * decimal delimiter, it can be omitted. The numeric range is
     * limited to approx. +-10^17, after which the value will be
     * rounded according to ordinary floating point rules.
     *
     * If there is a format error (esp. if both comma and point or
     * more than one of each appear in the float literal), a
     * HBCI::Error is thrown.
     *
     * The <CUR> currency string is simply truncated to three
     * characters; if you errorneously specified "Euro", you won't
     * notice that until your bank complains about an unknown
     * currency. FIXME: should we throw an error if there are more
     * than three characters after the colon? I don't think so.
     *
     * Examples: HBCI-conforming: "4567,89:EUR", "100,2:EUR",
     * "0,:EUR"; not HBCI-conforming, but also accepted here:
     * "-4567,89:EUR", "100.20:EUR", "0:EUR".
     *
     * @param strvalue string representation of the value
     * @throws HBCI::Error is the string is malformed
     */
    Value(const string &strvalue);

    /** Check whether this value is an empty value, which occurs if it
     * has been constructed by the default empty constructor. Returns
     * true otherwise.
     *
     * @return false if invalid/empty value, true if valid value.
     * @author Mathias Kettner <mk@quara.de> */
    bool isValid() const { return _isvalid; };

    /** 
     * Returns the amount of this value.
     * @return The amount.
     */
    double getValue() const { return _value;};

    /**
     * Returns the currency of this value as ISO-4217 string.
     * @return The currency.
     */
    const string& getCurrency() const { return _currency;};

    /**
     * Returns a %HBCI-conforming string representation of this value.
     *
     * See the documentation of the constructor for more on this.
     *
     * @return The string representation.
     */
    string toString() const;

    /** 
     * Returns a user-readable string representation of this value. 
     *
     * This has the format e.g. "1234.56 EUR".
     * @return The string representation.
     */
    string toReadableString() const;

    /**
     * Returns the standarized floating-point precision of a given
     * currency, according to ISO-4217. The returned number are the
     * number of digits after the decimal point (comma). 
     *
     * For most currencies this is 2 (e.g. "EUR"), but for some it is
     * 0 (e.g. Japan's Yen, "JPY"), and for even less others it might
     * be totally different. 
     *
     * Only the currencies mentioned in the HBCI-spec, chapter
     * VIII.11, are implemented currently.  For unimplemented
     * currencies, 2 is returned, and a warning message is printed on
     * stderr.
     *
     * @author Christian Stimming <stimming@tuhh.de>
     * @return The standarized precision for this currency
     */
    static unsigned int currencyPrecision(const string& c);

private:
    /**
     * Actual amount of money
     */
    double _value;

    /** currency in ISO-4217 notation, e.g. 'DEM' for german marks,
     * 'EUR' for Euro */
    string _currency;

    bool _isvalid;
};

/** Returns true if Value v1 is lesser than Value v2. 
 *
 * Note that this comparison doet <i>not</i> check whether both values
 * actually have the same currency, it only compares the values
 * itself. */
inline bool operator<(const Value &v1, const Value &v2) {
    return v1.getValue()<v2.getValue();
}

/** Returns true if Value v1 is greater than Value v2. 
 *
 * Note that this comparison doet <i>not</i> check whether both values
 * actually have the same currency, it only compares the values
 * itself. */
inline bool operator>(const Value &v1, const Value &v2) {
    return v1.getValue()>v2.getValue();
}


/** Returns true if Value v1 is equal to Value v2 <i>and</i> has the
    same currency. */
inline bool operator==(const Value &v1, const Value &v2) {
    return (v1.getCurrency()==v2.getCurrency()) && 
	(v1.getValue()==v2.getValue());
}

} /* namespace HBCI */
typedef struct HBCI::Value HBCI_Value;

#else /* __cplusplus */
typedef struct HBCI_Value HBCI_Value;
#endif /* __cplusplus */


#ifdef __cplusplus
extern "C" {
#endif
    /**
     * Construct a value by giving an amount and a currency.
     *
     * @param value the amount
     * @param currency the currency as ISO-4217 string, e.g. "EUR" for Euro
     */
    extern HBCI_Value *HBCI_Value_new_double(double value, 
					     const char *currency);
    /** Check whether this value is an empty value, which occurs if it
     * has been constructed by the default empty constructor. Returns
     * true otherwise.
     *
     * @return false if invalid/empty value, true if valid value.  */
    extern int HBCI_Value_isValid(const HBCI_Value *v);
    /** 
     * Returns the amount of this value.
     * @return The amount.
     */
    extern double HBCI_Value_getValue(const HBCI_Value *v);
    /**
     * Returns the currency of this value as ISO-4217 string.
     *
     * @return The currency. This string is still owned by this object,
     * so don't free it.  */
    extern const char* HBCI_Value_getCurrency(const HBCI_Value *v);
    /** 
     * Returns a user-readable string representation of this value. 
     *
     * This has the format e.g. "1234.56 EUR".
     *
     * @return The string representation. This Char* buffer will be
     * owned by the caller, so you need to free it by yourself if no
     * longer needed.  */
    extern char* HBCI_Value_toReadableString(const HBCI_Value *v);

#ifdef __cplusplus
}
#endif

#endif
