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


#include "aux0/swap.h"
#include "fxttypes.h"


class ksubset_twoclose
// k-subsets (kmin<=k<=kmax) in a two-close order with homogeneous moves.
// Recursive algorithm.
{
public:
    ulong *rv_;  // record of visits in graph (delta set)
    ulong n_;    // subsets of the n-element set

    // function to call with each combination:
    void (*visit_)(const ksubset_twoclose &);

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

public:
    explicit ksubset_twoclose(ulong n)
    {
        n_ = n;
#if !defined KSUBSET_TWOCLOSE_MAX_ARRAY_LEN
        rv_ = new ulong[n_];
#endif
    }


    ~ksubset_twoclose()
    {
#if !defined KSUBSET_TWOCLOSE_MAX_ARRAY_LEN
        delete [] rv_;
#endif
    }

    void generate(void (*visit)(const ksubset_twoclose &),
                  ulong kmin, ulong kmax)
    {
        visit_ = visit;
        ulong kmax0 = n_ - kmin;
        next_rec(n_, kmax, kmax0, 0);
    }

private:
    void next_rec(ulong d, ulong n1, ulong n0, bool q)
    // d:  remaining depth in recursion
    // n1: remaining ones to fill in
    // n0: remaining zeros to fill in
    // q:  direction in recursion
    {
        if ( 0==d )  { visit_(*this);  return; }

        --d;

        if ( q )
        {
            if ( n0 )  { rv_[d]=0;  next_rec(d, n1-0, n0-1, d&1); }
            if ( n1 )  { rv_[d]=1;  next_rec(d, n1-1, n0-0, q); }
        }
        else
        {
            if ( n1 )  { rv_[d]=1;  next_rec(d, n1-1, n0-0, q); }
            if ( n0 )  { rv_[d]=0;  next_rec(d, n1-0, n0-1, d&1); }
        }
    }
};
// -------------------------


#endif  // !defined HAVE_KSUBSET_TWOCLOSE_H__
