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

#include "comb/perm1-topsort.h"

#include "fxttypes.h"
#include "fxtio.h"
#include "jjassert.h"

class young_tab_fixed_shape
// Young tableaux with fixed shape.
// The underlying driver is class perm1_topsort.
// OEIS sequences "Young tableaux of shape [??]:
// A000108: [n,n]
// A005789: [n,n,n]
// A005790: [n,n,n,n]
// A039622: [n, n, ..., n] (n times n)
// A005118: [n, n-1, n-2, n-3, ..., 1]
// A003121: [1, 2, 3, ..., n]
// A071724: [n+1, n-1], also [n, 1, n]
// A000344: [n+2, n-2], also [n, 1, 1, 1, n]
// A000588: [n+3, n-3]
// A174687: [2*n, n]
// A123555: [n+1, n, n-1]
// A368567: [n, floor(n/2)]
// with shiftq == true:
// A181197: [n, n, n]
// A181198: [n, n, n, n]
// A181199: [n, n, n, n, n]
{
private:
    perm1_topsort *T;
    ulong *Z;  // priorities
    ulong *R;  // stats
    ulong n;   // number of elements to permute
    ulong k;   // number of types elements
    bool shiftq;
    inline static ulong ict = 0;  // number of objects; max 1
    inline static ulong * st_Z = nullptr; // == Z (of the one allowed object)

private:  // have pointer data
    young_tab_fixed_shape(const young_tab_fixed_shape&) = delete;
    young_tab_fixed_shape & operator = (const young_tab_fixed_shape&) = delete;

public:
    static bool cond_prio( ulong k , ulong l )
    {
//        if ( l==0 )  return false;
        return ( st_Z[ k ] < st_Z[ l ] );
    }

public:
    explicit young_tab_fixed_shape( const ulong * tR, ulong tk,
                                    bool tshiftq = false)
    {
        if ( ict != 0)
        {
            cerr << "Error: "
                 << "only one instance of young_tab_fixed_shape may exist!\n";
            // because we cannot create a non-static condition function
            jjassert( 0 );
        }
        ict = 1;

        shiftq = tshiftq;
        k = tk;
        R = new ulong[k];
        n = 0;
        for (ulong j=0; j<k; ++j)  { R[j] = tR[j]; }
        for (ulong j=0; j<k; ++j)  { n += R[j]; }
        T = new perm1_topsort( n, cond_prio );

        Z = new ulong[n+1];
        Z[0] = 0;  // is used
        st_Z = Z;
        first();
    }

//    void init_shape( const ulong * tR, ulong tk )
//    // n must be identical for new shape.
//    {
//    }

    ~young_tab_fixed_shape()
    {
        delete T;
        delete [] Z;
        delete [] R;
        ict = 0;
        st_Z = nullptr;
    }

    const perm1_topsort *topsort_obj()  const  { return T; }
    const ulong *data()  const  { return T->data(); }

    void first()
    {
        ulong w = 1;  // write position
        for (ulong j=0; j < k; ++j)
        {
            ulong z = 1;  // priority
            if ( shiftq )  z += j;
            for (ulong i=0; i < R[j]; ++i)
            {
                Z[w] = z;
                ++z;
                ++w;
            }
        }
        jjassert( w == n + 1 );

        T->first();
    }

    bool next()  { return T->next(); }

    void print(const char * bla=nullptr, bool pshift=false)  const
    {
        if ( bla )  { cout << bla << endl; }
        const ulong * Q = T->data();
        ulong r = 0;  // read position
        for (ulong i=0; i < k; ++i)
        {
            if ( pshift )
            { for (ulong j=0; j<i; ++j)  { cout << "   "; } }

            for (ulong j=0; j < R[i]; ++j)
            {
                cout << setw(3) << Q[r];
                ++r;
            }
            cout << endl;
        }
    }
};
// -------------------------

#endif // !defined HAVE_YOUNG_TAB_FIXED_SHAPE_H__
