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

#include "fxttypes.h"


void
rgs_to_paren_string(const ulong *rgs, ulong n, char *str, bool rq=false)
// Convert restricted growth string (Catalan-RGS) to paren-string.
// If rq is set then the reversed paren string is computed.
{
    str[2*n] = '\0';
    if ( n==0 )  return;  // nothing to do

    for (ulong k=0; k < 2*n; ++k)  str[k] = ')';
    for (ulong k=0,j=0; k<n; ++k,j+=2)  str[ j - rgs[k] ] = '(';

    if ( rq )  // reverse string and swap '(' and ')'
    {
        for (ulong j=0, k=2*n-1; j<k; ++j, --k)
        {
            char sj = str[j], sk = str[k];
            str[j] = ( sk == '(' ? ')' : '(' );
            str[k] = ( sj == '(' ? ')' : '(' );
        }
    }
}
// -------------------------


bool
paren_string_to_rgs(const char *str, ulong *rgs, bool rq/*=false*/)
// Convert paren-string to RGS,
// return whether parenthesis string is valid.
// rgs[j] = number of unclosed open parenthesis when
//  the j-th opening is found (j>=0).
// If rq is set then the RGS for the reversed paren string is computed.
{
    if ( str[0] == 0 )  return true;  // nothing to do

    long s = 0;  // running sum
    ulong jr = 0; // position in RGS
    if ( !rq )
    {
        for (ulong js=0; str[js]!=0; ++js)
        {
            if ( str[js] == '(' )
            {
                rgs[jr] = (ulong)s;
                ++jr;
                ++s;
            }
            else
            {
                --s;
                if ( s<0 )  return false;
            }
        }
    }
    else
    {
        ulong js = 0;
        while ( str[js] )  ++js;  // seek end

        while ( js-- )
        {
            if ( str[js] == ')' )
            {
                rgs[jr] = (ulong)s;
                ++jr;
                ++s;
            }
            else
            {
                --s;
                if ( s<0 )  return false;
            }
        }
    }
    return (s==0);
}
// -------------------------


void
rgs_to_paren_bit_string(const ulong *rgs, ulong n, ulong *str, bool rq=false)
// Convert restricted growth string (Catalan-RGS) to paren-bit-string.
// If rq is set then the reversed paren string is computed.
{
    if ( n==0 )  return;  // nothing to do

    for (ulong k=0; k < 2*n; ++k)  str[k] = 0;  // ')';
    for (ulong k=0,j=0; k<n; ++k,j+=2)  str[ j - rgs[k] ] = 1 ;  // '(';

    if ( rq )  // reverse string and swap '(' and ')'
    {
        for (ulong j=0, k=2*n-1; j<k; ++j, --k)
        {
            ulong sj = str[j],  sk = str[k];
//            str[j] = ( sk == '(' ? ')' : '(' );
            str[j] = 1 - sk;
//            str[k] = ( sj == '(' ? ')' : '(' );
            str[k] = 1 - sj;
        }
    }
}
// -------------------------


bool
paren_bit_string_to_rgs(const ulong *str, ulong n, ulong *rgs, bool rq/*=false*/)
// Convert paren-string given as array of zeros and ones to RGS str[0,1,...,n-1].
// Ones for '(', zeros for ')'.
// Return whether parenthesis string is valid.
// rgs[j] = number of unclosed open parenthesis when
//  the j-th opening is found (j>=0).
// If rq is set then the RGS for the reversed paren string is computed.
{
    if ( str[0] == 0 )  return true;  // nothing to do

    long s = 0;  // running sum
    ulong jr = 0; // position in RGS

    if ( !rq )
    {
        for (ulong js=0; js<n; ++js)
        {
            if ( str[js] == 1 )  // '('
            {
                rgs[jr] = (ulong)s;
                ++jr;
                ++s;
            }
            else
            {
                --s;
                if ( s<0 )  return false;
            }
        }
    }
    else
    {
        ulong js = n;

        while ( js-- )
        {
            if ( str[js] == 0 )  // ')'
            {
                rgs[jr] = (ulong)s;
                ++jr;
                ++s;
            }
            else
            {
                --s;
                if ( s<0 )  return false;
            }
        }
    }

    return (s==0);
}
// -------------------------


bool
is_paren_string(const char *str)
// Return whether parenthesis string is valid.
{
    long s = 0;  // running sum
    for (ulong js=0; str[js]!=0; ++js)
    {
        if ( str[js] == '(' )
        {
            ++s;
        }
        else
        {
            --s;
            if ( s<0 )  return false;
        }
    }
    return (s==0);
}
// -------------------------


bool
is_paren_bit_string(const ulong *str, ulong n)
// Test whether paren-string str[0,1,...,2*n-1]
// given as array of zeros and ones is valid.
{
    long s = 0;  // running sum
    for (ulong js=0; js<2*n; ++js)
    {
        if ( str[js] == 1 )
        {
            ++s;
        }
        else
        {
            --s;
            if ( s<0 )  return false;
        }
    }
    return (s==0);
}
// -------------------------


bool
is_catalan_rgs(const ulong *rgs, ulong n)
// Return whether rgs[] is a valid Catalan RGS.
{
    if ( n==0 )  return true;  // nothing to check

    if ( rgs[0] != 0 )  return false;

    for (ulong j=1; j<n; ++j)
        if ( rgs[j] > rgs[j-1] + 1 )  return false;

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

//bool
//is_rev_catalan_rgs(const ulong *rgs, ulong n)
//// Return whether reversed rgs[] is a valid Catalan RGS.
//{
//    if ( n==0 )  return true;  // nothing to check
//
//    if ( rgs[n-1] != 0 )  return false;
//
//    for (ulong j=n-1; j!=0; --j)
//        if ( rgs[j-1] > rgs[j] + 1 )  return false;
//
//    return true;
//}
//// -------------------------
