/*
 *  public/uwav/numgrp.c
 *
 *  Copyright (C) 2008  ADC, Inc
 *  Written by: Xinyu Yan <xinyu.yan@adc.com>
 *
 *  Description: number group lookup algorithm
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "numgrp.h"

static struct numgrp_table group_table[MAX_NUMBER_GROUP_TABLE];

struct numgrp_table *assign_numgrp_table(char *name, int size)
{
	int i;

	assert(size <= MAX_NUMBER_GROUP_TABLE_SIZE);
	
	for(i = 0; i < MAX_NUMBER_GROUP_TABLE; i++)
	{
		if(group_table[i].size == 0)
		{
			strncpy(group_table[i].name, name, 32);
			group_table[i].size = size;
			group_table[i].len = 0;
			group_table[i].item = malloc(sizeof(struct number_group) * size);
			return &group_table[i];
		}
	}
	return NULL;
}

int delete_numgrp_table(struct numgrp_table *table)
{
	int i;

	for(i = 0; i < MAX_NUMBER_GROUP_TABLE; i++)
	{
		if(&group_table[i] == table)
		{
			free(group_table[i].item);
			memset(&group_table[i], 0, sizeof(struct numgrp_table));
			return 1;
		}
	}
	return 0;
}

/*Return an integer greater than, equal to, or less than 0, if the number pointed  to
       by n1 is greater than, equal to, or less than the number pointed to by n2, respectively*/
static int numcmp(const num16_t *n1, const num16_t *n2)
{
	int i;
	
	if(n1->num_of_digit > n2->num_of_digit)
		return 1;
	else if(n1->num_of_digit < n2->num_of_digit)
		return -1;
	for(i = 0; i < n1->num_of_digit; i++)
	{
		if(n1->digit[i] > n2->digit[i])
			return 1;
		else if(n1->digit[i] < n2->digit[i])
			return -1;
	}
	return 0;
}

/*Return an integer greater than, equal to, or less than 0, if the number pointed  to
       by n is greater than, equal to, or less than the group pointed to by start and end, respectively*/
static int numgrpcmp(const num16_t *start, const num16_t *end, const num16_t *n)
{
	int ret1, ret2;

	ret1 = numcmp(n, start);
	ret2 = numcmp(n, end);
	if((ret1 >= 0) && (ret2 <= 0))
		return 0;
	else if(ret2 > 0)
		return 1;
	else
		return -1;
}

/* n: max items of table
 * num: number being searched
 * m: the position of value which is found or will be inserted
 * ret: return 1 if found, otherwise 0
*/
static int bisearch(struct number_group *item, int n, num16_t *num, int *m)
{
	int i = 0;
	int j = n - 1;
	int ret;

	*m = 0;
	while(i <= j)
	{
		*m = (i+j) / 2;
		ret = numgrpcmp(&item[*m].start, &item[*m].end, num);
		if(ret == 0)
			return 1;
		else if(ret > 0)
			i = *m + 1;
		else
			j = *m - 1;
	}
	*m = i;
	return 0;
}

int numgrp_search(int *index, struct numgrp_table *table, num16_t *num)
{
	int m;

	if(table == NULL)
		return 0;
	if(bisearch(table->item, table->len, num, &m))
	{
		*index = table->item[m].index;
		return 1;
	}
	return 0;
}

int numgrp_insert(struct numgrp_table *table, num16_t *start, num16_t *end, int index)
{
	int m, m2;

	if(numcmp(start, end) > 0)
	{
		printf("Start number > end number\n");
		return 0;
	}
	if(bisearch(table->item, table->len, start, &m))
	{
		printf("Start number in exist group\n");
		return 0;
	}
	if(bisearch(table->item, table->len, end, &m2))
	{
		printf("End number in exist group\n");
		return 0;
	}
	if(m != m2)
	{
		printf("Start-end contains other group\n");
		return 0;
	}
	memmove(&table->item[m+1], &table->item[m], sizeof(struct number_group)*(table->len-m));
	memcpy(&table->item[m].start, start, sizeof(num16_t));
	memcpy(&table->item[m].end, end, sizeof(num16_t));
	table->item[m].index = index;
	table->len++;
	return 1;
}

int numgrp_delete(struct numgrp_table *table, num16_t *num)
{
	int m;

	if(bisearch(table->item, table->len, num, &m))
	{
		memmove(&table->item[m], &table->item[m+1], sizeof(struct number_group)*(table->len-m-1));
		memset(&table->item[table->len-1], 0, sizeof(struct number_group));
		table->len--;
		return 1;
	}
	return 0;
}

