#if !defined HAVE_FRACTIONAL_BASE_NUMBER_H__
#define      HAVE_FRACTIONAL_BASE_NUMBER_H__
// This file is part of the FXT library.
// Copyright (C) 2021, 2023 Joerg Arndt
// License: GNU General Public License version 3 or later,
// see the file COPYING.txt in the main directory.


#include "fxttypes.h"

#include <iostream>

#define FRACTIONAL_BASE_NUMBER_FIXARRAYS

class fractional_base_number
// Numbers with fractional base b_num / b_den.
// Special case b_den == 1 gives the usual base - b_num numbers.
// Must have b_num >= 2 and 1 <= b_den < b_num.
{
public:
    static constexpr ulong enough = 256;  // max. number of digits
private:
#if defined FRACTIONAL_BASE_NUMBER_FIXARRAYS
    ulong D[enough];
#else
    ulong * D { nullptr };
#endif

    ulong num_dig;  // current number of digits, set to 0 for the number zero
    const ulong b_num = 3;  // base: numerator; highest digit allowed is b_num - 1
    const ulong b_den = 2;  // base: denominator; the carry with incrementing
    const ulong num_dig_max;  // max for num_dig


public:
    fractional_base_number( ulong b_num_, ulong b_den_, ulong num_dig_max_)
        : b_num(b_num_), b_den(b_den_), num_dig_max(num_dig_max_)
    {
#if defined FRACTIONAL_BASE_NUMBER_FIXARRAYS
#else
        D = new ulong[num_dig_max];
#endif
        first();
    }

    ~fractional_base_number()
    {
#if defined FRACTIONAL_BASE_NUMBER_FIXARRAYS
#else
        delete [] D;
#endif
    }

    void first()
    {
        for (ulong j=0; j <= num_dig_max; ++j)  D[j] = 0;
        num_dig = 0;  // zero has no digits
    }

    const ulong * data()  const  { return D; }

private:
//    __attribute__((always_inline))
    ulong incr_at( ulong j, ulong cy )
    // return carry
    {
        const ulong di = D[j] + cy;
        if ( di < b_num )  // carry = 0
        {
            D[ j ] = di;
            return 0;
        }
        else  // carry = b_den
        {
            D[ j ] = di - b_num;
            return  b_den;
        }
    }

public:
    ulong next()
    // Return length of number,
    // return zero if next number would have more then num_dig_max digits
    {
        ulong j = 0;
        ulong cy = 1;
        do
        {
            cy = incr_at(j, cy);
            j += 1;
        }
        while ( cy != 0 );

        if ( j > num_dig ) num_dig = j;  // increment num_dig

        if ( num_dig > num_dig_max )  return 0;  // current is last

        return num_dig;
    }

    void print_as_array()  const
    // unit digit first
    // the number zero gives no output
    {
        for (ulong j=0; j<num_dig; ++j)
        {
            std::cout << D[j];
            if ( b_num > 10 )  std::cout << ',';
        }
//        std::cout << "\n";
    }

    void print_as_number()  const
    // unit digit last
    // the number zero gives no output
    {
        ulong j = num_dig;
        while ( j != 0 )
        {
            j -= 1;
            std::cout << D[j];
            if ( b_num > 10 )  std::cout << ',';
        }
//        std::cout << "\n";
    }
};
// -------------------------

#endif  // !defined HAVE_FRACTIONAL_BASE_NUMBER_H__
