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

#include "comb/comb-print.h"
#include "comb/binary-sl-gray.h"

#include "fxttypes.h"


class subset_sl_gray : binary_sl_gray
// Nonempty subsets of the set {0,1,2,...,n-1} in SL-Gray order.
// Representation as list of parts.
// Elements are inserted/removed either at end or
//   at the second-last position.
// Loopless generation.
// See OEIS sequence A217262.
{
private:
    ulong * L;  // set as list of elements
    ulong nl;    // length of current set

    subset_sl_gray(const subset_sl_gray&) = delete;
    subset_sl_gray & operator = (const subset_sl_gray&) = delete;

public:
    subset_sl_gray(ulong tn)
        : binary_sl_gray(tn)
    {
        L = new ulong[ tn ];
        first();
    }

    ~subset_sl_gray()  { delete [] L; }

    void first()
    {
        binary_sl_gray::first();
        for (ulong k=0; k < binary_sl_gray::n; ++k)  { L[k] = 77; }
        nl = 0;  // first set is the empty set
    }

    const ulong * data()  const  { return L; }
    ulong len()  const  { return nl; }

    bool next()
    {
        if ( ! binary_sl_gray::next() )  return false;

        const ulong p = binary_sl_gray::pos();  // position of change

        if ( binary_sl_gray::dir() == +1 )  // p was added
        {
            if ( nl != 0 )  // non-empty set (almost always)
            {
                const ulong z = L[ nl - 1 ];  // last in list
                if ( p > z )  // append new last element
                {
                    L[ nl ] = p;
                }
                else  // insert p at second to last place
                {
                    L[ nl ] = z;
                    L[ nl - 1 ] = p;
                }
                nl += 1;
            }
            else  // was empty set (once)
            {
                L[0] = 0;
                nl = 1;
            }
        }
        else  // p was removed
        {
            nl -= 1;
            const ulong z = L[ nl ];  // last in list
            if ( p == z )  // last element removed
            {
                ;
            }
            else  // second last element removed
            {
                L[ nl - 1 ] = z;  // new last = old last
            }
        }

        return true;
    }

    void print(const char *bla, ulong off=0)  const
    // If dfz is true then Dots are printed For Zeros.
    { print_set(bla, data(), len(), off); }

//    bool OK()  const;
};
// -------------------------

#endif // !defined HAVE_SUBSET_SL_GRAY_H__
