#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "aocutils.h"

bool TGvalid(struct TextGrid *tg, unsigned row, unsigned col) {
    if (row >= tg->rows) return false;
    if (col >= tg->cols) return false;
    return true;
}
char *TGcharptr(struct TextGrid *tg, unsigned row, unsigned col) {
    if (!TGvalid(tg, row, col)) return NULL;
    return tg->data + (row * tg->cols) + col;
}

// TODO: rewrite this shit
size_t linearize2d(unsigned width, unsigned row, unsigned col) {
    return (row * width) + col;
}

size_t text2array(unsigned **dst, const char *r) {
    unsigned *a = malloc(512 * sizeof *a);
    size_t na = 0, sa = 512;
    char *err;
    unsigned v;
    for (;;) {
        if (na == sa) {
            // grow the array (by golden ratio)
            unsigned *tmp = realloc(a, ((13*sa) / 8) * sizeof *tmp);
            if (!tmp) exit(EXIT_FAILURE);
            a = tmp;
            sa = (13*sa) / 8;
        }
        v = strtoul(r, &err, 10);
        a[na++] = v;
        if (!*err) break;
        r = err;
    }
    *dst = a;
    return na;
}

size_t slurp(char **dst, const char *fn) {
    if (*dst) {
        fprintf(stderr, "slurp() must be called with a pointer to void!\n");
        exit(EXIT_FAILURE);
    }
    FILE *h = fopen(fn, "r");
    if (!h) {
        perror(fn);
        exit(EXIT_FAILURE);
    }

    int ch;
    char *tmp = malloc(512);
    size_t s = 512;
    size_t r = 0;
    while ((ch = fgetc(h)) != EOF) {
        if (r+1 == s) {
            // grow the array (by golden ratio)
            char *ttmp = realloc(tmp, (13*s) / 8);
            if (ttmp) {
                tmp = ttmp;
                s = (13*s) / 8;
            } else {
                free(tmp);
                return 0;
            }
        }
        tmp[r++] = ch;
    }
    fclose(h);
    tmp[r] = 0;
    *dst = tmp;

    return r;
}

unsigned distance(unsigned a, unsigned b) {
    if (a > b) return a - b;
    return b - a;
}

unsigned max3u(unsigned a, unsigned b, unsigned c) {
    if (a > b) {
        if (a > c) return a;
        return c;
    } else {
        if (b > c) return b;
    }
    return c;
}

unsigned min3u(unsigned a, unsigned b, unsigned c) {
    if (a < b) {
        if (a < c) return a;
        return c;
    } else {
        if (b < c) return b;
    }
    return c;
}
