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

#include "perm/rotate.h"

#include "fxttypes.h"
//#include "jjassert.h"

//#include <iostream>

class binary_rot
// Binary strings by rotations of prefixes.
// This is the "cooler" order from:
// Brett Stevens, Aaron Williams: The coolest order of binary strings,
// 6th International Conference on Fun with Algorithms (FUN 2012),
// San Servolo, Italy. LNCS 7288, pp.322-333, (2012).
{
private:
    ulong *B;  // binary word
    ulong n;  // number of bits
    ulong ct;  //
    ulong ct_max;
public:
    explicit binary_rot(ulong tn)
    {
        n = tn;
        ct_max = 1UL << n;
        B = new ulong[n + 2];
        // sentinels
        B[n+0] = 1;
        B[n+1] = 0;
        first();
    }

    ~binary_rot()
    {
        delete [] B;
    }

    void first()
    {
        ct = 0;
        ulong j = 0;
        while ( j < n )  { B[j] = 0;  ++j; }
    }

    const ulong * data()  { return B; }

private:
    ulong find01()  const
    // return 0 if no [1,0] in word
    {
        ulong j = 1;
        while ( true )
        {
            while ( B[j] == 0 )  { ++j; }
            // here b[j] == 1
            if ( B[j+1] == 0 )
            {
                if ( j != n )  { return j; }
                else            { return 0; }
            }
            ++j;
        }
    }
public:
    bool next()
    {
        // Let j be the minimum value such that b[j],b[j+1] = 1,0 and j > 0.
        // If j exists, then rotate j + 2 bits.
        // Otherwise, flip b[0], and then rotate n bits.
        ++ct;
        if ( ct >= ct_max )  { return false; }
        ulong j = find01();
        if ( j==0 )
        {
            B[0] ^= 1;
            rotate_left1( B, n );
//            std::cout << " :::::::::::::\n";
        }
        else
        {
            rotate_left1( B, j+2 );
//            std::cout << " -------------\n";
        }

        return true;
    }

    ulong num_ones()  const
    {
        ulong h = 0;
        for (ulong j=0; j<n; ++j)  { h += B[j]; }
        return h;
    }
};
// -------------------------


#endif  // !defined HAVE_BINARY_ROT_H__
