/************************************************************
 * This file is needed if the DEBUGGING macro is defined.
 * It supplies convenience functions for debugging the program
 * or examining its workings.
 ************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include "re.h"

#ifdef DEBUG

static char *types[] = {" OR", "AND", "~OR"};

// print out a node in a standard format
void dbNode(struct node *node, VD_INT4 recurse) {
    char range[100];
    char quote;
    char *not = NULL;
	VD_INT4 which;

    if (node) {
        if ((node->min != 1) || (node->max != 1)) {
            sprintf(range, "[%d - %u] ", node->min, node->max);
        }
        else {
            range[0] = 0;
        }
		which= 0;
        quote = (node->type & N_QUOTE) ? '"' : ' ';
        switch (node->type & TYPEMASK) {
        case N_NOTOR: which++;
        case N_AND: which++;
        case N_OR:
            printf("%*s%c%s%d%s\n", recurse, "", quote, types[which], node->id, range);
            if (recurse) {
                dbNode(node->d.logic.root, recurse + 2);
            }
            break;
        case N_RANGE:
            printf("%*s%cRANGE%d%s from %c to %c\n", recurse, "", quote, node->id, range, node->d.range.low, node->d.range.high);
            break;
        case N_STRING:
            printf("%*s%cSTRING%d%s %.*s\n", recurse, "", quote, node->id, range, node->d.string.len, node->d.string.start);
            break;
        case N_MEMBER:
            printf("%*s%cMEMBER%d %s %.*s\n", recurse, "", quote, node->id, range, node->d.string.len, node->d.string.start);
            break;
        case N_SUCCESS:
            printf("%*s SUCCESS\n", recurse, "");
            break;
        case N_STATIC:
            break;
        default:
            printf("%*sUNKNOWN TYPE %d\n", recurse, node->type);
        }
        if (recurse) {
            dbNode(node->link, recurse);
        }
    }
}

// print out the entire parse tree 
void dbTree(struct node *root) {
    dbNode(root, 2);
}

// print out a state in standard format
void state(struct state *state) {
	char *action;
	if (state->nextAction & A_CHAIN) action = "CHAIN ";
	else if (state->nextAction & A_REPEAT) action = "REPEAT";
	else action = "FAIL  ";
    printf("%3d%4d %s %10.10s: ", state->count, state->parent, action, state->ptr);    
    dbNode(state->node, 0);
}
    
// print out a state frame in a standard format
void dbState(struct stateStack *stack, VD_INT4 depth) {
    if (depth < 0) {
        depth = VDI_topFrame(stack);
    }
    printf("%3d:", depth);
    state(VDI_getState(stack, depth));
}

// print out the entire execution stack
void dbStack(struct stateStack *stack) {
    VD_INT4 i;
    printf("Stack depth = %d, allocated = %d\n", stack->ptr, stack->allocated);

    for (i = 0; i < stack->ptr; i++) {
        dbState(stack, i);
    }
    printf("\n");
}
 
// print out the results structure
void dbResults(struct VD_RE_Result *result, VD_INT4 depth) {
    printf("%*s'%.*s'\n", depth, "", result->len, result->start);
    if (result->contains) {
        dbResults(result->contains, depth + 2);
    }
    if (result->chain) {
        dbResults(result->chain, depth);
    }
}
void dbSummary(struct stateStack *stack) {
    printf("Final stack size %d, maximum stack size %d, allocated stack %d\n", stack->ptr, stack->maxSize, stack->allocated);
    printf("Iterations: %d; Total frames pushed: %d; total times backtracked: %d\n", stack->iterations, stack->pushed, stack->failed);
}

static VD_INT4 counters[] = {0, 0, 0, 0, 0, 0};
// give a unique ID number for each node of a given type
void nextID(VD_INT4 *p, VD_INT4 type) {
    switch(type & TYPEMASK) {
    case N_AND: *p = counters[0]++; break;
    case N_OR: *p = counters[1]++; break;
    case N_STRING: *p = counters[2]++; break;
    case N_MEMBER: *p = counters[3]++; break;
    case N_RANGE: *p = counters[4]++; break;
    case N_NOTOR: *p = counters[5]++; break;
    case N_SUCCESS: break;
    default: printf("unexpected type value of 0X%x in NEXTID\n", type);
    }
}
#endif

