// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause

// code taken from
// Arbitrarily large numbers
//
// Author  Matthew Caryl
// Created 13.3.97

#include "vtkLargeInteger.h"

#include <algorithm>

VTK_ABI_NAMESPACE_BEGIN
const unsigned int BIT_INCREMENT = 32;

void vtkLargeInteger::Contract()
{
  while (this->Number[this->Sig] == 0 && this->Sig > 0)
  {
    this->Sig--;
  }
}

vtkLargeInteger::vtkLargeInteger()
{
  this->Number = new char[BIT_INCREMENT];
  this->Number[0] = 0;
  this->Negative = 0;
  this->Max = BIT_INCREMENT - 1;
  this->Sig = 0;
}

vtkLargeInteger::vtkLargeInteger(long long n)
{
  this->Negative = n < 0 ? 1 : 0;
  n = n < 0 ? -n : n; // strip of sign
  this->Number = new char[BIT_INCREMENT];
  for (unsigned int i = 0; i < BIT_INCREMENT; i++)
  {
    this->Number[i] = n & 1;
    n >>= 1;
  }
  this->Max = BIT_INCREMENT - 1;
  this->Sig = BIT_INCREMENT - 1;
  this->Contract(); // remove leading 0s
}

vtkLargeInteger::vtkLargeInteger(unsigned long long n)
{
  this->Negative = 0;
  this->Number = new char[BIT_INCREMENT];
  for (unsigned int i = 0; i < BIT_INCREMENT; i++)
  {
    this->Number[i] = n & 1;
    n >>= 1;
  }
  this->Max = BIT_INCREMENT - 1;
  this->Sig = BIT_INCREMENT - 1;
  this->Contract(); // remove leading 0s
}

vtkLargeInteger::vtkLargeInteger(long n)
{
  this->Negative = n < 0 ? 1 : 0;
  n = n < 0 ? -n : n; // strip of sign
  this->Number = new char[BIT_INCREMENT];
  for (unsigned int i = 0; i < BIT_INCREMENT; i++)
  {
    this->Number[i] = n & 1;
    n >>= 1;
  }
  this->Max = BIT_INCREMENT - 1;
  this->Sig = BIT_INCREMENT - 1;
  this->Contract(); // remove leading 0s
}

vtkLargeInteger::vtkLargeInteger(unsigned long n)
{
  this->Negative = 0;
  this->Number = new char[BIT_INCREMENT];
  for (unsigned int i = 0; i < BIT_INCREMENT; i++)
  {
    this->Number[i] = n & 1;
    n >>= 1;
  }
  this->Max = BIT_INCREMENT - 1;
  this->Sig = BIT_INCREMENT - 1;
  this->Contract(); // remove leading 0s
}

vtkLargeInteger::vtkLargeInteger(unsigned int n)
{
  this->Negative = 0;
  this->Number = new char[BIT_INCREMENT];
  for (unsigned int i = 0; i < BIT_INCREMENT; i++)
  {
    this->Number[i] = n & 1;
    n >>= 1;
  }
  this->Max = BIT_INCREMENT - 1;
  this->Sig = BIT_INCREMENT - 1;
  this->Contract(); // remove leading 0s
}

vtkLargeInteger::vtkLargeInteger(int n)
{
  this->Negative = n < 0 ? 1 : 0;
  n = n < 0 ? -n : n; // strip of sign
  this->Number = new char[BIT_INCREMENT];
  for (unsigned int i = 0; i < BIT_INCREMENT; i++)
  {
    this->Number[i] = n & 1;
    n >>= 1;
  }
  this->Max = BIT_INCREMENT - 1;
  this->Sig = BIT_INCREMENT - 1;
  this->Contract(); // remove leading 0s
}

vtkLargeInteger::vtkLargeInteger(const vtkLargeInteger& n)
{
  this->Number = new char[n.Max + 1];
  this->Negative = n.Negative;
  this->Max = n.Max;
  this->Sig = n.Sig;
  for (int i = this->Sig; i >= 0; i--)
  {
    this->Number[i] = n.Number[i];
  }
}

vtkLargeInteger::~vtkLargeInteger()
{
  delete[] this->Number;
}

char vtkLargeInteger::CastToChar() const
{
  return this->CastToLong();
}

short vtkLargeInteger::CastToShort() const
{
  return this->CastToLong();
}

int vtkLargeInteger::CastToInt() const
{
  return this->CastToLong();
}

long vtkLargeInteger::CastToLong() const
{
  long n = 0;

  for (int i = this->Sig; i >= 0; i--)
  {
    n <<= 1;
    n |= this->Number[i];
  }
  if (this->Negative)
  {
    return -n;
  }

  return n;
}

// convert to an unsigned long, return max if bigger than unsigned long
unsigned long vtkLargeInteger::CastToUnsignedLong() const
{
  unsigned long n = 0;

  if (this->Sig >= (8 * sizeof(unsigned long)))
  {
    for (int i = (8 * sizeof(unsigned long)); i > 0; i--)
    {
      n <<= 1;
      n |= 1;
    }
  }
  else
  {
    for (int i = this->Sig; i >= 0; i--)
    {
      n <<= 1;
      n |= this->Number[i];
    }
  }

  return n;
}

int vtkLargeInteger::IsEven() const
{
  return this->Number[0] == 0;
}

int vtkLargeInteger::IsOdd() const
{
  return this->Number[0] == 1;
}

int vtkLargeInteger::GetLength() const
{
  return this->Sig + 1;
}

int vtkLargeInteger::GetBit(unsigned int p) const
{
  if (p <= this->Sig) // check if within current size
  {
    return this->Number[p];
  }

  return 0;
}

int vtkLargeInteger::IsZero() const
{
  return (this->Sig == 0 && this->Number[0] == 0);
}

int vtkLargeInteger::GetSign() const
{
  return this->Negative;
}

void vtkLargeInteger::Truncate(unsigned int n)
{
  if (n < 1) // either set to zero
  {
    this->Sig = 0;
    this->Number[0] = 0;
    this->Negative = 0;
  }
  else if (this->Sig > n - 1) // or chop down
  {
    this->Sig = n - 1;
    this->Contract(); // may have revealed leading zeros
  }
}

void vtkLargeInteger::Complement()
{
  if (!this->IsZero()) // can't have negative zeros
  {
    this->Negative = !this->Negative;
  }
}

bool vtkLargeInteger::operator==(const vtkLargeInteger& n) const
{
  if (this->Sig != n.Sig) // check size
  {
    return false;
  }

  if (this->Negative != n.Negative) // check sign
  {
    return false;
  }

  for (int i = this->Sig; i >= 0; i--)
  {
    if (this->Number[i] != n.Number[i]) // check bits
    {
      return false;
    }
  }

  return true;
}

bool vtkLargeInteger::operator!=(const vtkLargeInteger& n) const
{
  return !(*this == n);
}

bool vtkLargeInteger::IsSmaller(const vtkLargeInteger& n) const
{
  if (this->Sig < n.Sig) // check size
  {
    return true;
  }
  if (this->Sig > n.Sig) // check size
  {
    return false;
  }

  for (int i = this->Sig; i >= 0; i--)
  {
    if (this->Number[i] < n.Number[i]) // check bits
    {
      return true;
    }
    if (this->Number[i] > n.Number[i])
    {
      return false;
    }
  }

  return false;
}

bool vtkLargeInteger::IsGreater(const vtkLargeInteger& n) const
{
  if (this->Sig > n.Sig) // check size
  {
    return true;
  }
  if (this->Sig < n.Sig) // check sign
  {
    return false;
  }

  for (int i = this->Sig; i >= 0; i--)
  {
    if (this->Number[i] > n.Number[i]) // check bits
    {
      return true;
    }
    if (this->Number[i] < n.Number[i])
    {
      return false;
    }
  }

  return false;
}

bool vtkLargeInteger::operator<(const vtkLargeInteger& n) const
{
  if (this->Negative && !n.Negative) // try to make judgment using signs
    return true;
  else if ((!this->Negative) && n.Negative)
    return false;
  else if (this->Negative)
    return !this->IsSmaller(n);
  else
    return this->IsSmaller(n);
}

bool vtkLargeInteger::operator<=(const vtkLargeInteger& n) const
{
  return *this < n || *this == n;
}

bool vtkLargeInteger::operator>(const vtkLargeInteger& n) const
{
  return !(*this <= n);
}

bool vtkLargeInteger::operator>=(const vtkLargeInteger& n) const
{
  return !(*this < n);
}

void vtkLargeInteger::Expand(unsigned int n)
{
  if (n < this->Sig) // don't need to expand
  {
    return;
  }
  if (this->Max < n) // need to make a larger array
  {
    char* new_number = new char[n + 1];
    for (int i = this->Sig; i >= 0; i--)
    {
      new_number[i] = this->Number[i];
    }
    delete[] this->Number;
    this->Number = new_number;
    this->Max = n;
  }
  // zero top of array
  for (unsigned int i = this->Sig + 1; i <= this->Max; i++)
  {
    this->Number[i] = 0;
  }
  this->Sig = n;
}

vtkLargeInteger& vtkLargeInteger::operator=(const vtkLargeInteger& n)
{
  if (this == &n) // same object
  {
    return *this;
  }
  this->Expand(n.Sig); // make equal sizes
  this->Sig = n.Sig;   // might have been larger
  for (int i = this->Sig; i >= 0; i--)
  {
    this->Number[i] = n.Number[i];
  }
  this->Negative = n.Negative;
  return *this;
}

void vtkLargeInteger::Plus(const vtkLargeInteger& n)
{
  int m = std::max(this->Sig + 1, n.Sig + 1);
  this->Expand(m); // allow for overflow
  unsigned int i = 0;
  int carry = 0;
  for (; i <= n.Sig; i++) // add overlap
  {
    carry += this->Number[i] + n.Number[i];
    this->Number[i] = carry & 1;
    carry /= 2;
  }
  for (; carry != 0; i++) // continue with carry
  {
    carry += this->Number[i];
    this->Number[i] = carry & 1;
    carry /= 2;
  }
  this->Contract();
}

void vtkLargeInteger::Minus(const vtkLargeInteger& n)
{
  int m = std::max(this->Sig, n.Sig);
  this->Expand(m);
  unsigned int i = 0;
  int carry = 0;
  for (; i <= n.Sig; i++) // subtract overflow
  {
    carry += this->Number[i] - n.Number[i];
    this->Number[i] = (carry + 2) & 1;
    carry = carry < 0 ? -1 : 0;
  }
  for (; carry != 0; i++) // continue with carry
  {
    carry += this->Number[i];
    this->Number[i] = (carry + 2) & 1;
    carry = carry < 0 ? -1 : 0;
  }
  this->Contract();
}

vtkLargeInteger& vtkLargeInteger::operator+=(const vtkLargeInteger& n)
{
  if ((this->Negative ^ n.Negative) == 0) // cope with negatives
  {
    this->Plus(n);
  }
  else
  {
    if (this->IsSmaller(n))
    {
      vtkLargeInteger m(*this);
      *this = n;
      this->Minus(m);
    }
    else
    {
      this->Minus(n);
    }
    if (this->IsZero())
    {
      this->Negative = 0;
    }
  }
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator-=(const vtkLargeInteger& n)
{
  if ((this->Negative ^ n.Negative) == 1) // cope with negatives
  {
    this->Plus(n);
  }
  else
  {
    if (this->IsSmaller(n))
    {
      vtkLargeInteger m(*this);
      *this = n;
      this->Minus(m);
      this->Complement();
    }
    else
    {
      this->Minus(n);
    }
    if (this->IsZero())
    {
      this->Negative = 0;
    }
  }
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator<<=(int n)
{
  int i;

  if (n < 0) // avoid negatives
  {
    *this >>= -n;
    return *this;
  }
  this->Expand(this->Sig + n);

  // first shift
  for (i = this->Sig; i >= n; i--)
  {
    this->Number[i] = this->Number[i - n];
  }
  for (i = n - 1; i >= 0; i--) // then fill with 0s
  {
    this->Number[i] = 0;
  }
  this->Contract();
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator>>=(int n)
{
  if (n < 0) // avoid negatives
  {
    *this <<= -n;
    return *this;
  }

  // first shift the data
  unsigned int i;
  if (this->Sig >= static_cast<unsigned long>(n))
  {
    for (i = 0; i <= (this->Sig - n); i++)
    {
      this->Number[i] = this->Number[i + n];
    }
  }

  // then clear the other values to be safe
  int start = (this->Sig - n + 1);
  if (start < 0)
  {
    start = 0;
  }
  for (i = start; i <= this->Sig; i++)
  {
    this->Number[i] = 0;
  }

  start = start - 1;
  if (start < 0)
  {
    start = 0;
  }
  this->Sig = start;
  if (this->IsZero())
  {
    this->Negative = 0;
  }
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator++()
{
  return (*this += 1);
}

vtkLargeInteger& vtkLargeInteger::operator--()
{
  return (*this -= 1);
}

vtkLargeInteger vtkLargeInteger::operator++(int)
{
  vtkLargeInteger c = *this;
  *this += 1;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator--(int)
{
  vtkLargeInteger c = *this;
  *this -= 1;
  return c;
}

vtkLargeInteger& vtkLargeInteger::operator*=(const vtkLargeInteger& n)
{
  vtkLargeInteger c;
  int m2 = this->Sig + n.Sig + 1;
  this->Expand(m2);
  if (n.IsSmaller(*this)) // loop through the smaller number
  {
    for (unsigned int i = 0; i <= n.Sig; i++)
    {
      if (n.Number[i] == 1)
      {
        c.Plus(*this); // add on multiples of two
      }
      *this <<= 1;
    }
  }
  else
  {
    vtkLargeInteger m = n;
    for (unsigned int i = 0; i <= this->Sig; i++)
    {
      if (this->Number[i] == 1)
      {
        c.Plus(m); // add on multiples of two
      }
      m <<= 1;
    }
  }
  if (c.IsZero()) // check negatives
  {
    c.Negative = 0;
  }
  else
  {
    c.Negative = this->Negative ^ n.Negative;
  }

  *this = c;
  this->Contract();
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator/=(const vtkLargeInteger& n)
{
  if (n.IsZero()) // no divide by zero
  {
    vtkGenericWarningMacro("Divide by zero!");
    return *this;
  }

  vtkLargeInteger c;
  vtkLargeInteger m = n;
  m <<= std::max<int>(this->Sig - n.Sig, 0); // vtkpower of two multiple of n
  vtkLargeInteger i = 1;
  i = i << (this->Sig - n.Sig);
  for (; i > 0; i = i >> 1)
  {
    if (!m.IsGreater(*this))
    {
      this->Minus(m); // subtract of large chunk at time
      c += i;
    }
    m >>= 1; // shrink chunk down
  }
  if (c.IsZero()) // check negatives
  {
    c.Negative = 0;
  }
  else
  {
    c.Negative = this->Negative ^ n.Negative;
  }
  *this = c;
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator%=(const vtkLargeInteger& n)
{
  if (n.IsZero()) // no divide by zero
  {
    vtkGenericWarningMacro("Divide by zero!");
    return *this;
  }

  vtkLargeInteger m = n;
  m <<= std::max<int>(this->Sig - n.Sig, 0); // power of two multiple of n
  for (int i = this->Sig - n.Sig; i >= 0; i--)
  {
    if (!m.IsGreater(*this))
    {
      this->Minus(m); // subtract of large chunk at time
    }
    m >>= 1; // shrink chunk down
  }
  if (this->IsZero())
  {
    this->Negative = 0;
  }
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator&=(const vtkLargeInteger& n)
{
  int m = std::max(this->Sig, n.Sig);
  this->Expand(m); // match sizes
  for (int i = std::min(this->Sig, n.Sig); i >= 0; i--)
  {
    this->Number[i] &= n.Number[i];
  }
  this->Contract();
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator|=(const vtkLargeInteger& n)
{
  int m = std::max(this->Sig, n.Sig);
  this->Expand(m); // match sizes
  for (int i = std::min(this->Sig, n.Sig); i >= 0; i--)
  {
    this->Number[i] |= n.Number[i];
  }
  this->Contract();
  return *this;
}

vtkLargeInteger& vtkLargeInteger::operator^=(const vtkLargeInteger& n)
{
  int m = std::max(this->Sig, n.Sig);
  this->Expand(m); // match sizes
  for (int i = std::min(this->Sig, n.Sig); i >= 0; i--)
  {
    this->Number[i] ^= n.Number[i];
  }
  this->Contract();
  return *this;
}

vtkLargeInteger vtkLargeInteger::operator+(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c += n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator-(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c -= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator*(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c *= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator/(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c /= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator%(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c %= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator&(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c &= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator|(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c |= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator^(const vtkLargeInteger& n) const
{
  vtkLargeInteger c = *this;
  c ^= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator<<(int n) const
{
  vtkLargeInteger c = *this;
  c <<= n;
  return c;
}

vtkLargeInteger vtkLargeInteger::operator>>(int n) const
{
  vtkLargeInteger c = *this;
  c >>= n;
  return c;
}

ostream& operator<<(ostream& s, const vtkLargeInteger& n)
{
  if (n.Negative)
  {
    s << '-';
  }
  for (int i = n.Sig; i >= 0; i--)
  {
    s << char(n.Number[i] + '0');
  }
  return s;
}

istream& operator>>(istream& s, vtkLargeInteger& n)
{
  char c = 0;
  while (s.get(c)) // strip any leading spaces
    if (c != ' ' && c != '\n' && c != '\r')
    {
      s.putback(c);
      break;
    }
  n = 0;
  while (s.get(c)) // check for this->Negative
  {
    if (c != '-' && c != '+')
    {
      s.putback(c);
      break;
    }
    if (c == '-')
      n.Negative = !n.Negative;
  }
  while (s.get(c)) // build digits in reverse
  {
    if (c != '0' && c != '1')
    {
      s.putback(c);
      break;
    }
    if (n.Sig > n.Max)
    {
      n.Expand(n.Sig + BIT_INCREMENT);
      n.Sig -= BIT_INCREMENT;
    }
    n.Number[n.Sig++] = c - '0';
  }
  if (n.Sig > 0) // put digits right way round
  {
    n.Sig--;
    for (unsigned int j = n.Sig; j > n.Sig / 2; j--)
    {
      c = n.Number[j];
      n.Number[j] = n.Number[n.Sig - j];
      n.Number[n.Sig - j] = c;
    }
    n.Contract();
  }
  return s;
}
VTK_ABI_NAMESPACE_END
