/* Educational C11 model, NOT Aether's runtime. No network or display control.
 * Node.value borrows string literals; only heap-allocated nodes are freed.
 * Stack/Queue take ownership of nodes they allocate. No shared node ownership.
 */
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node {
    const char *value;
    struct Node *next;
} Node;

typedef struct Queue { Node *front; Node *rear; } Queue;

static Node *node_new(const char *value) {
    Node *node = malloc(sizeof *node);
    if (!node) return NULL;
    node->value = value;
    node->next = NULL;
    return node;
}

static bool insert_after(Node *prev, const char *value) {
    if (!prev) return false;
    Node *fresh = node_new(value);
    if (!fresh) return false;
    fresh->next = prev->next; /* Keep the path before replacing it. */
    prev->next = fresh;
    return true;
}

static bool remove_after(Node *prev) {
    if (!prev || !prev->next) return false;
    Node *victim = prev->next;
    prev->next = victim->next;
    free(victim); /* Requires heap ownership; never pass a static ring node here. */
    return true;
}

static bool stack_push(Node **top, const char *value) {
    Node *fresh = node_new(value);
    if (!fresh) return false;
    fresh->next = *top;
    *top = fresh;
    return true;
}

static bool stack_pop(Node **top, const char **out) {
    if (!*top) return false;
    Node *old = *top;
    *out = old->value;
    *top = old->next;
    free(old);
    return true;
}

static bool enqueue(Queue *q, const char *value) {
    Node *fresh = node_new(value);
    if (!fresh) return false;
    if (q->rear) q->rear->next = fresh;
    else q->front = fresh;
    q->rear = fresh;
    return true;
}

static bool dequeue(Queue *q, const char **out) {
    if (!q->front) return false;
    Node *old = q->front;
    *out = old->value;
    q->front = old->next;
    if (!q->front) q->rear = NULL;
    free(old);
    return true;
}

static void visit_ring(const Node *head) {
    if (!head) return;
    const Node *cursor = head;
    do {
        printf("%s ", cursor->value);
        cursor = cursor->next;
    } while (cursor != head);
    puts("");
}

int main(void) {
    /* Fixed nodes have automatic storage, not malloc ownership. */
    Node a = {"Eleven", NULL}, b = {"Maniac", NULL}, c = {"Nagini", NULL};
    a.next = &b; b.next = &c;
    Node *head = &a;
    puts("Linear traversal:");
    for (Node *cursor = head; cursor; cursor = cursor->next) puts(cursor->value);
    c.next = &a;
    puts("Circular traversal:"); visit_ring(head);
    head = head->next;
    puts("Rotated entry (same nodes, same links):"); visit_ring(head);

    /* A separate heap-owned list: insertion + removal. */
    Node *list = node_new("A");
    if (!list) return EXIT_FAILURE;
    if (!insert_after(list, "C")) { free(list); return EXIT_FAILURE; }
    if (!insert_after(list, "B")) { remove_after(list); free(list); return EXIT_FAILURE; }
    assert(strcmp(list->next->value, "B") == 0);
    assert(strcmp(list->next->next->value, "C") == 0);
    bool removed = remove_after(list);
    assert(removed && strcmp(list->next->value, "C") == 0);
    while (remove_after(list)) {}
    free(list);

    Node *top = NULL;
    Queue q = {NULL, NULL};
    const char *inputs[] = {"A", "B", "C"};
    const char *out = NULL;
    for (size_t i = 0; i < 3; ++i) {
        if (!stack_push(&top, inputs[i]) || !enqueue(&q, inputs[i])) {
            while (stack_pop(&top, &out)) {}
            while (dequeue(&q, &out)) {}
            return EXIT_FAILURE;
        }
    }
    puts("Stack LIFO:");
    for (size_t i = 0; i < 3; ++i) {
        bool ok = stack_pop(&top, &out);
        assert(ok && strcmp(out, inputs[2-i]) == 0);
        puts(out);
    }
    assert(top == NULL);
    bool empty_stack = stack_pop(&top, &out);
    assert(!empty_stack);
    puts("Queue FIFO:");
    for (size_t i = 0; i < 3; ++i) {
        bool ok = dequeue(&q, &out);
        assert(ok && strcmp(out, inputs[i]) == 0);
        puts(out);
    }
    assert(q.front == NULL && q.rear == NULL);
    bool empty_queue = dequeue(&q, &out);
    assert(!empty_queue);
    bool reinsert = enqueue(&q, "D");
    if (!reinsert) return EXIT_FAILURE;
    bool again = dequeue(&q, &out);
    assert(again && strcmp(out,"D")==0 && !q.rear);
    puts("All structural checks passed.");
    return EXIT_SUCCESS;
}
