#include <vslc.h>

static void node_print ( node_t *root, int nesting );
static void node_finalize ( node_t *discard );
static void destroy_subtree ( node_t *discard );


typedef struct stem_t *stem;
struct stem_t { const char *str; stem next; };
static void
tree_print(node_t* root, stem head) 
{
    static const char *sdown = "  │", *slast = "  └", *snone = "   ";
	struct stem_t col = {0, 0}, *tail;

    for (tail = head; tail; tail = tail->next) {
        if (!tail->next) {
            if (!strcmp(sdown, tail->str))
                printf("  ├");
            else 
                printf("%s", tail->str);
            break;
        }
        printf("%s", tail->str);
	}
    
    printf("──%s", node_string[root->type] );
    if ( root->type == IDENTIFIER_DATA ||
         root->type == STRING_DATA ||
         root->type == EXPRESSION ) 
        printf("(%s)", (char *) root->data);
    else if (root->type == NUMBER_DATA)
        printf ( "(%ld)", *((int64_t *)root->data) );
    putchar ( '\n' );
 
	if (!root->n_children) return;
 
	if (tail && tail->str == slast)
		tail->str = snone;
 
	if (!tail)	tail = head = &col;
	else		tail->next = &col;

    for ( int64_t i=0; i < root->n_children; i++ ) {
        col.str = root->n_children - i - 1 ? sdown : slast;
        tree_print(root->children[i], head);
    }
	tail->next = 0;
}


/* External interface */
void
destroy_syntax_tree ( void )
{
    destroy_subtree ( root );
}


void
print_syntax_tree ( void )
{
    //node_print ( root, 0 );
    tree_print(root, 0);
}


// Changed so it returns the pointer to the new node, can be used as before, but makes the parser file cleaner
node_t*
node_init (node_t *nd, node_index_t type, void *data, uint64_t n_children, ...)
{
    // Copy the type
    nd->type = type;
    // Copy n_children
    nd->n_children = n_children;

    /* 
    The memory for this data needs to be 
    allocated somewhere not here, since this 
    function does not know the type.
    */
    nd->data = data;

    // Prepeare the VA list
    va_list list_children;
    va_start(list_children, n_children);

    // Create memory region for the children pointers
    nd->children = malloc(n_children * sizeof(node_t*));

    // Populate the memory with pointers to children
    for (int i = 0; i < n_children; i++)
        nd->children[i] = va_arg(list_children, node_t*);

    return nd;
}


static void
node_print ( node_t *root, int nesting )
{
    if ( root != NULL )
    {
        printf ( "%*c%s", nesting, ' ', node_string[root->type] );
        if ( root->type == IDENTIFIER_DATA ||
             root->type == STRING_DATA ||
             root->type == EXPRESSION ) 
            printf ( "(%s)", (char *) root->data );
        else if ( root->type == NUMBER_DATA )
            printf ( "(%ld)", *((int64_t *)root->data) );
        putchar ( '\n' );
        for ( int64_t i=0; i<root->n_children; i++ )
            node_print ( root->children[i], nesting+1 );
    }
    else
        printf ( "%*c%p\n", nesting, ' ', root );
}


static void
node_finalize ( node_t *discard )
{   // The discard should have zero children here. If not -> MEMORY LEAK
    // Free the data and the children list.
    free(discard->data);
    free(discard->children);
    free(discard);
}


static void
destroy_subtree ( node_t *discard )
{
    // Don't do anything if discard is nullptr
    if (discard == NULL)
        return;

    // This will not run if n_children is zero
    // If non-zero, destroy all children recursivly
    while (discard->n_children--)
        destroy_subtree(discard->children[discard->n_children]);
    
    // Finally, destroy yourself
    node_finalize(discard);
}
