#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

#include "fcs_cl.h"

struct freecell_solver_display_information_context_struct
{
    int debug_iter_state_output;
    int freecells_num;
    int stacks_num;
    int decks_num;
    int parseable_output;
    int canonized_order_output;
    int display_10_as_t;
    int display_parent_iter_num;
    int debug_iter_output_on;
    int display_moves;
    int display_states;
    int standard_notation;
};

typedef struct freecell_solver_display_information_context_struct freecell_solver_display_information_context_t;

static void init_debug_context(
    freecell_solver_display_information_context_t * dc
    )
{
    dc->parseable_output = 0;
    dc->canonized_order_output = 0;
    dc->display_10_as_t = 0;
    dc->display_parent_iter_num = 0;
    dc->display_moves = 0;
    dc->display_states = 1;
    dc->standard_notation = 0;
}



static void my_iter_handler(
    void * user_instance,
    int iter_num,
    int depth,
    void * ptr_state,
    int parent_iter_num,
    void * lp_context
    )
{
    freecell_solver_display_information_context_t * context;
    context = (freecell_solver_display_information_context_t*)lp_context;

    fprintf(stdout, "Iteration: %i\n", iter_num);
    fprintf(stdout, "Depth: %i\n", depth);
    fprintf(stdout, "Stored-States: %i\n",
        freecell_solver_user_get_num_states_in_collection(user_instance)
        );
    if (context->display_parent_iter_num)
    {
        fprintf(stdout, "Parent Iteration: %i\n", parent_iter_num);
    }
    fprintf(stdout, "\n");


    if (context->debug_iter_state_output)
    {
        char * state_string =
            freecell_solver_user_iter_state_as_string(
                user_instance,
                ptr_state,
                context->parseable_output,
                context->canonized_order_output,
                context->display_10_as_t
                );
        printf("%s\n---------------\n\n\n", state_string);
        free((void*)state_string);
    }

#ifdef MYDEBUG
    {
        fcs_card_t card;
        int ret;
        char card_str[10];

        ret = fcs_check_state_validity(
            ptr_state_with_locations,
            context->freecells_num,
            context->stacks_num,
            context->decks_num,
            &card
            );

        if (ret != 0)
        {

            fcs_card_perl2user(card, card_str, context->display_10_as_t);
            if (ret == 3)
            {
                fprintf(stdout, "%s\n",
                    "There's an empty slot in one of the stacks."
                    );
            }
            else
            {
                fprintf(stdout, "%s%s.\n",
                    ((ret == 2)? "There's an extra card: " : "There's a missing card: "),
                    card_str
                );
            }
            exit(-1);
        }
    }
#endif
}

struct help_screen_struct
{
    char * key;
    char * screen;
};

typedef struct help_screen_struct help_screen_t;

help_screen_t help_screens[] = {
{
    "configs",
"These configurations are usually faster than the unmodified run:\n"
"\n"
"    fc-solve -l cool-jives\n"
"    fc-solve -l john-galt-line\n"
"\n"
"Or if you want an accurate verdict:\n"
"\n"
"    fc-solve -l fools-gold\n"
"\n"
"If you want to try constructing your own configurations refer to the\n"
"USAGE file in the Freecell Solver distribution\n"
},
{
    "options", 
"fc-solve [options] board_file\n"
"\n"
"If board_file is - or unspecified reads standard input\n"
"\n"
"Available Options:\n"
"-h     --help\n"
"     display the default help screen\n"
"--help-summary\n"
"     display the summary help screen\n"
"-i     --iter-output\n"
"     display the iteration number and depth in every state that is checked\n"
"-s     --state-output\n"
"     also output the state in every state that is checked\n"
"-p     --parseable-output\n"
"     Output the states in a format that is friendly to perl, grep and\n"
"     friends.\n"
"-c     --canonized-order-output\n"
"     Output the stacks and freecells according to their canonic order.\n"
"     (That means that stacks and freecells won't retain their place.)\n"
"-t     --display-10-as-t\n"
"     Display the card 10 as a capital T instead of \"10\".\n"
"-m     --display-moves\n"
"     Display the moves instead of the intermediate states.\n"
"-sam   --display-states-and-moves \n"
"     Display both intermediate states and moves.\n"
"-sn    --standard-notation\n"
"     Display the moves in standard (non-verbose) notation.\n"
"     (Applicable only if -m was specified)\n"
"-snx   --standard-notation-extended\n"
"     Display the moves in extended standard notation while specifying the\n"
"     number of cards moved if applicable\n"
"-pi    --display-parent-iter \n"
"     Display the index of the parent iteration of each state in the\n"
"     run-time dump.\n"
"\n"
"--freecells-num [Freecells\' Number]\n"
"     The number of freecells present in the board.\n"
"--stacks-num [Stacks\' Number]\n"
"     The number of stacks present in the board.\n"
"--decks-num [Decks\' Number]\n"
"     The number of decks in the board.\n"
"\n"
"--sequences-are-built-by {suit|alternate_color|rank}\n"
"     Specifies the type of sequence\n"
"--sequence-move {limited|unlimited}\n"
"     Specifies whether the sequence move is limited by the number of\n"
"     freecells or vacant stacks or not.\n"
"--empty-stacks-filled-by {kings|none|all}\n"
"     Specifies which cards can fill empty stacks.\n"
"\n"
"--game [game]   --preset [game]  -g [game]\n"
"     Specifies the type of game. (Implies several of the game settings\n"
"     options above.). Available presets:\n"
"     bakers_dozen       - Baker\'s Dozen\n"
"     bakers_game        - Baker\'s Game\n"
"     beleaguered_castle - Beleaguered Castle\n"
"     citadel            - Citadel\n"
"     cruel              - Cruel\n"
"     der_katz           - Der Katzenschwanz\n"
"     die_schlange       - Die Schlange\n"
"     eight_off          - Eight Off\n"
"     fan                - Fan\n"
"     forecell           - Forecell\n"
"     freecell           - Freecell\n"
"     good_measure       - Good Measure\n"
"     ko_bakers_game     - Kings\' Only Baker\'s Game\n"
"     relaxed_freecell   - Relaxed Freecell\n"
"     relaxed_seahaven   - Relaxed Seahaven Towers\n"
"     seahaven           - Seahaven Towers\n"
"     simple_simon       - Simple Simon\n"
"     streets_and_alleys - Streets and Alleys\n"
"\n"
"-md [depth]       --max-depth [depth] \n"
"     Specify a maximal search depth for the solution process.\n"
"-mi [iter_num]    --max-iters [iter_num] \n"
"     Specify a maximal number of iterations number.\n"
"-mss [states_num] --max-stored-states [states_num] \n"
"     Specify the maximal number of states stored in memory.\n"
"\n"
"-to [tests_order]   --tests-order  [tests_order] \n"
"     Specify a test order string. Each test is represented by one character.\n"
"     Valid tests:\n"
"        Freecell Tests:\n"
"\n"
"        '0' - put top stack cards in the foundations.\n"
"        '1' - put freecell cards in the foundations.\n"
"        '2' - put freecell cards on top of stacks.\n"
"        '3' - put non-top stack cards in the foundations.\n"
"        '4' - move stack cards to different stacks.\n"
"        '5' - move stack cards to a parent card on the same stack.\n"
"        '6' - move sequences of cards onto free stacks.\n"
"        '7' - put freecell cards on empty stacks.\n"
"        '8' - move cards to a different parent.\n"
"        '9' - empty an entire stack into the freecells.\n"
"\n"
"        Atomic Freecell Tests:\n"
"\n"
"        'A' - move a stack card to an empty stack.\n"
"        'B' - move a stack card to a parent on a different stack.\n"
"        'C' - move a stack card to a freecell.\n"
"        'D' - move a freecel card to a parent.\n"
"        'E' - move a freecel card to an empty stack.\n"
"\n"
"        Simple Simon Tests:\n"
"\n"
"        'a' - move a full sequence to the foundations.\n"
"        'b' - move a sequence to a true parent of his.\n"
"        'c' - move a whole stack sequence to a false parent (in order to\n"
"              clear the stack)\n"
"        'd' - move a sequence to a true parent that has some cards above it.\n"
"        'e' - move a sequence with some cards above it to a true parent.\n"
"        'f' - move a sequence with a junk sequence above it to a true parent\n"
"              that has some cards above it.\n"
"        'g' - move a whole stack sequence to a false parent which has some\n"
"              cards above it.\n"
"        'h' - move a sequence to a parent on the same stack.\n"
"\n"
"        Tests are grouped with parenthesis or square brackets. Each group\n"
"        will be randomized as a whole by the random-dfs scan.\n"
"\n"
"\n"
"-me [solving_method]   --method [solving_method]\n"
"     Specify a solving method. Available methods are:\n"
"        \"a-star\" - A*\n"
"        \"bfs\" - Breadth-First Search\n"
"        \"dfs\" - Depth-First Search (default)\n"
"        \"random-dfs\" - A randomized DFS\n"
"        \"soft-dfs\" - \"Soft\" DFS\n"
"\n"
"-asw [A* Weights]   --a-star-weight [A* Weights]\n"
"     Specify weights for the A* scan, assuming it is used. The parameter\n"
"     should be a comma-separated list of numbers, each one is proportional\n"
"     to the weight of its corresponding test.\n"
"\n"
"     The numbers are, in order:\n"
"     1. The number of cards out.\n"
"     2. The maximal sequence move.\n"
"     3. The number of cards under sequences.\n"
"     4. The length of the sequences which are found over renegade cards.\n"
"     5. The depth of the board in the solution.\n"
"\n"
"-seed [seed_number]\n"
"     Set the seed for the random number generator used by the\n"
"     \"random-dfs\" scan.\n"
"\n"
"-nst         --next-soft-thread\n"
"     Move to the next Soft-Thread. I.e: input another scan to run in\n"
"     parallel.\n"
"-step [step iterations]     --soft-thread-step [step iterations]\n"
"     Set the number of iterations in the step of the current soft-thread.\n"
"-nht        --next-hard-thread\n"
"     Move to the next Hard-Thread. This is a new group of scans to run\n"
"     in their own system thread (assuming the executable was compiled with\n"
"     support for them.)\n"
"--st-name\n"
"     Set the name of the soft-thread.\n"
"\n"
"--prelude [prelude_string]\n"
"     Set the prelude string of the hard thread. A prelude is a static\n"
"     sequence of iterations quotas that are executed at the beginning of\n"
"     the search. The format is a list of [Limit]@[Soft-Thread Name]\n"
"     delimited by commas.\n"
"\n"
"-ni         --next-instance\n"
"     Move to the next distinct solver instance. This is a separate scan\n"
"     which would run only if the previous ones returned an unsolvable\n"
"     verdict.\n"
"\n"
"-opt         --optimize-solution\n"
"     Try and optimize the solution for a small number of moves.\n"
"-opt-to      --optimization-tests-order\n"
"     The test order of the optimization scan.\n"
"\n"
"\n"
"--reparent-states\n"
"     Reparent states that have a larger depth than that of the state\n"
"     from which they were reached a posteriori.\n"
"--calc-real-depth\n"
"     If --reparent-states is enabled, then explictly calculate the real\n"
"     depth of a state by tracing its path to the initial state\n"
"--scans-synergy {none|dead-end-marks}\n"
"     Specifies the cooperation between the scans.\n"
"\n"
"\n"
"--reset\n"
"     Reset the program to its initial, unconfigured state.\n"
"--read-from-file [{num_skip},]filename\n"
"     Reads configuration parameter with the file while skipping num_skip\n"
"     arguments from the beginning.\n"
"-l [configuration]      --load-config [configuration]\n"
"     Reads the configuration [configruration] and configures the solver\n"
"     accordingly.\n"
"\n"
"\n"
"Signals:\n"
"SIGUSR1 - Prints the number of states that were checked so far to stderr.\n"
"SIGUSR2 SIGUSR1 - Turns iteration output on/off.\n"
"SIGUSR2 SIGUSR2 SIGUSR1 - Turns iteration's state output on/off.\n"
"\n"
"\n"
"Freecell Solver was written by Shlomi Fish.\n"
"Homepage: http://vipe.technion.ac.il/~shlomif/freecell-solver/\n"
"Send comments and suggestions to shlomif@vipe.technion.ac.il\n"
},
{
    "real-help",
"The environment variable FREECELL_SOLVER_DEFAULT_HELP sets the default help\n"
"screen. The name of the help screen is the same name as its \"--help-\" flag\n"
"but without the preceding \"--help-\". Type:\n"
"\n"
"    fc-solve --help-summary\n"
"\n"
"for the available help screens.\n"
"\n"
"Refer to your system's documentation for information on how to set environment\n"
"variables.\n"
},
{
    "problems",
"To be discussed.\n"
},
{
    "short-sol",
"The following configurations may produce shorter solutions:\n"
"\n"
"    fc-solve -opt\n"
"    fc-solve --method a-star -opt\n"
"    fc-solve --reparent-states -opt\n"
"    fc-solve --method a-star --reparent-states -opt\n"
"\n"
"If \"--method a-star\" is specified you can set the weights with\n"
"-asw {comma separated list of 5 numeric weights}, which may improve\n"
"the length of the solution. (refer to the USAGE file for more information)\n"
},
{
    "summary",
"fc-solve [flags] [board_file|-]\n"
"\n"
"Reads board from standard input by default or if a \"-\" is specified.\n"
"\n"
"- If it takes too long to finish, type \"fc-solve --help-configs\"\n"
"- If it erroneously reports a board as unsolvable, try adding the\n"
"  \"-to 01ABCDE\" flag\n"
"- If the solution is too long type \"fc-solve --help-short-sol\"\n"
"- To present the moves only try adding \"-m\" or \"-m -snx\"\n"
"- For a description of all options type \"fc-solve --help-options\"\n"
"- To deal with other problems type \"fc-solve --help-problems\"\n"
"- To turn --help into something more useful, type\n"
"  \"fc-solve --help-real-help\"\n"
"\n"
"Contact Shlomi Fish, shlomif@vipe.technion.ac.il for more information.\n" 
},
{
    NULL,
    NULL
}
}
;

enum MY_FCS_CMD_LINE_RET_VALUES
{
    EXIT_AND_RETURN_0 = FCS_CMD_LINE_USER,

};

static void print_help_string(char * key)
{
    int i;
    for(i=0;help_screens[i].key != NULL ; i++)
    {
        if (!strcmp(key, help_screens[i].key))
        {
            printf("%s", help_screens[i].screen);
        }
    }
}

static int cmd_line_callback(
    void * instance,
    int argc,
    char * argv[],
    int arg,
    int * num_to_skip,
    int * ret,
    void * context
    )
{
    freecell_solver_display_information_context_t * dc;
    *num_to_skip = 0;

    dc = (freecell_solver_display_information_context_t * )context;

    if ((!strcmp(argv[arg], "-h")) || (!strcmp(argv[arg], "--help")))
    {
        char * help_key;
        
        help_key = getenv("FREECELL_SOLVER_DEFAULT_HELP");
        if (help_key == NULL)
        {
            help_key = "summary";
        }
        print_help_string(help_key);
        *ret = EXIT_AND_RETURN_0;
        return FCS_CMD_LINE_STOP;
    }
    else if (!strncmp(argv[arg], "--help-", 7))
    {
        print_help_string(argv[arg]+7);
        *ret = EXIT_AND_RETURN_0;
        return FCS_CMD_LINE_STOP;
    }
    else if ((!strcmp(argv[arg], "-i")) || (!strcmp(argv[arg], "--iter-output")))
    {
#define set_iter_handler() \
        freecell_solver_user_set_iter_handler(   \
            instance,   \
            my_iter_handler,   \
            dc    \
            );        \
        dc->debug_iter_output_on = 1;

        set_iter_handler();
    }
    else if ((!strcmp(argv[arg], "-s")) || (!strcmp(argv[arg], "--state-output")))
    {
        set_iter_handler();
        dc->debug_iter_state_output = 1;
#undef set_iter_handler
    }
    else if ((!strcmp(argv[arg], "-p")) || (!strcmp(argv[arg], "--parseable-output")))
    {
        dc->parseable_output = 1;
    }
    else if ((!strcmp(argv[arg], "-c")) || (!strcmp(argv[arg], "--canonized-order-output")))
    {
        dc->canonized_order_output = 1;
    }
    else if ((!strcmp(argv[arg], "-t")) || (!strcmp(argv[arg], "--display-10-as-t")))
    {
        dc->display_10_as_t = 1;
    }
    else if ((!strcmp(argv[arg], "-m")) || (!strcmp(argv[arg], "--display-moves")))
    {
        dc->display_moves = 1;
        dc->display_states = 0;
    }
    else if ((!strcmp(argv[arg], "-sn")) || (!strcmp(argv[arg], "--standard-notation")))
    {
        dc->standard_notation = 1;
    
    }
    else if ((!strcmp(argv[arg], "-snx")) || (!strcmp(argv[arg], "--standard-notation-extended")))
    {
        dc->standard_notation = 2;   
    }
    else if ((!strcmp(argv[arg], "-sam")) || (!strcmp(argv[arg], "--display-states-and-moves")))
    {
        dc->display_moves = 1;
        dc->display_states = 1;
    }
    else if ((!strcmp(argv[arg], "-pi")) || (!strcmp(argv[arg], "--display-parent-iter")))
    {
        dc->display_parent_iter_num = 1;
    }
    else if ((!strcmp(argv[arg], "--reset")))
    {
        init_debug_context(dc);
        freecell_solver_user_set_iter_handler(
            instance,
            NULL,
            NULL
            );                
        *num_to_skip = 0;
        return FCS_CMD_LINE_OK;
    }
    else
    {
        printf("Unimplemented option - \"%s\"!", argv[arg]);
        exit(-1);
    }
    *num_to_skip = 1;
    return FCS_CMD_LINE_SKIP;
}


static int command_num = 0;
static int debug_iter_output_on = 0;

static void select_signal_handler(int signal_num)
{
    command_num = (command_num+1)%3;
}

static void * current_instance;
static freecell_solver_display_information_context_t * dc;


static void command_signal_handler(int signal_num)
{
    if (command_num == 0)
    {
        fprintf(
            stderr,
            "The number of iterations is %i\n",
            freecell_solver_user_get_num_times(current_instance)
            );
    }
    else if (command_num == 1)
    {
        if (debug_iter_output_on)
        {
            freecell_solver_user_set_iter_handler(
                current_instance,
                NULL,
                NULL
                );
            debug_iter_output_on = 0;
        }
        else
        {
            freecell_solver_user_set_iter_handler(
                current_instance,
                my_iter_handler,
                dc
                );
            debug_iter_output_on = 1;
        }
    }
    else if (command_num == 2)
    {
        dc->debug_iter_state_output = ! dc->debug_iter_state_output;
    }

    command_num = 0;
}


static char * known_parameters[] = {
    "-h", "--help",
        "--help-configs", "--help-options", "--help-problems", 
        "--help-real-help", "--help-short-sol", "--help-summary",
    "-i", "--iter-output",
    "-s", "--state-output",
    "-p", "--parseable-output",
    "-c", "--canonized-order-output",
    "-t", "--display-10-as-t",
    "-m", "--display-moves",
    "-sn", "--standard-notation",
    "-snx", "--standard-notation-extended",
    "-sam", "--display-states-and-moves",
    "-pi", "--display-parent-iter",
    "--reset",
    NULL
    };

#define USER_STATE_SIZE 1024

int main(int argc, char * argv[])
{
    int parser_ret;
    void * instance;
    char * error_string;
    int arg;
    FILE * file;
    char user_state[USER_STATE_SIZE];
    int ret;

    freecell_solver_display_information_context_t debug_context;

    init_debug_context(&debug_context);

    dc = &debug_context;

    instance = freecell_solver_user_alloc();

    current_instance = instance;


    parser_ret =
        freecell_solver_user_cmd_line_parse_args(
            instance,
            argc,
            argv,
            1,
            known_parameters,
            cmd_line_callback,
            &debug_context,
            &error_string,
            &arg
            );

    if (parser_ret == EXIT_AND_RETURN_0)
    {
        freecell_solver_user_free(instance);
        return 0;
    }
    else if (
        (parser_ret == FCS_CMD_LINE_PARAM_WITH_NO_ARG)
            )
    {
        fprintf(stderr, "The command line parameter \"%s\" requires an argument"
                " and was not supplied with one.\n", argv[arg]);
        return (-1);
    }
    else if (        
        (parser_ret == FCS_CMD_LINE_ERROR_IN_ARG)
        )
    {
        if (error_string != NULL)
        {
            fprintf(stderr, "%s", error_string);
            free(error_string);
        }
        freecell_solver_user_free(instance);
        return -1;
    }

    if ((arg == argc) || (!strcmp(argv[arg], "-")))
    {
        file = stdin;
        if (!getenv("FREECELL_SOLVER_QUIET"))
        {
            fprintf(stderr, "%s", 
                    "Reading the board from the standard input.\n"
                    "Type \"fc-solve --help\" for more usage information.\n"
                    "To cancel this message set the FREECELL_SOLVER_QUIET environment variable.\n"
                   );
        }
    }
    else if (argv[arg][0] == '-')
    {
        fprintf(stderr,
                "Unknown option \"%s\". "
                "Type \"%s --help\" for usage information.\n",
                argv[arg],
                argv[0]
                );
        freecell_solver_user_free(instance);

        return -1;
    }
    else
    {
        file = fopen(argv[arg], "r");
        if (file == NULL)
        {
            fprintf(stderr,
                "Could not open file \"%s\" for input. Exiting.\n",
                argv[arg]
                );
            freecell_solver_user_free(instance);

            return -1;
        }
    }
    memset(user_state, '\0', sizeof(user_state));
    fread(user_state, sizeof(user_state[0]), USER_STATE_SIZE-1, file);
    fclose(file);

    /* Win32 Does not have those signals */
#ifndef WIN32
    signal(SIGUSR1, command_signal_handler);
    signal(SIGUSR2, select_signal_handler);
#endif

#if 0
    {
        int limit = 500;
        freecell_solver_user_limit_iterations(instance, limit);
        ret = freecell_solver_user_solve_board(instance, user_state);
        while (ret == FCS_STATE_SUSPEND_PROCESS)
        {
            limit += 500;
            freecell_solver_user_limit_iterations(instance, limit);
            ret = freecell_solver_user_resume_solution(instance);
        }
    }
#else
    ret = freecell_solver_user_solve_board(instance, user_state);
#endif

    if (ret == FCS_STATE_INVALID_STATE)
    {
        char * error_string;
        error_string =
            freecell_solver_user_get_invalid_state_error_string(
                instance,
                debug_context.display_10_as_t
                );
        printf("%s\n", error_string);
        free(error_string);
    }
    else
    {
        if (ret == FCS_STATE_WAS_SOLVED)
        {
            printf("-=-=-=-=-=-=-=-=-=-=-=-\n\n");
            {
                fcs_move_t move;
                FILE * move_dump;
                char * as_string;
                int move_num = 0;

                move_dump = stdout;


                if (debug_context.display_states)
                {
                    as_string =
                        freecell_solver_user_current_state_as_string(
                            instance,
                            debug_context.parseable_output,
                            debug_context.canonized_order_output,
                            debug_context.display_10_as_t
                            );

                    fprintf(move_dump, "%s\n", as_string);

                    free(as_string);

                    fprintf(move_dump, "%s", "\n====================\n\n");
                }

                while (
                        freecell_solver_user_get_next_move(
                            instance,
                            &move
                            ) == 0
                        )
                {
                    if (debug_context.display_moves)
                    {
                        as_string =
                            freecell_solver_user_move_to_string_w_state(
                                instance,
                                move,
                                debug_context.standard_notation
                                );

                        if (debug_context.display_states && debug_context.standard_notation)
                        {
                            fprintf(move_dump, "Move: ");
                        }

                        fprintf(
                            move_dump,
                            (debug_context.standard_notation ?
                                "%s " :
                                "%s\n"
                            ),
                            as_string
                            );
                        move_num++;
                        if (debug_context.standard_notation)
                        {
                            if ((move_num % 10 == 0) || debug_context.display_states)
                            {
                                fprintf(move_dump, "\n");
                            }
                        }
                        if (debug_context.display_states)
                        {
                            fprintf(move_dump, "\n");
                        }
                        fflush(move_dump);
                        free(as_string);
                    }

                    if (debug_context.display_states)
                    {
                        as_string =
                            freecell_solver_user_current_state_as_string(
                                instance,
                                debug_context.parseable_output,
                                debug_context.canonized_order_output,
                                debug_context.display_10_as_t
                                );

                        fprintf(move_dump, "%s\n", as_string);

                        free(as_string);
                    }

                    if (debug_context.display_states || (!debug_context.standard_notation))
                    {
                        fprintf(move_dump, "%s", "\n====================\n\n");
                    }
                }

                if (debug_context.standard_notation && (!debug_context.display_states))
                {
                    fprintf(move_dump, "\n\n");
                }
            }

            printf("This game is solveable.\n");
        }
        else
        {
            printf ("I could not solve this game.\n");
        }

        printf(
            "Total number of states checked is %i.\n",
            freecell_solver_user_get_num_times(instance)
            );
#if 1
        printf(
            "This scan generated %i states.\n",
            freecell_solver_user_get_num_states_in_collection(instance)
            );
#endif
    }

    freecell_solver_user_free(instance);

    return 0;
}