/**********************************************************************
 
	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	<stdlib.h>
#include	"task.h"
#include	"memory_debug.h"
#include	"resource.h"


int resource_id[RT_MAX];
extern RESOURCE ** res_entry_hash_table;
extern RESOURCE ** res_target_hash_table;
extern RESOURCE ** res_no_hash_table;
extern SEM res_lock;

int
get_new_rid(int type)
{
RESOURCE * res;
int id;
RESOURCE * _search_resource_by_no(int);
	for ( ; ; ) {
		id = type*0x10000 + resource_id[type];
		res = _search_resource_by_no(id);
		if ( res == 0 )
			return id;
		resource_id[type] ++;
		if ( resource_id[type] >= RID_LENGTH )
			resource_id[type] = 0;
	}
}


unsigned int
get_lchar_key(L_CHAR * a)
{
unsigned int key;
	key = 0;
	for ( ; *a ; a ++ )
		key += *a;
	return key;
}

unsigned int
get_rhash_key(URL * u)
{
unsigned int key;
	key = get_lchar_key(u->proto);
	key += u->port;
	key += get_lchar_key(u->db);
	key += get_lchar_key(u->resource);
	return key % RES_HASH_SIZE;
}



RESOURCE *
_new_resource_entry(int type,URL * entry)
{
RESOURCE * r;
int size;
char * ptr;
int flags;
int key;


	if ( res_entry_hash_table == 0 ||
			res_target_hash_table == 0 ||
			res_no_hash_table == 0 )
		er_panic("_new_resource_entry(1)"); 

	switch ( type ) {
	case RT_COORDINATE:
		r = d_alloc(size=sizeof(COORDINATE),60);
		flags = RF_I_AUTO;
		break;
	case RT_PIXEL_MAP_R64:
		r = d_alloc(size=sizeof(PIXEL_MAP_R64),61);
		flags = RF_I_ON;
		break;
	case RT_DRAW_GB:
		r = d_alloc(size=sizeof(DRAW_GB),62);
		flags = RF_I_ON;
		break;
	case RT_MAP:
		r = d_alloc(size=sizeof(RES_MAP),63);
		flags = RF_I_ON;
		break;
	default:
		er_panic("new_resource_entry(1)");
	}
	for ( ptr = (char*)r ; size ; *ptr++ = 0 , size -- );
	r->h.type = type;
	r->h.flags = flags;
	r->h.no = get_new_rid(type);
	r->h.meta = 0;
	r->h.initial_error = 0;
	r->h.initial_status = RS_IDLE;
	r->h.incremental_status = RS_IDLE;
	r->h.incremental_error = 0;
	r->h.error_time = 0;
	r->h.error_expire = 0;
	r->h.entry.proto = 0;
	r->h.target.proto = 0;
	r->h.notes = 0;
	r->h.visible_resolution = 0;
	zero_c_unit(&r->h.cu);

	copy_url(&r->h.entry,entry);

	key = get_rhash_key(&r->h.entry);
	r->h.entry_next = res_entry_hash_table[key];
	res_entry_hash_table[key] = r;

	r->h.target_next = 0;

	key = ((unsigned int)r->h.no) % RES_HASH_SIZE;
	r->h.no_next = res_no_hash_table[key];
	res_no_hash_table[key] = r;

	return r;
}

RESOURCE *
new_resource_entry(int type,URL * u)
{
RESOURCE * ret;

	lock_task(res_lock);
	ret = _new_resource_entry(type,u);
	unlock_task(res_lock,"new_reosource_entry");
	return ret;
}


int
_set_resource_target(RESOURCE * r,URL * u)
{
int key;
	if ( res_entry_hash_table == 0 ||
			res_target_hash_table == 0 ||
			res_no_hash_table == 0 )
		er_panic("_new_resource_entry(1)"); 


	if ( r->h.target.proto )
		return -1;
	copy_url(&r->h.target,u);

	key = get_rhash_key(u);
	r->h.target_next = res_target_hash_table[key];
	res_target_hash_table[key] = r;
	return 0;
}


int
set_resource_target(RESOURCE * r,URL * u)
{
int ret;
	lock_task(res_lock);
	ret = _set_resource_target(r,u);
	unlock_task(res_lock,"set_resource_target");
	return ret;
}

void
_delete_resource_entry(RESOURCE * r)
{
int key;
RESOURCE ** rp;

	if ( res_entry_hash_table == 0 ||
			res_target_hash_table == 0 ||
			res_no_hash_table == 0 )
		er_panic("_new_resource_entry(1)"); 

	key = get_rhash_key(&r->h.entry);
	rp = &res_entry_hash_table[key];
	for ( ; *rp ; rp = &(*rp)->h.entry_next ) {
		if ( *rp != r )
			continue;
		*rp = r->h.entry_next;
		break;
	}

	key = ((unsigned int)r->h.no) % RES_HASH_SIZE;
	rp = &res_no_hash_table[key];
	for ( ; *rp ; rp = &(*rp)->h.no_next ) {
		if ( *rp != r )
			continue;
		*rp = r->h.no_next;
		break;
	}

	if ( r->h.target.proto == 0 )
		return;
	key = get_rhash_key(&r->h.target);
	rp = &res_target_hash_table[key];
	for ( ; *rp ; rp = &(*rp)->h.target_next ) {
		if ( *rp != r )
			continue;
		*rp = r->h.target_next;
		break;
	}
}


void
delete_resource_entry(RESOURCE * r)
{
	lock_task(res_lock);
	_delete_resource_entry(r);
	unlock_task(res_lock,"delete_resource_entry");
}
