// HugeIntX.h: interface for the CHugeIntX class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_HUGEINTX_H__5B7DCBAC_6D89_4C55_B51F_D96B5E741B51__INCLUDED_)
#define AFX_HUGEINTX_H__5B7DCBAC_6D89_4C55_B51F_D96B5E741B51__INCLUDED_

#if _MSC_VER > 1000
    #pragma once
#endif // _MSC_VER > 1000

#include "HugeCalc.h"
#include "RadixConverter.h"

class CHugeSIntX;
class CHugeIntX;

typedef struct tagCVECTOR_HHUGEINTX
{
    CONST CHugeIntX ** p_start;
    UINT32 u32Size;

#ifdef __cplusplus
    tagCVECTOR_HHUGEINTX( CONST CHugeIntX ** CONST _p_start = NULL, CONST UINT32 _u32Size = 0 )
        : p_start( _p_start ), u32Size( _u32Size )
    {
    };
#endif
} CVECTOR_HHUGEINTX, FAR *PCVECTOR_HHUGEINTX;
typedef CONST CVECTOR_HHUGEINTX FAR *LPCVECTOR_HHUGEINTX;

#define HX_API HUGECALC_API

class HX_API CHugeIntX
{
    friend class CHugeInt;
    friend CRadixConverter& CRadixConverter::operator =( CONST CHugeIntX& right );
    // CompareAbs
    HX_API friend CONST SINT32 CompareAbs( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST SINT32 CompareAbs( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST SINT32 CompareAbs( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST SINT32 CompareAbs( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST SINT32 CompareAbs( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // Compare
    HX_API friend CONST SINT32 Compare( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST SINT32 Compare( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST SINT32 Compare( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST SINT32 Compare( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST SINT32 Compare( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // PowMod
    HX_API friend CONST UINT32 PowMod( CONST UINT32 u32Base, CONST CHugeIntX& hugeExp, CONST UINT32 u32Mod );
    HX_API friend CONST SINT64 PowMod( CONST CHugeIntX& hugeBase, CONST UINT32 u32Exp, CONST UINT32 u32Mod );
    HX_API friend CONST SINT64 PowMod( CONST CHugeIntX& hugeBase, CONST SINT32 s32Exp, CONST UINT32 u32Mod );
    HX_API friend CONST SINT64 PowMod( CONST CHugeIntX& hugeBase, CONST CHugeIntX& hugeExp, CONST UINT32 u32Mod );

    // relation operators
    HX_API friend CONST BOOL operator ==( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST BOOL operator ==( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator ==( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST BOOL operator ==( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST BOOL operator ==( CONST CHugeIntX& left, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator !=( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST BOOL operator !=( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator !=( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST BOOL operator !=( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST BOOL operator !=( CONST CHugeIntX& left, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator <( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST BOOL operator <( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator <( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST BOOL operator <( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST BOOL operator <( CONST CHugeIntX& left, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator <=( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST BOOL operator <=( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator <=( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST BOOL operator <=( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST BOOL operator <=( CONST CHugeIntX& left, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator >( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST BOOL operator >( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator >( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST BOOL operator >( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST BOOL operator >( CONST CHugeIntX& left, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator >=( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST BOOL operator >=( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST BOOL operator >=( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST BOOL operator >=( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST BOOL operator >=( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // +
    HX_API friend CONST CHugeIntX operator +( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST CHugeIntX operator +( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST CHugeIntX operator +( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST CHugeIntX operator +( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST CHugeIntX operator +( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // -
    HX_API friend CONST CHugeIntX operator -( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST CHugeIntX operator -( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST CHugeIntX operator -( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST CHugeIntX operator -( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST CHugeIntX operator -( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // *
    HX_API friend CONST CHugeIntX operator *( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST CHugeIntX operator *( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST CHugeIntX operator *( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST CHugeIntX operator *( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST CHugeIntX operator *( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // Division, return quotient
    HX_API friend CONST SINT64 Div( CONST UINT32 u32Dividend, CONST CHugeIntX& hugeDivisor, UINT32 * CONST pRemainder = NULL );
    HX_API friend CONST SINT32 Div( CONST SINT32 s32Dividend, CONST CHugeIntX& hugeDivisor, SINT32 * CONST pRemainder = NULL );

    // /
    HX_API friend CONST SINT64 operator /( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST SINT32 operator /( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST CHugeIntX operator /( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST CHugeIntX operator /( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST CHugeIntX operator /( CONST CHugeIntX& left, CONST CHugeIntX& right );

    // %
    HX_API friend CONST UINT32 operator %( CONST UINT32 u32Num, CONST CHugeIntX& right );
    HX_API friend CONST SINT32 operator %( CONST SINT32 s32Num, CONST CHugeIntX& right );

    HX_API friend CONST SINT64 operator %( CONST CHugeIntX& left, CONST UINT32 u32Num );
    HX_API friend CONST SINT32 operator %( CONST CHugeIntX& left, CONST SINT32 s32Num );

    HX_API friend CONST CHugeIntX operator %( CONST CHugeIntX& left, CONST CHugeIntX& right );

public:
    // Constructor
    explicit CHugeIntX( VOID );
    explicit CHugeIntX( CONST SINT32& s32Num );
    explicit CHugeIntX( CONST SINT64& s64Num );
    explicit CHugeIntX( CONST UINT32& u32Num );
    explicit CHugeIntX( CONST UINT64& u64Num );
    explicit CHugeIntX( CONST LPCTSTR lpszNum );
    explicit CHugeIntX( CONST CRadixConverter& RadixConverter );
    explicit CHugeIntX( CONST CHugeIntX& right );
    explicit CHugeIntX( CONST CHugeInt& right );

    // destructor
    /*virtual */~CHugeIntX( );

    static CONST UINT32 GetCount( VOID );

    // reload operator ->
    CHugeIntX * CONST operator ->( VOID );

    // get property
    CONST SIGN GetSign( VOID ) CONST;
    CONST BOOL operator !( VOID ) CONST;
    CONST BOOL IsAbsOne( VOID ) CONST;
    CONST BOOL IsOdd( VOID ) CONST;
    CONST BOOL IsEven( VOID ) CONST;
    CONST BOOL IsBitOne( CONST UINT32 u32BitIndex ) CONST;
    CONST BOOL IsPrime( VOID ) CONST;
    CONST PRIMALITY TestPrimality( CONST UINT32 u32Repeat = 5 ) CONST;
    CONST UINT32 GetBits( VOID ) CONST;
    CONST UINT32 GetDigits( VOID ) CONST;
    CONST UINT32 GetTailBitZeros( VOID ) CONST;

    // Return non-zero if the value of (*this) fits in SINT32, UINT32, SINT64 or UINT64, respectively. Otherwise, return zero.
    operator CONST SINT32( VOID ) CONST;
    operator CONST SINT64( VOID ) CONST;
    operator CONST UINT32( VOID ) CONST;
    operator CONST UINT64( VOID ) CONST;
    // as GetStr( FS_FS_NORMAL )
    operator CONST LPCTSTR( VOID ) CONST;

    CONST CHugeIntX operator -( VOID ) CONST;

    CHugeIntX& Abs( VOID );
    CHugeIntX& Negate( VOID );
    CHugeIntX& Swap( CHugeIntX& right );

    CHugeIntX& Ceil( CONST UINT32 u32Bits );
    CHugeIntX& Truncate( CONST UINT32 u32Bits );
    CHugeIntX& Floor( CONST UINT32 u32Bits );

    CHugeIntX& Random( CONST UINT32 u32Bits );
    CHugeIntX& GeneratePrime( CONST UINT32 u32Bits );

    // Returns the largest prime number less than the argument.
    CHugeIntX& PreviousPrime( CONST CHugeIntX& hBenchmark );
    // Returns the smallest prime number greater than the argument.
    CHugeIntX& NextPrime( CONST CHugeIntX& hBenchmark );

    // reload operators
    CHugeIntX& operator =( CONST SINT32& s32Num );
    CHugeIntX& operator =( CONST SINT64& s64Num );
    CHugeIntX& operator =( CONST UINT32& u32Num );
    CHugeIntX& operator =( CONST UINT64& u64Num );
    CHugeIntX& operator =( CONST LPCTSTR lpszNum );
    CHugeIntX& operator =( CONST CRadixConverter& RadixConverter );
    CHugeIntX& operator =( CONST CHugeIntX& right );
    CHugeIntX& operator =( CONST CHugeInt& right );

    CHugeIntX& SetHexStr( CONST LPCTSTR lpszHexNum );

    CHugeIntX& SetText( CONST LPCTSTR lpszText );

    CHugeIntX& operator +=( CONST UINT32 u32Num );
    CHugeIntX& operator +=( CONST SINT32 s32Num );
    CHugeIntX& operator +=( CONST CHugeIntX& right );

    CHugeIntX& operator ++( VOID );
    CONST CHugeIntX operator ++( CONST INT );

    CHugeIntX& operator -=( CONST UINT32 u32Num );
    CHugeIntX& operator -=( CONST SINT32 s32Num );
    CHugeIntX& operator -=( CONST CHugeIntX& right );

    CHugeIntX& operator --( VOID );
    CONST CHugeIntX operator --( CONST INT );

    CHugeIntX& operator *=( CONST UINT32 u32Num );
    CHugeIntX& operator *=( CONST SINT32 s32Num );
    CHugeIntX& operator *=( CONST CHugeIntX& right );

    CHugeIntX& operator /=( CONST UINT32 u32Num );
    CHugeIntX& operator /=( CONST SINT32 s32Num );
    CHugeIntX& operator /=( CONST CHugeIntX& right );

    CHugeIntX& operator %=( CONST UINT32 u32Num );
    CHugeIntX& operator %=( CONST SINT32 s32Num );
    CHugeIntX& operator %=( CONST CHugeIntX& right );

    CHugeIntX& operator <<=( CONST UINT32 u32BitLShift );
    CHugeIntX& operator >>=( CONST UINT32 u32BitRShift );

    CONST CHugeIntX operator <<( CONST UINT32 u32BitLShift ) CONST;
    CONST CHugeIntX operator >>( CONST UINT32 u32BitRShift ) CONST;

    CHugeIntX& operator &=( CONST CHugeIntX& right );
    CHugeIntX& operator ^=( CONST CHugeIntX& right );
    CHugeIntX& operator |=( CONST CHugeIntX& right );

    CONST CHugeIntX operator &( CONST CHugeIntX& right ) CONST;
    CONST CHugeIntX operator ^( CONST CHugeIntX& right ) CONST;
    CONST CHugeIntX operator |( CONST CHugeIntX& right ) CONST;

    // Multiplication, return product
    CHugeIntX& Mul( CONST UINT32 u32Multiplicand, CONST CHugeIntX& hugeMultiplier );
    CHugeIntX& Mul( CONST SINT32 s32Multiplicand, CONST CHugeIntX& hugeMultiplier );

    CHugeIntX& Mul( CONST CHugeIntX& hugeMultiplicand, CONST UINT32 u32Multiplier );
    CHugeIntX& Mul( CONST CHugeIntX& hugeMultiplicand, CONST SINT32 s32Multiplier );

    CHugeIntX& Mul( CONST CHugeIntX& hugeMultiplicand, CONST CHugeIntX& hugeMultiplier );

    // Division, return quotient
    CHugeIntX& Div( CONST CHugeIntX& hugeDividend, CONST UINT32 u32Divisor, SINT64 * CONST pRemainder = NULL );
    CHugeIntX& Div( CONST CHugeIntX& hugeDividend, CONST SINT32 s32Divisor, SINT32 * CONST pRemainder = NULL );

    CHugeIntX& Div( CONST CHugeIntX& hugeDividend, CONST CHugeIntX& hugeDivisor, CHugeIntX * CONST pRemainder = NULL );

    CHugeIntX& Pow( CONST UINT32 u32Exp );
    CHugeIntX& Pow( CONST CHugeIntX& hugeBase, CONST UINT32 u32Exp );

    // Extraction
    CHugeIntX& Root( CONST CHugeIntX& hugeRadicand, CONST UINT32 u32Exp, CHugeIntX * CONST pRemainder = NULL, BOOL * CONST pIsReal = NULL );

    // Logarithm
    CONST UINT32 Log( CONST UINT32 u32Base, BOOL * CONST pIsExact = NULL ) CONST;
    CONST UINT32 Log( CONST CHugeIntX& hugeBase, BOOL * CONST pIsExact = NULL ) CONST;

    // PrimeFactorial(n) gives the product of the first n primes.
    CHugeIntX& PrimeFactorial( CONST UINT32 u32Index );
    // Primorial(n) gives the product of the primes less than or equal to n.
    CHugeIntX& Primorial( CONST UINT32 u32Num );

    // Factorial, Permutation, Combination
    CHugeIntX& Factorial( CONST UINT32 n );
    CHugeIntX& Factorial2( CONST UINT32 n );
    CHugeIntX& Permutation( CONST UINT32 n, CONST UINT32 r );
    CHugeIntX& Combination( CONST UINT32 n, CONST UINT32 r );

    // Fibonacci numbers
    CHugeIntX& Fibonacci( CONST SINT32 n );

    // Lucas numbers
    CHugeIntX& Lucas( CONST SINT32 n );

    // MulMod
    CHugeIntX& MulMod( CONST CHugeIntX& hugeMultiplicand, CONST CHugeIntX& hugeMultiplier, CONST CHugeIntX& hugeMod );
    CHugeIntX& MulMod( CONST CHugeIntX& hugeMultiplier, CONST CHugeIntX& hugeMod );

    // InvertMod: x = InvertMod( b, m ) && !(!x) <==> ( b * x ) mod m = 1
    CHugeIntX& InvertMod( CONST UINT32 u32InvertBase, CONST CHugeIntX& hugeMod );
    CHugeIntX& InvertMod( CONST CHugeIntX& hugeInvertBase, CONST CHugeIntX& hugeMod );
    CHugeIntX& InvertMod( CONST CHugeIntX& hugeMod );

    // PowMod
    CHugeIntX& PowMod( CONST UINT32 u32Base, CONST UINT32 u32Exp, CONST CHugeIntX& hugeMod );
    CHugeIntX& PowMod( CONST UINT32 u32Base, CONST SINT32 s32Exp, CONST CHugeIntX& hugeMod );
    CHugeIntX& PowMod( CONST UINT32 u32Base, CONST CHugeIntX& hugeExp, CONST CHugeIntX& hugeMod );
    CHugeIntX& PowMod( CONST CHugeIntX& hugeBase, CONST UINT32 u32Exp, CONST CHugeIntX& hugeMod );
    CHugeIntX& PowMod( CONST CHugeIntX& hugeBase, CONST SINT32 s32Exp, CONST CHugeIntX& hugeMod );
    CHugeIntX& PowMod( CONST CHugeIntX& hugeBase, CONST CHugeIntX& hugeExp, CONST CHugeIntX& hugeMod );

    // ModPowTwo: *this %= 2^u32Exp
    CHugeIntX& ModPowTwo( CONST UINT32 u32Exp );

    // Greatest Common Divisor
    CHugeIntX& Gcd( CONST UINT32 u32Num, CONST CHugeIntX& right );
    CHugeIntX& Gcd( CONST SINT32 s32Num, CONST CHugeIntX& right );
    CHugeIntX& Gcd( CONST CHugeIntX& left, CONST UINT32 u32Num );
    CHugeIntX& Gcd( CONST CHugeIntX& left, CONST SINT32 s32Num );

    CHugeIntX& Gcd( CONST CHugeIntX& left, CONST CHugeIntX& right );

    CHugeIntX& Gcd( CONST CVECTOR_HHUGEINTX& vLpHugeIntX );

    // GcdEx: g = GcdEx( x, y, u, v ) = u * x + v * y. g is always positive, even if one or both of u and v are negative.
    CHugeIntX& GcdEx( CHugeIntX& x, CHugeIntX& y, CONST CHugeIntX& u, CONST CHugeIntX& v );

    // Lowest Common Multiple
    CHugeIntX& Lcm( CONST CVECTOR_UINT32& vU32Num );

    CHugeIntX& Lcm( CONST UINT32 u32Num, CONST CHugeIntX& right );
    CHugeIntX& Lcm( CONST SINT32 s32Num, CONST CHugeIntX& right );
    CHugeIntX& Lcm( CONST CHugeIntX& left, CONST UINT32 u32Num );
    CHugeIntX& Lcm( CONST CHugeIntX& left, CONST SINT32 s32Num );

    CHugeIntX& Lcm( CONST CHugeIntX& left, CONST CHugeIntX& right );

    CHugeIntX& Lcm( CONST CVECTOR_HHUGEINTX& vLpHugeIntX );

    CHugeIntX& Product( CONST CVECTOR_UINT32& vU32Num );
    CHugeIntX& Product( CONST CVECTOR_HHUGEINTX& vLpHugeIntX );

    // if u32Exp==0, then call function: Product( ... );
    CHugeIntX& SumsOfLikePowers( CONST CVECTOR_UINT32& vU32Num, CONST UINT32 u32Exp = 1 );
    CHugeIntX& SumsOfLikePowers( CONST CVECTOR_HHUGEINTX& vLpHugeIntX, CONST UINT32 u32Exp = 1 );

    // Output
    CONST LPCTSTR GetStr( CONST BYTE byFormat = FS_DEFAULT, UINT32 * CONST pStrLen = NULL ) CONST;

    // no "0x"
    CONST LPCTSTR GetHexStr( CONST BYTE byFormat = FS_DEFAULT, UINT32 * CONST pStrLen = NULL ) CONST;

    // This function can convert the huge integer to a string of digits in another Radix system.
    CONST LPCTSTR GetStrRadix( CONST UINT32 u32Radix = 10, UINT32 * CONST pDigits = NULL, CONST BYTE byFormat = FS_DEFAULT, CONST UINT32 u32BandLength = 3, UINT32 * CONST pStrLen = NULL ) CONST;

    CONST LPCTSTR GetText( VOID ) CONST;

    VOID FreeStrBuffer( VOID ) CONST;

protected:

private:
    explicit CHugeIntX( CONST CHugeSIntX& right );
    CHugeIntX& operator =( CONST CHugeSIntX& right );

    CHugeSIntX * CONST m_pSHuge;
};

#endif // !defined(AFX_HUGEINTX_H__5B7DCBAC_6D89_4C55_B51F_D96B5E741B51__INCLUDED_)