/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/

#include "vpf_std.h"
#include "vpf_container.h"


// VPF_LIST
VPF_LIST_ITEM *vpf_list_item_new()
{
	return (VPF_LIST_ITEM *)calloc(sizeof(VPF_LIST_ITEM),1);
}

void vpf_list_item_delete(VPF_LIST_ITEM *item, void (*data_destructor)(void *))
{
	VPF_LIST_ITEM *tmp;
	while(item){
		tmp = item->next;
		if(data_destructor){
			data_destructor(item->data);
		}
		free(item);
		item=tmp;
	}
}

VPF_LIST *vpf_list_new(void (*data_destructor)(void *))
{
VPF_LIST *ret;
	ret=(VPF_LIST *)calloc(sizeof(VPF_LIST),1);
	ret->data_destructor = data_destructor;
	return ret;
}

void vpf_list_push(VPF_LIST *list, void *data)
{
VPF_LIST_ITEM *item;
	item = vpf_list_item_new();
	item->data = data;
	
	if(list->tail == 0){
		list->tail = list->head = item;
	}
	else{
		list->tail->next = item;
		list->tail = item;
	}
}

void vpf_list_delete(VPF_LIST *list)
{
	if(list==NULL)
		return;
	vpf_list_item_delete(list->head, list->data_destructor);
	free(list);
}

int vpf_list_size(const VPF_LIST *list)
{
	VPF_LIST_ITEM *i;
	int ret=0;
	for(i=list->head; i; i=i->next){
		++ret;
	}
	return ret;
}

void vpf_list_invert(VPF_LIST *dest, const VPF_LIST *source)
{
VPF_LIST_ITEM **buff;
int item_count;
VPF_LIST_ITEM *it;
int i;

	item_count = vpf_list_size(source);
	buff=(VPF_LIST_ITEM **)malloc(sizeof(VPF_LIST_ITEM *)*item_count);
	for(i=0,it=source->head; it; it=it->next,++i){
		buff[i] = it;
	}
	for(i=item_count-1; i>=0; --i){
		vpf_list_push(dest, buff[i]->data);
	}
	free(buff);
}



// VPF_MAP
VPF_MAP *vpf_map_new(void (*data_destructor)(void *,void *), int (*comp)(const void *lhs, const void *rhs)){
	VPF_MAP *map;
	map = calloc(sizeof(VPF_LIST),1);
	map->data_destructor = data_destructor;
	map->comp = comp;
	return map;
}

VPF_MAP_ITEM *vpf_map_item_new()
{
	return calloc(sizeof(VPF_MAP_ITEM),1);
}

void vpf_map_item_delete(VPF_MAP_ITEM *item, void (*data_destructor)(void *,void*)){
	if(item==NULL)
		return;
	vpf_map_item_delete(item->left,data_destructor);
	vpf_map_item_delete(item->right,data_destructor);
	if(data_destructor){
		data_destructor(item->key, item->data);
	}
	free(item);
}

typedef int (*vpf_map_item_push_comp_type)(void *lhs, void *rhs);

void vpf_map_item_push(
		VPF_MAP *map, 
		VPF_MAP_ITEM **item, 
		void *key, void *data,  
		int (*comp)(void *lhs, void *rhs)){
int v;
	if(*item == NULL){
		*item = vpf_map_item_new();
		(*item)->key = key;
		(*item)->data = data;
		return;
	}
	v = comp((*item)->key, key);
	if(v==0){
		if(map->data_destructor){
			map->data_destructor((*item)->key, (*item)->data);
		}
		(*item)->key = key;
		(*item)->data = data;
	}
	else if(v>0){
		vpf_map_item_push(map, &(*item)->left, key, data, comp);
	}
	else{
		vpf_map_item_push(map, &(*item)->right, key, data, comp); 
	}
}

void vpf_map_push(VPF_MAP *map, void *key, void *data){
	vpf_map_item_push(map, &map->root, key, data, 
		(vpf_map_item_push_comp_type)map->comp);
}

void vpf_map_delete(VPF_MAP *map){
	if(map==NULL)
		return;
	vpf_map_item_delete(map->root, map->data_destructor);
	free(map);
}

void *vpf_map_find(const VPF_MAP *map, const void *key)
{
VPF_MAP_ITEM *item;
int i;
	item = map->root;
	if(!item)
		return NULL;
	while( (i = map->comp(item->key, key)) != 0){
		if(i > 0){
			if(item->left == NULL)
				return NULL;
			item = item->left;
		}
		else{
			if(item->right == NULL)
				return NULL;
			item = item->right;
		}
	}

	return item;
}
