#if !defined HAVE_COMPOSITION_NZ_SUBDIAGONAL_H__
#define      HAVE_COMPOSITION_NZ_SUBDIAGONAL_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-composition-nz.h"

#include "comb/comb-print.h"
#include "comb/print-composition-aa.h"

#include "fxttypes.h"


class composition_nz_subdiagonal
// Subdiagonal compositions: compositions a[1] + a[2] + ... + a[m] = n
//   such that a[k] <= k.
// Lexicographic order.
// Cf. OEIS sequence A008930.
{
public:
    ulong n_;  // composition of n
    ulong m_;  // current composition has m parts
    ulong *A;  // composition: a[1] + a[2] + ... + a[m] = n

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

public:
    explicit composition_nz_subdiagonal(ulong n)
    {
        n_ = n;
        A = new ulong[n_+1];
        A[0] = 0;  // unused
        first();
    }

    ~composition_nz_subdiagonal()
    { delete [] A; }

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

    ulong num_parts()  const  { return m_; }

    void first()
    {
        m_ = n_;
        for (ulong j=1; j<=n_; ++j)  A[j] = 1;
    }

    ulong next()
    // Return number of parts of generated composition.
    // Return zero if the current is the last composition.
    {
        if ( m_ <= 1 )  return 0;  // make things work for n == 0

        const ulong m1 = m_ - 1;
        const ulong y = A[m1];
        const ulong z = A[m_];
        A[m_] = 1;
        if ( y+1 <= m1 )  // easy case
        {
            A[m1] = y+1;
            // elements after that are already all 1
            m_ +=  z - 2;
        }
        else
        {
            ulong s = z;
            ulong w = m1;
            while ( A[w] >= w )  // skip elements on diagonal
            {
                s += A[w];
                A[w] = 1;
                if ( w <= 1 )  return 0;  // current is last
                --w;
            }
            A[w] += 1;
            // elements after that are already all 1
            m_ = w + s - 1;
        }
        return m_;
    }


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

    void print_aa()  const  // ASCII art
    { print_composition_aa(data(), m_); }

    bool OK()  const
    {
        if ( ! is_composition_nz(data(), num_parts(), n_) )  return false;

        if ( m_ > n_ )  return false;

        for (ulong j=1; j<=m_; ++j)  // a[k] <= k
            if ( A[j] > j )  return false;

        return true;
    }
};
// -------------------------


#endif  // !defined HAVE_COMPOSITION_NZ_SUBDIAGONAL_H__
