#include <arpa/inet.h> /* For htonl() */

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "bhash.h"

void bhash_init(bhash_t *bh, const void *data, size_t data_len)
{
    memset(bh, 0, sizeof(*bh));

    bh->bh_data = malloc(data_len);
    memcpy(bh->bh_data, data, data_len);
    bh->bh_len = data_len;

    bh->bh_bits_avail = data_len * 8.0;
}

void bhash_fini(bhash_t *bh)
{
    free(bh->bh_data);
}

uint32_t bhash_mod32(bhash_t *bh, uint32_t mod)
{
    uint32_t *pi;
    uint32_t *pend;
    uint64_t n;

    uint32_t rv = 0;

    if ((bh->bh_len % sizeof(uint32_t)) != 0)
    {
        return BHASH_MOD32_ERR;
    }

    pend = (uint32_t *)(bh->bh_data + bh->bh_len);

    for (pi = (uint32_t *)bh->bh_data; pi < pend; pi++)
    {
        n = (uint64_t)rv << (sizeof(uint32_t) * 8);
        n |= htonl(*pi);

        *pi = ntohl(n / mod);
        rv = n % mod;
    }

    bh->bh_bits_used += log(mod) / log(2);
    if (bh->bh_bits_used > bh->bh_bits_avail)
    {
        return BHASH_MOD32_ERR;
    }

    return rv;
}

double bhash_bits_avail(bhash_t *bh)
{
    return bh->bh_bits_avail;
}
double bhash_bits_used(bhash_t *bh)
{
    return bh->bh_bits_used;
}

