#if !defined  HAVE_WEAK_ASCENT_RGS_H__
#define       HAVE_WEAK_ASCENT_RGS_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/is-ascent-rgs.h"

#include "comb/comb-print.h"

#include "fxttypes.h"


// whether to use arrays instead of pointers:
#define WEAK_ASCENT_RGS_FIXARRAYS  // default on


class weak_ascent_rgs
// Weak ascent sequences (restricted growth strings, RGS), lexicographic order.
// A weak ascent sequence is a sequence [d(1), d(2), ..., d(n)] where d(1)=0, d(k)>=0,
//   and d(k) <= 1 + asc([d(1), d(2), ..., d(k-1)]) and asc(.) counts the
//   number of weak ascents d(j) >= d(j-1) of its argument.
// See OEIS sequences A336070, A369321, A369322.
{
public:
#if !defined WEAK_ASCENT_RGS_FIXARRAYS
    ulong *A;  // digits of the RGS: A[k] <= M[k-1] + 1
    ulong *M;  // m[k] = number of weak ascents in prefix a[0,1,..,k]
#else
    ulong A[32];  // > 2^98 ascent sequences
    ulong M[32];
#endif
    ulong n_;   // Number of digits

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

public:
    explicit weak_ascent_rgs(ulong n)
    {
        n_ = (n > 0 ? n : 1);  // shall work for n==0
#if !defined WEAK_ASCENT_RGS_FIXARRAYS
        A = new ulong[n_];
        M = new ulong[n_];
#endif
        first();
    }

    ~weak_ascent_rgs()
    {
#if !defined WEAK_ASCENT_RGS_FIXARRAYS
        delete [] A;
        delete [] M;
#endif
    }

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

    void first()
    {
        for (ulong k=0; k<n_; ++k)  A[k] = 0;
        for (ulong k=0; k<n_; ++k)  M[k] = k;
    }

    ulong next()
    // Return position of leftmost change, zero with last.
    {
        ulong j = n_ - 1;
        while ( j != 0 )
        {
            if ( A[j] <= M[j-1] )  break;  // can increment
            A[j] = 0;
            --j;
        }

        if ( j==0 )  return 0;  // current is last

        ++A[j];

        ulong na = M[j-1] + ( A[j] >= A[j-1] );
        for (ulong z=j; z<n_; ++z)  { M[z] = na; na += ( z != j ); }
//        for (ulong z=j; z<n_; ++z)  { M[z] = M[z-1] + ( A[z] >= A[z-1] ); }

        return j;
    }

    ulong num_weak_ascents()  const
    // Return number of weak ascents.
    { return  M[n_-1]; }

    void print(const char *bla, bool dfz=true)  const
    { print_vec(bla, data(), n_, dfz); }

    bool OK()  const
    {
        // ascent stats in m[] OK?
        if ( M[0] != 0 )  return false;
        ulong na = 0;
        for (ulong j=1; j<n_; ++j)
        {
            na += ( A[j] >= A[j-1] );
            if ( M[j] != na )  return false;
        }

        return  is_weak_ascent_rgs(A, n_);
    }
};
// -------------------------


#endif  // !defined HAVE_WEAK_ASCENT_RGS_H__
