//
// linteger.inl
//
// Copyright (C) 1996-7 by Leonard Janke (janke@unixg.ubc.ca)

inline int LInteger::DigitValue(char digit)
{
  if ( ( digit >= 'a' && digit <='z' ) )  
    return int(digit-'a'+10);
  else if ( digit >= 'A' && digit <='Z' )  
    return int(digit-'A'+10);
  else if ( digit >= '0' && digit <='9' )  
    return int(digit-'0');

  return -1; 
}

inline char LInteger::DigitToCharacter(const int digit, const int upcase=1)
{
  if ( digit >=0 && digit <=9 ) 
    return char(digit)+'0';
  else if ( ( digit >= 10 && digit <=35 ) )  
    if ( upcase )
      return char(digit-10)+'A';
    else
      return char(digit-10)+'a';

  return -1; 
}

inline LInteger LInteger::Negative(const LInteger& x)
{
  if ( x._sign==0 && x._digits==0 && x._magnitude[0]==0u )
    return x;

  return LInteger(x._magnitude,x._digits,x._sign^1u);
}

inline LInteger LInteger::AbsoluteValue(const LInteger& x)
{
  if ( x.IsNonNegative() )
    return x;

  return LInteger(x._magnitude,x._digits,x._sign^1);
}

inline void LInteger::ConvertToTwosComplement(u8* x, int bytes)
{
  for ( int i=0; i<bytes; i++)
    x[i]=~x[i];

  // tsk... tsk... Using assembly in the LInteger class
  // at least this method is private! :)

  asm volatile("0:\tdecl %%ecx\n\t"
	       "addb $1, (%%edi,%%ecx,1)\n\t"
	       "jc 0b\n\t"
	       : "=ecx" (bytes)
	       : "ecx" (bytes), "D" (x)
	       : "%ecx", "memory"
	       );
}


inline unsigned char LInteger::sign() const 
{ 
  return _sign; 
}

inline int LInteger::digits() const 
{ 
  return _digits; 
}

inline unsigned int* LInteger::magnitude() const 
{ 
  return _magnitude; 
}

inline void LInteger::SetSign(const unsigned char newSign)  
{ 
   _sign=newSign; 
}

inline void LInteger::SetDigits(const int newDigits) 
{ 
  _digits=newDigits; 
}

inline void LInteger::SetMagnitude(unsigned int* newMagnitude) 
{ 
  _magnitude=newMagnitude; 
}

inline LInteger operator-(const LInteger& x)
{
  return LInteger::Negative(x);
}

inline LInteger operator+(const LInteger& x)
{
  return x;
}

inline LInteger& LInteger::operator+=(const LInteger& a)
{
  *this=*this+a; 
  return *this;
}

inline LInteger LInteger::operator++(int) 
{ 
  // postfix *is* different from prefix 
  // thanks to Erik De Win for pointing this out

  LInteger temp(*this);
  *this+=LInteger::One; 
  return LInteger(temp); 
}

inline LInteger& LInteger::operator++() 
{ 
  *this+=LInteger::One; 
  return *this; 
}

inline LInteger operator-(const LInteger& x, const LInteger& y) 
{
  return x+(-y);
}

inline LInteger& LInteger::operator-=(const LInteger& x)
{
  *this=*this-x; 
  return *this;
}

inline LInteger LInteger::operator--(int) 
{ 
  // postfix *is* different from prefix 
  // thanks to Erik De Win for pointing this out

  LInteger temp(*this);
  *this-=LInteger::One; 
  return LInteger(temp); 
}

inline LInteger& LInteger::operator--() 
{ 
  *this-=LInteger::One; 
  return *this; 
}

inline LInteger operator*(const LInteger& x, unsigned int y)
{
  return y*x;
}

inline LInteger operator*(const int x, const LInteger& y)
{
  if ( x>0 )
    return unsigned(x)*y;
  else
    return unsigned(-1*x)*y;
}

inline LInteger operator*(const LInteger& x, const int y)
{
  return y*x;
}

inline LInteger& LInteger::operator*=(const LInteger& x)
{
  *this=*this *x; 
  return *this;
}

inline LInteger& LInteger::operator*=(const unsigned int x)
{
  *this=*this *x; 
  return *this;
}

inline LInteger& LInteger::operator*=(const int x)
{
  *this=*this *x; 
  return *this;
}

inline LInteger& LInteger::operator/=(const LInteger& divisor)
{
  *this=*this/divisor; 
  return *this;
}

inline LInteger& LInteger::operator%=(const LInteger& divisor)
{
  *this=*this%divisor; 
  return *this;
}

inline LInteger& LInteger::operator^=(const LInteger& x)
{
  *this=*this^x; 
  return *this;
}

inline LInteger& LInteger::operator|=(const LInteger& x)
{
  *this=*this|x; 
  return *this;
}

inline LInteger& LInteger::operator&=(const LInteger& x)
{
  *this=*this&x; 
  return *this;
}


inline LInteger& LInteger::operator<<=(const int distance)
{
  *this=*this<<distance;
  return *this;
}

inline int operator<(const LInteger& x, const LInteger& y)
{
  if ( x._sign && ! y._sign ) // x<0 && y>=0
      return 1;
  else if ( ! x._sign && y._sign ) // x>=0 & y<0
    return 0;

  // same sign

  if ( x._sign ) // x,y <0
    return LInteger::CompareMagnitudes(x,y) >0; 
  else         // x,y >0
    return LInteger::CompareMagnitudes(x,y) < 0; 
}
 	
inline int operator>(const LInteger& x, const LInteger& y)
{
  if ( x._sign && !x._sign ) // x<0 && y>=0
    return 0;
  else if ( !x._sign && y._sign ) // x>=0 & y<0
    return 1;
    
  // same sign

  if ( x._sign ) // x,y<0
    return LInteger::CompareMagnitudes(x,y) < 0;  
  else // a,b >0
    return LInteger::CompareMagnitudes(x,y) > 0;  
}

inline int operator==(const LInteger& x, const LInteger& y)
{ 
  return (x._sign==y._sign) && (x._digits==y._digits) &&
    BMath::EqualTo(x._magnitude,y._magnitude,x._digits);
}

inline int operator!=(const LInteger& x, const LInteger& y)
{ 
  return (x._sign!=y._sign) || (x._digits!=y._digits) ||
    BMath::NotEqualTo(x._magnitude,y._magnitude,x._digits);
}

inline int operator<=(const LInteger& x, const LInteger& y)
{
  return  x<y || x==y ;
}

inline int operator>=(const LInteger& x, const LInteger& y)
{
  return  x>y || x==y ;
}

inline int LInteger::IsOdd() const
{
  return _magnitude[_digits-1]&1u; 
}

inline int LInteger::IsEven() const
{
  return (_magnitude[_digits-1]&1u)^1u; 
}

inline int LInteger::IsZero() const 
{ 
  return  _sign==0 && _digits==1 && _magnitude[0]==0u; 
} 

inline int LInteger::IsOne() const 
{ 
  return  _sign==0 && _digits==1 && _magnitude[0]==1u; 
} 

inline int LInteger::IsNegative() const
{
  return  _sign==1 ;
}

inline int LInteger::IsNonNegative() const
{
  return  _sign==0 ;
}

inline int LInteger::IsNonZero() const
{
  return  _sign!=0 || _digits!=1 || _magnitude[0]!=0u ;
}

inline int LInteger::IsPositive() const
{
  return  IsNonNegative() && IsNonZero() ;
}

inline int LInteger::IsCompressable() const 
{ 
  return _digits>1 && _magnitude[0]==0u; 
} 

inline LInteger& LInteger::DivByTwo() 
{
  BMath::Div2(_magnitude,_digits);

  if ( IsCompressable() )
    _digits=compress(_magnitude,_digits);

  if ( _digits==1 && _magnitude[0]==0u ) 
    _sign=0;

  return *this;
}

int LInteger::NumberOfBits() const
{
  if ( this->IsZero() )
    return 1;

  return BMath::BSR(_magnitude,_digits)+1;
}

int LInteger::NumberOfBytes() const 
{
  return LMisc::Ceiling(NumberOfBits(),8);
}

