#include <stdlib.h>

#include "xutil.h"
#include "fw.h"
#include "naive.h"

naive_t *naive_init(uint32_t n) {
	naive_t *naive = xmalloc(sizeof(naive_t));

	naive->n = n;
	naive->T0 = matrix_create(n, n);
	naive->Tn = matrix_create(n, n);
	naive->temp = matrix_create(n, n);
	naive->tc = n;

	matrix_identity(naive->T0);

	return naive;
}

bitnaive_t *bitnaive_init(uint32_t n) {
	bitnaive_t *naive = xmalloc(sizeof(bitnaive_t));

	naive->n = n;
	naive->T0 = bitmatrix_create(n, n);
	naive->Tn = bitmatrix_create(n, n);
	naive->temp = bitmatrix_create(n, n);
	naive->tc = n;

	bitmatrix_identity(naive->T0);

	return naive;
}

void naive_destroy(naive_t *naive) {
	if (NULL != naive) {
		matrix_destroy(naive->T0);
		matrix_destroy(naive->Tn);
		matrix_destroy(naive->temp);
		free(naive);
	}
}

void bitnaive_destroy(bitnaive_t *naive) {
	if (NULL != naive) {
		bitmatrix_destroy(naive->T0);
		bitmatrix_destroy(naive->Tn);
		bitmatrix_destroy(naive->temp);
		free(naive);
	}
}


void naive_insert(naive_t *naive, uint32_t i, uint32_t j) {
	// We do not allow changes on the diagonal
	if (i == j || MAT(naive->T0, i, j) != 0) {
		return;
	}
	MAT(naive->T0, i, j) = 1;
	fw_transitive_closure(naive);
}

void bitnaive_insert(bitnaive_t *naive, uint32_t i, uint32_t j) {
	// We do not allow changes on the diagonal

	bitmatrix_setbit(naive->T0, i, j);
	fw_transitive_closure_bit(naive);
}


void naive_delete(naive_t *naive, uint32_t i, uint32_t j) {
	// We do not allow changes on the diagonal
	//
	MAT(naive->T0, i, j) = 0;
	fw_transitive_closure(naive);
}

void bitnaive_delete(bitnaive_t *naive, uint32_t i, uint32_t j) {
	// We do not allow changes on the diagonal

	bitmatrix_clearbit(naive->T0, i, j);
	fw_transitive_closure_bit(naive);
}


uint32_t naive_query(naive_t *naive) {
	return naive->tc - naive->n;
}

uint32_t bitnaive_query(bitnaive_t *naive) {
	return naive->tc - naive->n;
}




void naive_expand(naive_t *naive) {
	uint32_t n = naive->n;

	matrix_expand(naive->T0);
	matrix_expand(naive->Tn);
	naive->T0->data[n*(n+1) + n] = 1;
	naive->Tn->data[n*(n+1) + n] = 1;

	naive->temp->data = realloc(naive->temp->data, (n+1)*(n+1) * sizeof(int64_t));
	naive->temp->m += 1;
	naive->temp->n += 1;

	naive->n += 1;
}

void naive_remove(naive_t *naive, uint32_t i) {
	uint32_t n = naive->n;

	matrix_remove(naive->T0, i);
	matrix_remove(naive->Tn, i);

	naive->temp->data = realloc(naive->temp->data, (n-1)*(n-1) * sizeof(int64_t));
	naive->temp->m -= 1;
	naive->temp->n -= 1;

	naive->n -= 1;
}
