#include <stdio.h>
#include "uthash.h"

#include <netinet/ip.h>

struct groupinfo {
	uint32_t id;            /* use this field as key (name has to be "id" */
	/* new_marker_value = markervalue_start + (ip - nw_addr) / group_size */
	uint32_t nw_addr;
	uint32_t group_size;
	uint32_t markervalue_start;
	UT_hash_handle hh; /* makes this structure hashable */
};

struct groupinfo *group_hashtable = NULL;

void add_group(struct groupinfo *g) {
	struct groupinfo *g_find;

	HASH_FIND_INT(group_hashtable, &g->id, g_find);  /* id already in the hash? */
	if (g_find == NULL) {
		HASH_ADD_INT( group_hashtable, id, g );
	} else {
		printf("id already in hashtable, not adding: %d", g->id);
	}
}
/*
INFO: It is ok to have concurrent readers on hashtable since uthash 1.5
*/
struct groupinfo *find_group(int ip_prefix) {
    struct groupinfo *s;

    HASH_FIND_INT( group_hashtable, &ip_prefix, s );
    return s;
}

void delete_group(struct groupinfo *g) {
    HASH_DEL( group_hashtable, g);
}

void read_groups(char *filename, uint32_t markervalue_bits) {
char line[1000];
/* file format: ip\tmarkervalue\tsubnets */
FILE *ip_file = fopen(filename, "r");

while (fgets(line, 1000, ip_file) != NULL) {

	if (!ip_file) {
		perror("Error while opening the group file.\n");
		exit(EXIT_FAILURE);
	}
	/* split by tabs */
	char* token = strtok(line, "\t");
	//printf("%s\n", token);
	struct in_addr addr;

	if (!inet_aton(token, &addr)) {
		printf("could not parse ip: %s\n", token);
	}
	uint32_t ip_int_ho = (uint32_t)ntohl(addr.s_addr);
	// remove trailing checksum bits
	// 0xAAAAAABB -> 0x00AAAAAA
	//ip_int_ho >>= (32 - markervalue_bits);
	//printf("ip: %u\n", ip_int_ho);

	token = strtok(NULL, "\t");
	//printf("%s\n", token);
	uint32_t markervalue = atoi(token);
	//printf("markervlue: %d\n", markervalue);

	token = strtok(NULL, "\t");
	//printf("%s\n", token);
	uint32_t subnets = atoi(token);
	//printf("subnets: %d\n", subnets);
	//printf("------\n");

		struct groupinfo *newentry;
		newentry = malloc(sizeof(struct groupinfo));
		newentry->id = ip_int_ho;
		add_group(newentry);

}
fclose(ip_file);
	unsigned int groups_total;
	groups_total = HASH_COUNT(group_hashtable);
	printf("there are %u groups\n", groups_total);

}
int main() {
read_groups("./groupfile_test3.csv", 24);
}
int main_() {
	int i = 0;

	for (; i < 500000; ++i) {
		struct groupinfo *newentry;
		newentry = malloc(sizeof(struct groupinfo));
		newentry->id = i;
		add_group(newentry);
	}

	unsigned int groups_total;
	groups_total = HASH_COUNT(group_hashtable);
	printf("there are %u groups\n", groups_total);

	struct groupinfo *g = find_group(1234);
	printf("value: %d\n", g->id);
	sleep(99999);
}
