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

#include "bitmatrix.h"
#include "xutil.h"

int64_t bitmatrix_getbit(bitmatrix_t *m, uint32_t i, uint32_t j) {
	assert(i < m->m);
	assert(j < m->n);

	uint64_t *row = &m->data[i * m->rsize];
	uint32_t idx = j / BPI;

	return row[idx] & (((uint64_t)1) << (63 - j % BPI));
}

void bitmatrix_setbit(bitmatrix_t *m, uint32_t i, uint32_t j) {
	assert(i < m->m);
	assert(j < m->n);

	uint64_t *row = &m->data[(uint64_t)i * m->rsize];
	uint32_t idx = j / BPI;

	row[idx] |= (((uint64_t)1) << (63 - j % BPI));
}

void bitmatrix_clearbit(bitmatrix_t *m, uint32_t i, uint32_t j) {
	assert(i < m->m);
	assert(j < m->n);

	uint64_t *row = &m->data[i * m->rsize];
	uint32_t idx =j / BPI;

	row[idx] &= ~(((uint64_t)1 << (63 - j % BPI)));
}

void bitmatrix_identity(bitmatrix_t *m) {
	uint32_t i;

	for (i = 0; i < m->n; i++) {
		bitmatrix_setbit(m, i, i);
	}
}

bitmatrix_t *bitmatrix_create(uint32_t m, uint32_t n) {
	bitmatrix_t *matrix = xmalloc(sizeof(bitmatrix_t));

	matrix->m = m;
	matrix->n = n;

	matrix->rsize = ceil((double)(n)/BPI);
	matrix->size = m * matrix->rsize;

	matrix->data = xmalloc(matrix->size * sizeof(uint64_t));

	bitmatrix_zero(matrix);

	return matrix;
}

void bitmatrix_zero(bitmatrix_t *m) {
	memset(m->data, 0, m->size * sizeof(uint64_t));
}

void bitmatrix_print(bitmatrix_t *m) {
	uint32_t i, j, k;

	/*
	for (i = 0; i < m->m; i++) {
		for (j = 0; j < m->rsize; j++) {
			printf("%20"PRIu64, m->data[i * m->rsize + j]);
		}
		printf("\n");
	}
	*/

	for (i = 0; i < m->m; i++) {
		for (j = 0; j < m->rsize; j++) {
			for (k = 0; j * BPI + k < m->n && k < 64; k++) {
				uint64_t val = m->data[i * m->rsize + j] & (((uint64_t)1) << (63 - k));
				printf("%u ", val != 0 ? 1u : 0u);
			}
		}
		printf("\n");
	}
}

void bitmatrix_destroy(bitmatrix_t *m) {
	free(m->data);
	free(m);
}
