#include <assert.h>

#ifdef __needExternC
#error Only compile observation.c (once) in plain C
#endif

#include <stdio.h>
#include <stddef.h>

#include "observation.h"

static size_t NumNodes;

void bobs_init(size_t NumNodes_) {
    // printf("at bobs_init; bobs_ops_completed = %zd\n", bobs_ops_completed);

    // todo: register a signal handler that prints progress info
    // note function bobs_XXX in driver.c are untested until that's working
    // to be driven as:
    //       ./a.out &          # then, very quickly
    //       kill -s USR2 $!

    NumNodes = NumNodes_;
}

#ifdef BOBS_SHOW_ADDRESSES
#define SNAP \
    void * userAddr = bobs_getCurrentLoc(); \
    size_t userValue = bobs_getCurrentVal();
#define SHOW(pfx, sfx) \
    printf(" " pfx "%d@%p" sfx, userValue, userAddr);
#else
#define SNAP \
    size_t userValue = bobs_getCurrentVal();
#define SHOW(pfx, sfx) \
    printf(" " pfx "%zd" sfx, userValue);
#endif

static void printPreds(size_t leash) {
    if (leash==0)
        return;
    if (!bobs_hasCurrent()) {
        printf(" |");
        return;
    }
    SNAP
    bobs_movePrev();
    printPreds(leash - 1);
    SHOW("", "")
}
static void printSuccs(size_t leash) {
    if (leash==0)
        return;
    if (!bobs_hasCurrent()) {
        printf(" |");
        return;
    }
    SNAP
    SHOW("", "")
    bobs_moveNext();
    printSuccs(leash - 1);
}
static void explore(size_t here, size_t leash) {
    bobs_seek(here);
    if (!bobs_hasCurrent()) {
        printf(" <X>");
        return;
    }
    bobs_movePrev();
    printPreds(leash);

    bobs_seek(here);
    SNAP
    SHOW("<", ">")

    bobs_moveNext();
    printSuccs(leash);
}
static void exploreRange(size_t validFrom, size_t validTo) {
    size_t gapsize = validTo - validFrom;
    size_t midpoint = (validTo + validFrom) / 2;

    size_t listFirstmost, listLastmost;
    switch(bobs_op_polarity) {
        case insfirst:
            listFirstmost = validTo;
            listLastmost = validFrom;
            break;
        case inslast:
            listFirstmost = validFrom;
            listLastmost = validTo;
            break;
        default:
            assert(0 && "unsupported bobs_op_movement value");
    }

    printf(" v%zd..%zd ", listFirstmost, listLastmost);

    explore(listFirstmost, 6);
    printf(" ...");
    // if (gapsize > 5) {
    //     explore(midpoint);
    //     printf(" ...");
    // }
    explore(listLastmost, 6);
}

void bobs_report(void) {
    if (bobs_prog_rollover_flag) {
        printf("%8zd + ? (rolling over)\n", bobs_ops_completed);
    } else {
        printf("%8zd + %6zd/2 + %6zd/2, %6zd@e %6zd_u", bobs_ops_completed, bobs_prog_inserting, bobs_prog_removing, bobs_prog_removing_end, *bobs_prog_rem_pos);

        ptrdiff_t validFrom = bobs_first_valid();
        ptrdiff_t validTo = bobs_last_valid();

        printf("  ");

        if (validTo < validFrom) {
            printf(" (list is empty)");
        } else {
            exploreRange(validFrom, validTo);
        }

        printf("\n");
    }
}
