// ----------------------------------------------------------------------------
// FILE NAME: idecimal.hpp
//
// DESCRIPTION:
//   Declaration of the classes:
//     IDecimalUtil
//
// COPYRIGHT:
//   IBM Open Class Library
//   Licensed Materials - Property of IBM
//
//   5645-001
//   (C) Copyright IBM Corporation 1992, 1997  All Rights Reserved.
//
// Revision: 05  1.7.1.6  source/core/base/idecimal.hpp, appsupport, ioc.v400, 001006  
// ----------------------------------------------------------------------------

#ifndef _IDECIMAL_
#define _IDECIMAL_

extern "C"
{
    #include <stdio.h>
    #include <string.h>
}

#include <iostream.h>
#include <ibase.hpp>
#include <istring.hpp>

#ifdef IC_STREAMING
#include <idatstrm.hpp>
#endif

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

#ifndef IC_BUILD
class IDecimalUtil;
class IBinaryCodedDecimal;
inline ostream& IC_EXPORTB operator<<(ostream& os, const IDecimalUtil &dut);
inline ostream& operator<<(ostream& os, const IBinaryCodedDecimal& bcd);
inline istream& operator>>(istream& is, IBinaryCodedDecimal& bcd);
#endif

#define DEC_DIG     31
#define DEC_MIN     ((IBinaryCodedDecimal)("-9999999999999999999999999999999"))
#define DEC_MAX     ((IBinaryCodedDecimal)("+9999999999999999999999999999999"))
#define DEC_EPSILON ((IBinaryCodedDecimal)(".0000000000000000000000000000001"))

// default sizes for native data types
#define DFT_DIG       15
#define DFT_PREC      5
#define DFT_INT_DIG   10
#define DFT_LNG_DIG   20

// constants for manipulation by IDecimalUtil class
#define MAX_ITGRL     64            // max # of digits stored for integral part
#define MAX_FRTNL     32            // max # of digits stored for fractional part
                                    // these two # MUST be fully divisible by 8.
#define MASK_OF_6     0x66666666UL
#define MASK_OF_8     0x88888888UL
#define NEGATIVE_1    0x99999999UL  // in 10's complement

class IDecimalUtil;

#pragma pack(push,4)
#pragma enum(4)

class IC_EXPORTB IBinaryCodedDecimal
{
public:
    IBinaryCodedDecimal();
    IBinaryCodedDecimal(const char* val);
    IBinaryCodedDecimal(int anInt);
    IBinaryCodedDecimal(unsigned int auInt);
    IBinaryCodedDecimal(long aLong);
    IBinaryCodedDecimal(unsigned long auLong);
    IBinaryCodedDecimal(float afloat);
    IBinaryCodedDecimal(double aDouble);
    IBinaryCodedDecimal(long double alDouble);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        int anInt);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        unsigned int auInt);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        long aLong);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        unsigned long auLong);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        float afloat);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        double aDouble);
    IBinaryCodedDecimal(unsigned int nDig, unsigned int nPrec,
                        long double alDouble);

    IBinaryCodedDecimal operator++();
    IBinaryCodedDecimal operator++(int);
    IBinaryCodedDecimal operator--();
    IBinaryCodedDecimal operator--(int);
    IBinaryCodedDecimal operator+() const;
    IBinaryCodedDecimal operator-() const;
    int operator!() const;

    IBinaryCodedDecimal& operator=(const IBinaryCodedDecimal &bcd);
    IBinaryCodedDecimal& operator=(const IDecimalUtil &dut);
    IBinaryCodedDecimal& operator=(int anInt);
    IBinaryCodedDecimal& operator=(unsigned auInt);
    IBinaryCodedDecimal& operator=(long aLong);
    IBinaryCodedDecimal& operator=(unsigned long auLong);
    IBinaryCodedDecimal& operator=(float aFloat);
    IBinaryCodedDecimal& operator=(double aDouble);
    IBinaryCodedDecimal& operator=(long double alDouble);

    int operator>(const IDecimalUtil& dut) const;
    int operator>=(const IDecimalUtil& dut) const;
    int operator<(const IDecimalUtil& dut) const;
    int operator<=(const IDecimalUtil& dut) const;
    int operator==(const IDecimalUtil& dut) const;
    int operator!=(const IDecimalUtil& dut) const;

    void operator+=(const IDecimalUtil& dut);
    void operator-=(const IDecimalUtil& dut);
    void operator*=(const IDecimalUtil& dut);
    void operator/=(const IDecimalUtil& dut);

    int digitsOf() const;
    int precisionOf() const;
    const bool isPositive() const;
    const bool isNegative() const;
    const char* cData() const;
    IString asString() const;
    long asLong() const;
    double asDouble() const;

#ifdef IC_STREAMING
    void operator>>=(IDataStream &toWhere);
    void operator<<=(IDataStream &fromWhere);

protected:
    void writeToStream(IDataStream &toWhere) const;
    void readFromStream(IDataStream &fromWhere);
#endif

private:
    void setNegative();
    void setPositive();
    char buf[(DEC_DIG >> 1) + 1];
    int numDig, numPrec;

};

// utility class for IBinaryCodedDecimal
class IC_EXPORTB IDecimalUtil
{
public:
    IDecimalUtil();
    IDecimalUtil(int anInt);
    IDecimalUtil(unsigned int auInt);
    IDecimalUtil(long aLong);
    IDecimalUtil(unsigned long auLong);
    IDecimalUtil(float afloat);
    IDecimalUtil(double aDouble);
    IDecimalUtil(long double alDouble);
    IDecimalUtil (const IBinaryCodedDecimal& bcd);

    operator IBinaryCodedDecimal() const;
    int operator>(const IDecimalUtil& dut) const;
    int operator>=(const IDecimalUtil& dut) const;
    int operator<(const IDecimalUtil& dut) const;
    int operator<=(const IDecimalUtil& dut) const;
    int operator==(const IDecimalUtil& dut) const;
    int operator!=(const IDecimalUtil& dut) const;

private:
    IDecimalUtil& operator=(const IDecimalUtil& dut);

    friend class IBinaryCodedDecimal;
    friend IDecimalUtil IC_EXPORTB
                operator+(const IDecimalUtil& lv, const IDecimalUtil& rv);
    friend IDecimalUtil IC_EXPORTB
                operator-(const IDecimalUtil& lv, const IDecimalUtil& rv);
    friend IDecimalUtil IC_EXPORTB
                operator*(const IDecimalUtil& lv, const IDecimalUtil& rv);
    friend IDecimalUtil IC_EXPORTB
                operator/(const IDecimalUtil& lv, const IDecimalUtil& rv);
    friend ostream& IC_EXPORTB
                operator << (ostream& os, const IDecimalUtil &dut);
    friend ostream& operator<<(ostream& os, const IBinaryCodedDecimal& bcd);
    friend istream& operator>>(istream& is, IBinaryCodedDecimal& bcd);

    operator long() const;
    operator double() const;

    static void throwOverflow();

    static void cptrToDec(const char* val, int& nDig, int& nPrec, char* decBuf,
                            bool hasDigPrec=true);
    static bool cptrToDUT(const char* val,
                                    int& nitgrl, int& nfrtnl, char* dutBuf);
    static void intToDec(int anInt, int nDig, int nPrec, char* decBuf);
    static void uIntToDec(unsigned int auInt, int nDig, int nPrec, char* decBuf);
    static void longToDec(long aLong, int nDig, int nPrec, char* decBuf);
    static void uLongToDec(unsigned long auLong, int nDig, int nPrec,
                            char* decBuf);
    static void doubleToDec(double aDouble, int nDig, int nPrec, char* decBuf);
    static void lDoubleToDec(long double alDouble, int nDig, int nPrec,
                            char* decBuf);

    // public member access function, all const
    IString asString() const;

    void  trimZero();
    static unsigned long genuLong(const char* bcdBuf);
    static unsigned long gen10Complement(unsigned long auLong);
    static void genBCD(char* bcdBuf, unsigned long auLong);
    static unsigned long decAddWord(unsigned long in1, unsigned long in2,
                                    unsigned long mask6, unsigned long mask8);
    static int addBCD(char* resBCD, const char* lvptr,
                        const char* rvptr, int numOfWord);
    static void subBCD(char* resBCD, const char* lvptr,
                        const char* rvptr, int numOfWord);
    static int mulBCD(char* resBCD, int resBCDSize,
                        const char* lvptr, int lvByte,
                        const char* rvptr, int rvByte);
    static int divBCD(char* resBCD, int powOf10,
                        const char* lvptr, int lvByte,
                        const char* rvptr, int rvByte);
    static int times10(char* cptr, int numOfWord);

    //
    // The decimal point is always in the middle of the data
    // with the integral part right justified and fractional part
    // left justified at the decimal point like in COBOL
    // 9(MAX_ITGRL)v9(MAX_FRTNL)
    //
    char bcdData[(MAX_ITGRL >> 1) + (MAX_FRTNL >> 1)];

    // Actual # of non zero nibbles in integral and fractional part
    int nitgrl; 
    int nfrtnl;

    // The sign
    bool  positive;
};

#pragma enum(pop)
#pragma pack(pop)

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#include <idecimal.inl>

#endif // _IDECIMAL_
