// 181/C++examples/huge/HugeInt.cc   -bds mods to 
// Fig. 8.8: hugeint1.cpp 
// Member and friend function definitions for class HugeInt
#include <string.h>
#include "HugeInt.h"

// static const members
const int HugeInt::SIZE = 40;
const int HugeInt::MAX_INDEX = SIZE - 1;

const int HugeInt::BASE = 3;
const int HugeInt::HALF_BASE = BASE/2;
const int HugeInt::MAX_DIGIT = BASE - 1;

// Default constructor
HugeInt::HugeInt(){
  integer = new short[SIZE];
  for ( int i = 0; i < SIZE; i++ )
    integer[ i ] = 0;   // initialize array to zero
}

// Copy constructor
HugeInt::HugeInt( HugeInt& source ){
  HugeInt::HugeInt();
  for ( int i = 0; i < SIZE; i++ ) 
    integer[ i ] = source.integer[ i ];
}

// Conversion constructors
HugeInt::HugeInt( long v )
{
   HugeInt::HugeInt();
   long val = v >= 0 ? v : -v;

   // idea use clock arithmetic in the style of hardware
   for ( int i = MAX_INDEX; val != 0 && i >= 0; i-- ) {
     integer[ i ] = val % BASE;
     val /= BASE;
   }
   if ( v < 0 ) 
     negate();
}

HugeInt::HugeInt( const char *string )
{
   HugeInt::HugeInt();

   if ( string[0] == '-' ) {// assuming non-null string.
     HugeInt::HugeInt( string + 1 );
     negate();
   } 
   else {
     int i, j;
     for ( i = SIZE - strlen( string ), j = 0; i <= MAX_INDEX; i++, j++ )
       integer[ i ] = string[ j ] - '0';
   }

   // debugging display:
   char* s = new char[20 + strlen(string)];
   // s = "HugeInt( ";
   strcpy( s, "HugeInt( " );
   strcat( s, string );
   strcat( s, " ) = " );
   debug( s );
   delete[] s;
}

// Addition
HugeInt HugeInt::operator+( HugeInt &op2 )
{ // correct for now
   HugeInt temp;
   int carry = 0;

   for ( int i = MAX_INDEX; i >= 0; i-- ) {
      temp.integer[ i ] = integer[ i ] + 
                          op2.integer[ i ] + carry;

      if ( temp.integer[ i ] > MAX_DIGIT ) {
         temp.integer[ i ] -= BASE;
         carry = 1;
      }
      else
         carry = 0;
   }
   return temp;
}

HugeInt HugeInt::operator+( int op2 )
   { return *this + HugeInt( op2 ); }

HugeInt HugeInt::operator+( const char *op2 )
   { return *this + HugeInt( op2 ); }

// subtraction
HugeInt HugeInt::operator-( HugeInt &op2 )  
{ 
   op2.negate();
   HugeInt ans = *this + op2;
   op2.negate();
   return ans;
}


HugeInt HugeInt::operator-( int op2 )
   { return *this - HugeInt( op2 ); }

HugeInt HugeInt::operator-( const char *op2 )
   { return *this - HugeInt( op2 ); }

// negation and complement
void HugeInt::negate() {
   debug( "negate start = " );
  complement();
   debug( "negate complemented = " );
  add1();
    debug( "negate add1-ed = " );
}

void HugeInt::add1() {
  int i;
  for ( i = MAX_INDEX; i >= 0 && integer[ i ] == MAX_DIGIT; i-- )
    integer[ i ] = 0;
  if ( i >= 0 ) integer[ i ] += 1;
}

void HugeInt::complement() {
  for ( int i = 0; i < SIZE; i++ )
    integer[ i ] = MAX_DIGIT - integer[ i ];
}

// the friends
HugeInt operator+( int op1, HugeInt& op2 ) 
   { return op2 + op1; }
  
HugeInt operator-( int op1, HugeInt& op2 ) 
   { return HugeInt(op1) - op2; }
  
HugeInt abs( HugeInt& op ) {
  HugeInt ans(op);
  if ( ans.integer[0] >= HugeInt::HALF_BASE ) ans.negate();
  return ans;
}

// output operator only works for BASE <= 10.
ostream& operator<<( ostream &output, HugeInt &num )
{

   if ( num.integer[0] >= HugeInt::HALF_BASE ) 
     output << "-" << abs( num );
   else {
     int i;
     for ( i = 0; ( num.integer[ i ] == 0 ) && ( i < HugeInt::SIZE ); i++ )
       ; // skip leading zeros

     if ( i == HugeInt::SIZE )
       output << 0; // the number is zero
     else 
       for ( ; i <= HugeInt::MAX_INDEX; i++ )
         output << num.integer[ i ];
   }
   return output;
}

void HugeInt::debug( char* s ) {
/*
  cerr << s;
  for(int k = 0; k < SIZE; k++) cerr << integer[k]; 
  cerr << ", BASE is " << BASE << ", SIZE is " << SIZE << endl;
  */
}

