/*
 * this is a trimmed-down version of bdz.c with only "search".
 */
#include "bdz.h"
#include "cmph_structs.h"
#include "bdz_structs.h"
#include "bitbool.h"

#define UNASSIGNED 3U

// table used for looking up the number of assigned vertices  a 8-bit integer
const cmph_uint8 bdz_lookup_table[] =
{
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 0
};

static inline cmph_uint32 rank(cmph_uint32 b, cmph_uint32 * ranktable, cmph_uint8 * g, cmph_uint32 vertex)
{
	register cmph_uint32 index = vertex >> b;
	register cmph_uint32 base_rank = ranktable[index];
	register cmph_uint32 beg_idx_v = index << b;
	register cmph_uint32 beg_idx_b = beg_idx_v >> 2;
	register cmph_uint32 end_idx_b = vertex >> 2;
	while(beg_idx_b < end_idx_b)
	{
		base_rank += bdz_lookup_table[*(g + beg_idx_b++)];

	}
	beg_idx_v = beg_idx_b << 2;
	while(beg_idx_v < vertex)
	{
		if(GETVALUE(g, beg_idx_v) != UNASSIGNED) base_rank++;
		beg_idx_v++;
	}

	return base_rank;
}

/** cmph_uint32 bdz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
 *  \brief Use the packed mphf to do a search.
 *  \param  packed_mphf pointer to the packed mphf
 *  \param key key to be hashed
 *  \param keylen key legth in bytes
 *  \return The mphf value
 */
cmph_uint32 bdz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
{

	register cmph_uint32 vertex;
	register CMPH_HASH hl_type  = (CMPH_HASH)(*(cmph_uint32 *)packed_mphf);
	register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4;

	register cmph_uint32 *ranktable = (cmph_uint32*)(hl_ptr + hash_state_packed_size(hl_type));

	register cmph_uint32 r = *ranktable++;
	register cmph_uint32 ranktablesize = *ranktable++;
	register cmph_uint8 * g = (cmph_uint8 *)(ranktable + ranktablesize);
	register cmph_uint8 b = *g++;

	cmph_uint32 hl[3];
	hash_vector_packed(hl_ptr, hl_type, key, keylen, hl);
	hl[0] = hl[0] % r;
	hl[1] = hl[1] % r + r;
	hl[2] = hl[2] % r + (r << 1);
	vertex = hl[(GETVALUE(g, hl[0]) + GETVALUE(g, hl[1]) + GETVALUE(g, hl[2])) % 3];
	return rank(b, ranktable, g, vertex);
}
