#include "rwlock.h"
#include <string.h>

struct read_write_lock rwlock;
int shared_data = 0;

#define MAX_LOG 100
#define NUM_WRITERS 20
#define NUM_READERS 10

char log_type[MAX_LOG];
int log_id[MAX_LOG];
int log_count = 0;
pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;

void record(char type, int id) {
    pthread_mutex_lock(&log_lock);
    if (log_count < MAX_LOG) {
        log_type[log_count] = type;
        log_id[log_count] = id;
        log_count++;
    }
    pthread_mutex_unlock(&log_lock);
}

void* reader_func(void* arg) {
    int id = *(int*)arg;
    ReaderLock(&rwlock);
    record('R', id);
    printf("Reader %d acquired lock\n", id);
    usleep(50000);
    ReaderUnlock(&rwlock);
    return NULL;
}

void* writer_func(void* arg) {
    int id = *(int*)arg;
    WriterLock(&rwlock);
    record('W', id);
    printf("Writer %d acquired lock\n", id);
    usleep(50000);
    WriterUnlock(&rwlock);
    return NULL;
}

int main() {
    InitalizeReadWriteLock(&rwlock);

    pthread_t w_threads[NUM_WRITERS];
    pthread_t r_threads[NUM_READERS];
    int w_ids[NUM_WRITERS];
    int r_ids[NUM_READERS];

    // Step 1: Writer 0 holds lock
    printf("=== Writer 0 holds lock, others queue up ===\n");
    WriterLock(&rwlock);
    printf("Writer 0 acquired lock\n");
    record('W', 0);

    // Step 2: Spawn 20 writers (all block)
    for (int i = 0; i < NUM_WRITERS; i++) {
        w_ids[i] = i + 1;
        pthread_create(&w_threads[i], NULL, writer_func, &w_ids[i]);
    }
    usleep(100000);

    // Step 3: Spawn 10 readers (all block)
    for (int i = 0; i < NUM_READERS; i++) {
        r_ids[i] = i + 1;
        pthread_create(&r_threads[i], NULL, reader_func, &r_ids[i]);
    }
    usleep(100000);

    // Step 4: Release
    printf("\n=== Writer 0 releasing lock ===\n");
    WriterUnlock(&rwlock);

    for (int i = 0; i < NUM_WRITERS; i++) pthread_join(w_threads[i], NULL);
    for (int i = 0; i < NUM_READERS; i++) pthread_join(r_threads[i], NULL);

    // Step 5: Check log
    printf("\n=== Acquisition order ===\n");
    int first_writer_after_release = -1;
    int readers_before_writer = 0;

    for (int i = 1; i < log_count; i++) {
        printf("%c%d ", log_type[i], log_id[i]);
        if (log_type[i] == 'W' && first_writer_after_release == -1)
            first_writer_after_release = i;
        if (first_writer_after_release == -1 && log_type[i] == 'R')
            readers_before_writer++;
    }

    printf("\n\nReaders before any writer: %d / %d\n", readers_before_writer, NUM_READERS);
    if (readers_before_writer == NUM_READERS)
        printf("PASS: Reader preference verified!\n");
    else
        printf("FAIL: Writers got in before all readers.\n");

    return 0;
}