//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / pf
//
//File: integer.cpp
//
//Version: $Revision: 1.1 $
//
//State: $State: Exp $
//
//Date: $Date: 1998/10/05 07:09:48 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications and Multimedia
//
//Author:
//      Juhana Räsänen
//
//Description:
//      See corresponding header file
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 
//
//

#include "integer.h"
#include <assert.h>
#include <limits.h>

//
// Function: pfInteger constructor
//
// Description:
//     Constructor initializes pfInteger by setting value to 0
//     and checking modulus supplied by user. Modulus must be >= 1
//     (although ints modulo 1 make little sense...) and < ULONG_MAX/2.
//     Upper limit cannot be ULONG_MAX for the class to function
//     properly, consider eg. case:
//           ((ULONG_MAX-2) + (ULONG_MAX-2)) % (ULONG_MAX-1)
//     (Temporary) variable holding the sum before modulo operator
//     will overflow and result will be nonsense.
//

pfInteger :: pfInteger(unsigned long modulus_)
    : _value(0)
{
    assert((modulus_ > 0) && (modulus_ < (ULONG_MAX / 2)));
    _modulus = modulus_;
    return;
}

pfInteger :: pfInteger(const pfInteger &other_)
    : _value(other_._value),
      _modulus(other_._modulus)
{
    return;
}

pfInteger :: ~pfInteger(void)
{
    return;
}

//
// Functions: pfInteger :: getValue
//            pfInteger :: getModulus
//
// Description:
//     Get methods for pfInteger attributes.
//

unsigned long pfInteger :: getValue(void) const
{
    return _value;
}

unsigned long pfInteger :: getModulus(void) const
{
    return _modulus;
}

//
// Functions: pfInteger :: operator=
//            pfInteger :: operator==
//            pfInteger :: operator!=
//            pfInteger :: operator<
//            pfInteger :: operator>
//            pfInteger :: operator<=
//            pfInteger :: operator>=
//            pfInteger :: operator+
//            pfInteger :: operator-
//            pfInteger :: operator+=
//            pfInteger :: operator-=
//            pfInteger :: operator++
//            pfInteger :: operator--
//
// Description:
//     Some arithmetic operators for pfIntegers. Some operators
//     return numeric value (unsigned long) of the pfInteger
//     (instead of const reference).
//     Functionality of + and - operators is defined only once (in
//     operator+(unsigned long) and operator-(unsigned long)), other
//     variations of these operators call those versions.
//

const pfInteger &pfInteger :: operator=(unsigned long value_)
{
    _value = (value_ % _modulus);
    return *this;
}

const pfInteger &pfInteger :: operator=(const pfInteger &other_)
{
    _value = other_._value;
    _modulus = other_._modulus;
    return *this;
}

int pfInteger :: operator==(unsigned long value_) const
{
    int isEqual = (_value == value_);
    return isEqual;
}

int pfInteger :: operator==(const pfInteger &other_) const
{
    int isEqual = ((_value == other_._value) &&
                   (_modulus == other_._modulus));
    return isEqual;
}

int pfInteger :: operator!=(unsigned long value_) const
{
    int isNotEqual = (_value != value_);
    return isNotEqual;
}

int pfInteger :: operator!=(const pfInteger &other_) const
{
    int isNotEqual = ((_value != other_._value) ||
                      (_modulus != other_._modulus));
    return isNotEqual;
}

int pfInteger :: operator<(unsigned long value_) const
{
    int isSmallerThan = _value < value_;
    return isSmallerThan;
}

int pfInteger :: operator<(const pfInteger &other_) const
{
    int isSmallerThan = _value < other_._value;
    return isSmallerThan;
}

int pfInteger :: operator>(unsigned long value_) const
{
    int isGreaterThan = _value > value_;
    return isGreaterThan;
}

int pfInteger :: operator>(const pfInteger &other_) const
{
    int isGreaterThan = _value > other_._value;
    return isGreaterThan;
}

int pfInteger :: operator<=(unsigned long value_) const
{
    int isSmallerOrEqual = ((this->operator<(value_)) ||
                            (this->operator==(value_)));
    return isSmallerOrEqual;
}

int pfInteger :: operator<=(const pfInteger &other_) const
{
    int isSmallerOrEqual = ((this->operator<(other_)) ||
                            (this->operator==(other_)));
    return isSmallerOrEqual;
}

int pfInteger :: operator>=(unsigned long value_) const
{
    int isGreaterOrEqual = ((this->operator>(value_)) ||
                            (this->operator==(value_)));
    return isGreaterOrEqual;
}

int pfInteger :: operator>=(const pfInteger &other_) const
{
    int isGreaterOrEqual = ((this->operator>(other_)) ||
                            (this->operator==(other_)));
    return isGreaterOrEqual;
}

unsigned long pfInteger :: operator+(unsigned long value_) const
{
    unsigned long retval = ((_value + (value_ % _modulus)) % _modulus);
    return retval;
}

unsigned long pfInteger :: operator+(const pfInteger &other_) const
{
    unsigned long retval = this->operator+(other_._value);
    return retval;
}

unsigned long pfInteger :: operator-(unsigned long value_) const
{
    // Note the semantics of substraction: pfIntegers are meant
    // to be unsigned longs with a modulus. When value would become
    // -1, it will get to modulus-1.

    unsigned long value = value_ % _modulus;
    unsigned long retval = 0;
    if (value > _value)
    {
        retval = _modulus - (value - _value);
    }
    else
    {
        retval = _value - value;
    }
    return retval;
}

unsigned long pfInteger :: operator-(const pfInteger &other_) const
{
    unsigned long retval = this->operator-(other_._value);
    return retval;
}

unsigned long pfInteger :: operator+=(unsigned long value_)
{
    _value = this->operator+(value_);
    return _value;
}

unsigned long pfInteger :: operator+=(const pfInteger &other_)
{
    _value = this->operator+(other_._value);
    return _value;
}

unsigned long pfInteger :: operator-=(unsigned long value_)
{
    _value = this->operator-(value_);
    return _value;
}


unsigned long pfInteger :: operator-=(const pfInteger &other_)
{
    _value = this->operator-(other_._value);
    return _value;
}

unsigned long pfInteger :: operator++(void)
{
    _value = ((++_value) % _modulus);
    return _value;
}

unsigned long pfInteger :: operator--(void)
{
    if (_value == 0)
    {
        _value = _modulus - 1;
    }
    else
    {
        _value--;
    }
    return _value;
}

unsigned long pfInteger :: operator++(int)
{
    unsigned long saved = _value;
    this->operator++();
    return saved;
}

unsigned long pfInteger :: operator--(int)
{
    unsigned long saved = _value;
    this->operator--();
    return saved;
}

int pfInteger :: compareWithBase(
    const pfInteger &left_,
    const pfInteger &right_,
    const pfInteger &base_)
{
    int retval = 0;
    if (left_ != right_)
    {
        pfInteger leftNorm(left_);
        leftNorm -= base_;
        pfInteger rightNorm(right_);
        rightNorm -= base_;
        if (leftNorm._value  < rightNorm._value)
        {
            retval = -1;
        }
        else
        {
            retval = 1;
        }
    }
    return retval;
}

// These functions can't be member functions, so they are defined
// as friend functions. They are needed to ensure that operators work
// properly in both pfInteger + ulong and ulong + pfInteger
// cases.

unsigned long operator+(unsigned long lhs_, const pfInteger &rhs_)
{
    unsigned long retval = rhs_.operator+(lhs_);
    return retval;
}

unsigned long operator-(unsigned long lhs_, const pfInteger &rhs_)
{
    unsigned long retval = rhs_.operator-(lhs_);
    return retval;
}

int operator==(unsigned long lhs_, const pfInteger &rhs_)
{
    int isEqual = rhs_.operator==(lhs_);
    return isEqual;
}

int operator!=(unsigned long lhs_, const pfInteger &rhs_)
{
    int isNotEqual = rhs_.operator!=(lhs_);
    return isNotEqual;
}

int operator<(unsigned long lhs_, const pfInteger &rhs_)
{
    int isSmallerThan = rhs_.operator<(lhs_);
    return isSmallerThan;
}

int operator>(unsigned long lhs_, const pfInteger &rhs_)
{
    int isGreaterThan = rhs_.operator>(lhs_);
    return isGreaterThan;
}

int operator<=(unsigned long lhs_, const pfInteger &rhs_)
{
    int isSmallerOrEqual = rhs_.operator<=(lhs_);
    return isSmallerOrEqual;
}

int operator>=(unsigned long lhs_, const pfInteger &rhs_)
{
    int isGreaterOrEqual = rhs_.operator>=(lhs_);
    return isGreaterOrEqual;
}

