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

#include "comb/setpart.h"
#include "fxtiomanip.h"
#include "fxttypes.h"

#include "aux0/sign.h" // abs()

//#include "jjassert.h"

int
setpart::cp_append(const int *src, int *dst, ulong k, ulong a)
// Copy partition in src[0,...,k-2] to dst[0,...,k-1]
// append element k at subset a (a>=0)
// Return number of sets in created partition.
{
    ulong ct = 0;
    for (int j=0; j<(int)k-1; ++j)
    {
        int e = src[j];
        if ( e > 0 )  dst[j] = e;
        else
        {
            if ( a==ct )
            {
                dst[j]=-e;
                ++dst;
                dst[j]=-(int)k;
            }
            else  dst[j] = e;
            ++ct;
        }
    }
    if ( a>=ct )  { dst[k-1] = (int)(-k); ++ct; }

    return (int)ct;
}
// -------------------------

//void
//setpart::as2x()
//{
//    for (ulong k=0; k<n_; ++k)  h_[k] = 0;
//    for (ulong k=0; k<n_; ++k)  ++h_[as_[k+1]];
//    for (ulong k=1; k<n_; ++k)  h_[k] += h_[k-1];
//    for (ulong k=n_-1; k; --k)  h_[k] = h_[k-1];
//    h_[0] = 0;
//    for (ulong k=0; k<n_; ++k)  x_[k] = 0;
//    for (ulong k=0; h_[k]<n_; ++k)  x_[h_[k]] = 1;
//
//    for (ulong k=0; k<n_; ++k)
//    {
//        x_[h_[k]] = k+1;
//        h_[k]++;
//    }
//}
//// -------------------------


int
setpart::next_rec(ulong k)
// Update partition in level k from partition in level k-1  (k<=n)
// Return number of sets in created partition
{
    if ( k<=1 )  return 0;  // current is last

    int d = d_[k];
    int as = as_[k] + d;
    bool ovq = ( (d>0) ? (as>ns_[k-1]) : (as<0) );
    if ( ovq )  // have to recurse
    {
        ulong ns1 = next_rec(k-1);
        if ( 0==ns1 )  return 0;

        d = ( xdr_ ? -d : dr0_ );
        d_[k] = d;

        as = ( (d>0) ? 0 : ns_[k-1] );
    }
    as_[k] = as;

    ulong ns = cp_append(pp_[k-1], pp_[k], k, as);
    ns_[k] = (int)ns;
    return  (int)ns;
}
// -------------------------


void
setpart::init(bool xdr, int dr0)
{
    dr0 = ( (dr0>=0) ? +1 : -1 );
    dr0_ = dr0;

    xdr_ = xdr;

    p_[0] = -1;

    ulong n = n_;
    if ( dr0_>0 )
    {
        for (ulong k=0; k<=n; ++k)  as_[k] = 0;
        for (ulong k=0; k<=n; ++k)  ns_[k] = 1;
    }
    else
    {
        for (ulong k=0; k<=n; ++k)  as_[k] = (int)k - 1;
        for (ulong k=0; k<=n; ++k)  ns_[k] = (int)k;
    }

    for (ulong k=0; k<=n; ++k)  d_[k] = dr0_;

    for (ulong k=2; k<=n; ++k)
    {
        cp_append(pp_[k-1], pp_[k], k, as_[k]);
    }
}
// -------------------------


void
setpart::print_internal()  const
{
//    const char sep[]=", ";
    const char sep[]=" ";

    ulong n = n_;
    const int *x = pp_[n];

    cout << "as[ ";
    for (ulong j=1; j<=n; ++j)  cout << as_[j] << sep;
    cout << "]    ";

    cout << "ns[ ";
    for (ulong j=1; j<=n; ++j)  cout << ns_[j] << sep;
    cout << "]    ";

    cout << "d[ ";
    for (ulong j=1; j<=n; ++j)  cout << (d_[j]>0 ? '+' : '-') << sep;
    cout << "]    ";

//    cout << "h[ ";
//    for (ulong j=0; j<n; ++j)  cout << h_[j] << ", ";
//    cout << "]    ";

    cout << "x[ ";
    for (ulong j=0; j<n; ++j)  cout << (x[j]>0?'+':'-') << abs(x[j]) << sep;
    cout << "]    ";
}
// -------------------------

ulong
setpart::print_p(ulong k)  const
{
    const int *x = pp_[k];
    ulong n = k;

    ulong nch = 1;  // number of chars printed
    cout << "{";
    for (ulong j=0; j<n; ++j)
    {
        int e = x[j];
        if ( e>0 ) { cout << e << ", ";  nch += 3; }
        else
        {
            e = -e;
            cout << e << "}";  nch += 2;
            if ( j+1<n )  { cout << ", {";  nch +=3; }
        }
    }

    if ( n>9 )
    {
        nch += (n-9);
        if ( n>99 )  nch += (n-99);
    }

    return nch;
}
// -------------------------
