
#include "comb/stringsubst.h"

#include "fxtiomanip.h"
//#include "jjassert.h"
#include "fxttypes.h"  // ulong
#include "demo/nextarg.h" // NXARG()

//% String substitution engine.


void
usage(const char *argv0)
{
    cout << "Usage:" << endl;
    cout << "  " << argv0 << " maxdepth starts symbol0 rule0 symbol1 rule1 ... " << endl;
    cout << "For each symbol a rule must be supplied. " << endl;
    cout << "At least two symbol/rule pairs are needed. " << endl;
    cout << "Example 1:  (rabbit sequence)" << endl;
    cout << "  " << argv0 << "  9   0   0 1      1 10 " << endl;
    cout << "Example 2:  (Thue sequence)" << endl;
    cout << "  " << argv0 << "  4   0   0 111   1 110 " << endl;
}
// -------------------------

int
run_substitutions(ulong maxn, const char *start, ulong nsym, char * const *args)
{
    ulong cmax = 10000;
    string_subst S(cmax, nsym, args);

#if 0 // print command line format
    cout << "cmd:   " << maxn << "  \"" << start <<"\"";
    for (ulong j=0; j<nsym; ++j)
    {
        cout << "  \"" << S.symbol_[j] << "\" \"" << S.symrule_[j] << "\"";
    }
    cout << endl;
#endif

    S.print_rules(start);

    cout << "-------------" << endl;
    if ( 0!=S.verify(start) )  return 1;

    for (ulong j=0; j<=maxn; ++j)
    {
        ulong ctc = S.subst(j, start);

        cout << j << ": ";
        cout << "  (#=" << ctc << ")" << endl;
        cout << "  " << S.string();
        cout << endl;
    }
    return  0;
}
// -------------------------

// rabbit:  ./bin  9   0  0 1  1 10
// Pell:    ./bin  6   0  0 1  1 110
// Thue:    ./bin  4   0  0 111  1 110

// Thue-Morse:  ./bin  6   0  0 01  1 10
// related (with sign):
//  ./bin  6   0  0 L1  1 10 L L0
// using other symbols:
//  ./bin  6   0  0 -+  + +0  - -0

// oscillating machines:
// osc2: ./bin  10  0  0 1  1 01
// osc2: ./bin  10  .  . A  A B.  B A.
// osc3: ./bin  10  .  . A  A B.  B .A


// Gosper curve:
//  ./bin  3 XF  F F   X X+YF++YF-FX--FXFX-YF+   Y -FX+YFYF++YF+FX--FX-Y   + +   - -

int
main(int argc, char *argv[])
{
    ulong maxn = 7;
    NXARG(maxn, "Max depth");

    char *start;
    NXARGSTR(start, "Start symbol(s)", "A");

    RESTARGS("Rules:  sym1 rep1  sym2 rep2  [... symN repN]");
    cout << "Example: " << argv[0] << " 7 A  A x  x xA" << endl;


    int ret;
    if ( argc > 1 )
    {
        int rem = argc - 3;
        // need at least two rules (4 more args):
        if ( rem < 4 )  { usage( argv[0] ); return 1; }
        // need an even number of args:
        if ( 0!=(rem%2) )  { usage( argv[0] ); return 1; }

        ulong nsym = rem / 2;
        ret = run_substitutions( maxn, start, nsym, argv+3 );
    }
    else // defaults:
    {
        cout << "\n------------- rabbit sequence: -------------" << endl;
        const char * const rabbit_rules[] = { "0", "1",
                                              "1", "10" };
        ret = run_substitutions( 7, "0", 2, (char* const*)rabbit_rules );  // jjcast

        cout << "\n------------- modified rabbit sequence: -------------" << endl;
        const char * const fibonacci_rules[] = { ".", "A",
                                    "A", "B.",
                                    "B", "B." };
        ret = run_substitutions( 10, ".", 3, (char* const*)fibonacci_rules );

        cout << "\n------------- Thue-Morse sequence: -------------" << endl;
        const char * const thue_morse_rules[] = { "0", "01",
                                                  "1", "10" };
        ret = run_substitutions( 6, "0", 2, (char* const*)thue_morse_rules );

        cout << "\n------------- Power series of prod(n>=1, 1+x^(2^n-1)): -------------" << endl;
        const char * const prod_rules[] = { "0", "0",
                                              "1", "110",
                                              "A", "A" };
        ret = run_substitutions( 5, "1A", 3, (char* const*)prod_rules );

        cout << "\n------------- Dragon curve: -------------" << endl;
        const char * const dragon_rules[] = { "F", "F+G+",
                                              "G", "-F-G",
                                              "+", "+",
                                              "-", "-",};
        ret = run_substitutions( 6, "F", 4, (char* const*)dragon_rules );

        cout << "\n------------- tree (20deg turns): -------------" << endl;
        const char * const tree_rules[] = { "L", "R[+L]R[-L]+L",
                                            "R", "RR",
                                            "+", "+",
                                            "-", "-",
                                            "[", "[", // push position/direction
                                            "]", "]" };  // pop position/direction
        ret = run_substitutions( 3, "L", 6, (char* const*)tree_rules );

        cout << "\n------------- Hilbert curve (90deg turns): -------------" << endl;
        const char * const hilbert_rules[] = { "a", "-bF+aFa+Fb-",
                                               "b", "+aF-bFb-Fa+",
                                               "+", "+",
                                               "-", "-",
                                               "F", "F" };
        ret = run_substitutions( 4, "a", 5, (char* const*)hilbert_rules );

        cout << "\n------------- Hilbert curve (moves): -------------" << endl;
        const char * const hilbertm_rules[] = { "A", "D>A^A<C",
                                                "B", "C<BvB>D",
                                                "C", "BvC<C^A",
                                                "D", "A^D>DvB",
                                                ">", ">",
                                                "<", "<",
                                                "^", "^",
                                                "v", "v"};
        ret = run_substitutions( 3, "A", 8, (char* const*)hilbertm_rules );

//           "X",   "Y ^ X > X v y",  // ( ^ * v )
//           "x",   "y v x < x ^ Y",  // ( v * ^ )
//           "Y",   "X > Y ^ Y < x",  // ( > * < )
//           "y",   "x < y v y > X",  // ( < * > )
//        cout << "\n------------- Hilbert 3D curve (moves, TEST): -------------" << endl;
//        const char * const hilbertx_rules[] = {
//            "X",   "Y^Z+yvX>X^Y-zvy",  // ( ^ * v )
////            "x",   "yvz-Y^x<xvy+Z^Y",  // ( v * ^ )
//            "Y",   "Z+X>z-Y^Y+Z<x-z",  // ( + * - )
////            "y",   "z-x<Z+yvy-z>X+Z",  // ( - * + )
////            "Z",   "X>Y^x<Z+Z>Xvy<x",  // (  *  )
//            "Z",   "Y^X>yvZ+Z^Y<xvy",  // ( ^ * v )
////            "z",   "x<yvX>z-z<x^Y>X",
////            "z",   "yvx<Y^z-zvy>X^Y",  // ( v * ^ )
//
//            ">", ">",
//            "<", "<",
//            "^", "^",
//            "v", "v",
//            "+", "+",
//            "-", "-" };
//        ret = run_substitutions( 3, "X", 12, (char* const*)hilbertx_rules );


//        cout << "\n------------- Hilbert curve (moves): -------------" << endl;
//        const char * const hilbertm2_rules[] = {"A", "A^D>DvB>D>A^A<C^D>A^A<C<BvC<C^A",
//                                   "B", "BvC<C^A<C<BvB>DvC<BvB>D>A^D>DvB",
//                                   "C", "C<BvB>DvBvC<C^A<BvC<C^A^D>A^A<C",
//                                   "D", "D>A^A<C^A^D>DvB>A^D>DvBvC<BvB>D",
//                                   ">", ">",
//                                   "<", "<",
//                                   "^", "^",
//                                   "v", "v"};
//        ret = run_substitutions( 2, "A", 8, (char* const*)hilbertm2_rules );

//        cout << "\n------------- 3D Hilbert curve (90deg turns): -------------" << endl;
//        const char * const hilbert3d_rules[] = { "a", "^<aF^<aFa-F^>>aFavF+>>aFa-F>a->",
//                                    "F", "F"
//                                    "<", "<",
//                                    ">", ">",
//                                    "^", "^",
//                                    "v", "v",
//                                    "+", "+",
//                                    "-", "-" };
//        ret = run_substitutions( 3, "a", 8, (char* const*)hilbert3d_rules );

    }

    return ret;
}
// -------------------------

/// Emacs:
/// Local Variables:
/// MyRelDir: "demo/ds"
/// makefile-dir: "../../"
/// make-target: "1demo DSRC=demo/ds/stringsubst-demo.cc"
/// make-target2: "1demo DSRC=demo/ds/stringsubst-demo.cc DEMOFLAGS=-DTIMING"
/// End:

