// **********************************************************************
//
// Copyright (c) 2002
// IONA Technologies, Inc.
// Waltham, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_FIXED_H
#define OB_FIXED_H

#include <OB/Basic.h>

namespace CORBA
{

class Fixed
{
    //
    // Conversions from other types
    //
    void fromLongLong(LongLong);
    void fromULongLong(ULongLong, Short = 1);
    void fromString(const char*);

    //
    // Helper functions
    //
    static void mul10(Fixed&, ULong);
    static void div10(Fixed&, ULong);

public: // Should be private but this doesn't work with VC++ 6
    //
    // Array holding the actual value with a precision of up to 64 digits
    //
    Octet value_[64];

    //
    // The signum
    //
    Short signum_;

    //
    // The scale
    //
    UShort scale_;

public:

    // Constructors
#if SIZEOF_LONG == 4
    Fixed(int val = 0) { fromLongLong(val); }
    Fixed(unsigned int val) { fromULongLong(val); }
    Fixed(Long val) { fromLongLong(val); }
#else
    Fixed(Long val = 0) { fromLongLong(val); }
#endif
    Fixed(ULong val) { fromULongLong(val); }
    Fixed(LongLong val) { fromLongLong(val); }
    Fixed(ULongLong val) { fromULongLong(val); }
    Fixed(Double);
    Fixed(LongDouble);
    Fixed(const Fixed&);
    Fixed(const char* val) { fromString(val); }
    ~Fixed() { };

    //
    // ORBacus-specific constructor
    //
    Fixed(const Fixed&, UShort);

    // Conversions
    operator LongLong() const;
    operator LongDouble() const;
    Fixed round(UShort) const;
    Fixed truncate(UShort) const;
    char *to_string() const;

    // Operators
    Fixed& operator=(const Fixed&);
    Fixed& operator+=(const Fixed&);
    Fixed& operator-=(const Fixed&);
    Fixed& operator*=(const Fixed&);
    Fixed& operator/=(const Fixed&);

    Fixed& operator++();
    Fixed operator++(int);
    Fixed& operator--();
    Fixed operator--(int);
    Fixed operator+() const;
    Fixed operator-() const;
    Boolean operator!() const;

    UShort fixed_digits() const;
    UShort fixed_scale() const;

    //
    // Additional ORBacus-specific functions
    //

    //
    // Return absolute value
    //
    Fixed abs() const;

    //
    // Return signum
    //
    Short signum() const;

    //
    // Set new scale
    //
    Fixed setScale(UShort) const;

    //
    // Shift decimal point to the left/right
    //
    Fixed movePointLeft(Short) const;
    Fixed movePointRight(Short) const;

    //
    // Some compilers do not support declaration of global friend functions
    //
    static CORBA::Fixed opAdd(const CORBA::Fixed&, const CORBA::Fixed&);
    static CORBA::Fixed opSub(const CORBA::Fixed&, const CORBA::Fixed&);
    static CORBA::Fixed opMul(const CORBA::Fixed&, const CORBA::Fixed&);
    static CORBA::Fixed opDiv(const CORBA::Fixed&, const CORBA::Fixed&);

    static CORBA::Boolean opGt(const CORBA::Fixed&, const CORBA::Fixed&);
};

typedef Fixed& Fixed_out;

} // End of namespace CORBA

OB_STD(istream)& operator>>(OB_STD(istream)&, CORBA::Fixed&);
OB_STD(ostream)& operator<<(OB_STD(ostream)&, const CORBA::Fixed&);

CORBA::Fixed operator+(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Fixed operator-(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Fixed operator*(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Fixed operator/(const CORBA::Fixed&, const CORBA::Fixed&);

CORBA::Boolean operator>(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Boolean operator<(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Boolean operator>=(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Boolean operator<=(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Boolean operator==(const CORBA::Fixed&, const CORBA::Fixed&);
CORBA::Boolean operator!=(const CORBA::Fixed&, const CORBA::Fixed&);

#endif
