/**********************************************************************
 
	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	"task.h"
#include	"lock_level.h"
#include	"memory_debug.h"
#include	"utils.h"
#include	"rcache.h"

SEM rcache_lock;
L_CHAR * rcache_dir_path;
RCACHE_BLK * path_blk_list;
int rcache_start_flag;
int rcache_flags;

int rcache_flush();
int rcache_exit_flag;
void rcache_exit_tick();
void rcache_task();

void
init_rcache()
{
	rcache_lock = new_lock(LL_RCACHE);
	int_handler = rcache_flush;
	new_tick(rcache_exit_tick,1,0);
	init_rt_cache();
	init_rs_cache();
	create_task(rcache_task,0,0);
}

int
rcache_flush()
{
	rcache_exit_flag = 1;
	return 0;
}

void
rcache_exit_tick()
{
	if ( rcache_exit_flag == 0 )
		return;
	printf("RCACHE INTERRUPT\n");
	disable_rcache();
	exit(0);
}

void
mk_path(L_CHAR * path,int last)
{
L_CHAR * ptr, * buf;
L_CHAR ch;
char * p;
	buf = ll_copy_str(path);
	if ( buf[0] == '/' )
		ptr = &buf[1];
	else	ptr = buf;
	for ( ; *ptr ; ) {
		for ( ; *ptr && *ptr != '/' ; ptr ++ );
		if ( *ptr == 0 && last == 0 )
			break;
		ch = *ptr;
		*ptr = 0;
		p = n_string(std_cm,buf);
		u_mkdir(p,0755);
		*ptr = ch;
		if ( ch == 0 )
			break;
		ptr ++;
	}
	d_f_ree(buf);
}

void
set_rcache_dir_path(L_CHAR * main_path,L_CHAR * rcache_path)
{
L_CHAR * path;
int m_len,c_len;
int cpp;
	lock_task(rcache_lock);
ss_printf("set_rcache_dir(1)\n");
	if ( main_path ) {
		m_len = l_strlen(main_path);
		c_len = l_strlen(rcache_path);
		path = d_alloc((m_len + c_len + 3)*sizeof(L_CHAR));
		memcpy(path,main_path,m_len * sizeof(L_CHAR));
		if ( path[m_len-1] == '/' ) {
			cpp = m_len;
		}
		else {
			path[m_len] = '/';
			cpp = m_len + 1;
		}
		memcpy(&path[cpp],rcache_path,c_len * sizeof(L_CHAR));
		cpp += c_len;
		if ( path[cpp-1] == '/' )
			path[cpp] = 0;
		else {
			path[cpp] = '/';
			path[cpp+1] = 0;
		}
		if ( rcache_dir_path )
			d_f_ree(rcache_dir_path);
		rcache_dir_path = path;
		mk_path(path,1);
	}
	else {
		d_f_ree(rcache_dir_path);
		rcache_dir_path = 0;
	}
	unlock_task(rcache_lock,"set_rcache_dir_path");
}

L_CHAR *
get_rcache_file_name(char * name)
{
L_CHAR * ret;
int len,n_len;
L_CHAR * _name;
	if ( rcache_dir_path == 0 )
		return 0;
	_name = l_string(std_cm,name);
	len = l_strlen(rcache_dir_path);
	n_len = l_strlen(_name);
	ret = d_alloc((len + n_len + 1)*sizeof(L_CHAR));
	memcpy(ret,rcache_dir_path,len * sizeof(L_CHAR));
	memcpy(&ret[len],_name,(n_len + 1)* sizeof(L_CHAR));
	return ret;
}


RCACHE_BLK *
_search_blk(L_CHAR * path)
{
RCACHE_BLK * b;
int len_path,len_b,min;
	len_path = l_strlen(path);
	for ( b = path_blk_list ; b ; b = b->next ) {
		len_b = l_strlen(b->path);
		if ( len_b < len_path )
			min = len_b;
		else	min = len_path;
		if ( memcmp(b->path,path,min*sizeof(L_CHAR)) == 0 )
			return b;
	}
	return 0;
}

int
_x_lock_rcache_path(L_CHAR * path,int lock,char * file,int line)
{
RCACHE_BLK * b;

retry:
	b = _search_blk(path);
	if ( b ) {
		sleep_task((int)b,rcache_lock);
		lock_task(rcache_lock);
		goto retry;
	}
	b = d_alloc(sizeof(*b));
	b->path = ll_copy_str(path);
	b->lock = lock;
	b->tid = get_tid();
	b->err = 0;
	b->next = path_blk_list;
	b->ent_file = copy_str(file);
	b->ent_line = line;
	b->ext_file = 0;
	b->ext_line = 0;
	path_blk_list = b;
	return 0;
}

int
_unlock_rcache_path(L_CHAR * path)
{
RCACHE_BLK * b, ** bp;
int tid;
	tid = get_tid();
	for ( bp = &path_blk_list ; *bp ; bp = &(*bp)->next ) {
		b = *bp;
		if ( l_strcmp(b->path,path) )
			continue;
		*bp = b->next;
		if ( b->tid != tid )
			er_panic("invalid tid");
		wakeup_task((int)b);
		d_f_ree(b->ent_file);
		d_f_ree(b->path);
		d_f_ree(b);
		return 0;
	}
	er_panic("no path");
	return -1;
}


int
x_rlock_rcache_path(L_CHAR * path,char * file,int line)
{
int ret;
	lock_task(rcache_lock);
	ret = _x_lock_rcache_path(path,1,file,line);
	unlock_task(rcache_lock,"rlock_rcache_path");
	return ret;
}

int
x_wlock_rcache_path(L_CHAR * path,char * file,int line)
{
int ret;
	lock_task(rcache_lock);
	ret = _x_lock_rcache_path(path,-1,file,line);
	unlock_task(rcache_lock,"rlock_rcache_path");
	return ret;
}

int
unlock_rcache_path(L_CHAR * path)
{
int ret;
	lock_task(rcache_lock);
	ret = _unlock_rcache_path(path);
	unlock_task(rcache_lock,"rlock_rcache_path");
	return ret;
}

int
x_rlock_rcache(RCACHE_BLK * b,char * file,int line)
{
int ret;
	lock_task(rcache_lock);
	if ( b->tid == get_tid() && b->lock == 2 )
		goto loc;
	for ( ; b->lock ; ) {
		sleep_task((int)b,rcache_lock);
		lock_task(rcache_lock);
	}
loc:
	b->lock = 1;
	b->tid = get_tid();
	if ( b->ent_file )
		d_f_ree(b->ent_file);
	b->ent_file = copy_str(file);
	b->ent_line = line;
	ret = 0;
end:
	unlock_task(rcache_lock,"rlock_rcache");
	return ret;
}

int
x_local_lock_rcache(RCACHE_BLK * b,char * file,int line)
{
int ret;
	lock_task(rcache_lock);
	for ( ; b->lock ; ) {
		sleep_task((int)b,rcache_lock);
		lock_task(rcache_lock);
	}
	b->lock = 2;
	b->tid = get_tid();
	if ( b->ent_file )
		d_f_ree(b->ent_file);
	b->ent_file = copy_str(file);
	b->ent_line = line;
	ret = 0;
end:
	unlock_task(rcache_lock,"rlock_rcache");
	return ret;
}

int
x_wlock_rcache(RCACHE_BLK * b,char * file,int line)
{
int ret;
	lock_task(rcache_lock);
	if ( b->tid == get_tid() && b->lock == 2 )
		goto loc;
	for ( ; b->lock ; ) {
		sleep_task((int)b,rcache_lock);
		lock_task(rcache_lock);
	}
loc:
	b->lock = -1;
	b->tid = get_tid();
	if ( b->ent_file )
		d_f_ree(b->ent_file);
	b->ent_file = copy_str(file);
	b->ent_line = line;
	ret = 0;
end:
	unlock_task(rcache_lock,"wlock_rcache");
	return ret;
}



int
x_unlock_rcache(RCACHE_BLK * b,char * file,int line)
{
int ret;
	lock_task(rcache_lock);
	if ( b->lock > 0 ) {
		b->lock = 0;
	}
	else if ( b->lock < 0 ) {
		if ( b->tid != get_tid() )
			er_panic("unlock_rcache");
		b->lock = 0;
	}
	else	er_panic("unlock_rcache");
	b->tid = 0;
	if ( b->ext_file )
		d_f_ree(b->ext_file);
	b->ext_file = copy_str(file);
	b->ext_line = line;
	wakeup_task((int)b);
	ret = 0;
end:
	unlock_task(rcache_lock,"rlock_rcache");
	return ret;
}


int
new_rcache_blk(RCACHE_BLK * b,char * name)
{
int ret;

	if ( b->err != RE_IDLE )
		goto end;
	if ( b->path )
		d_f_ree(b->path);
	b->path = get_rcache_file_name(name);
	if ( b->path == 0 ) {
		ret = -1;
		goto end;
	}
	b->ext_file = b->ent_file = 0;
	b->ext_line = b->ent_line = 0;
	b->err = RE_RUN;
	ret = 0;

end:
	return ret;
}




void
purge_rcache(L_CHAR * url)
{
	purge_rt_cache(url);
	purge_rs_cache(url);
}

void
enable_rcache(int flags)
{
	lock_task(rcache_lock);
	rcache_flags = flags;
	unlock_task(rcache_lock,"enable_rache");
	enable_rt_cache(flags);
	enable_rs_cache(flags);
}

int
get_rcache_flags()
{
int ret;
	lock_task(rcache_lock);
	ret = rcache_flags;
	unlock_task(rcache_lock,"get_rcache_flags");
	return ret;
}


void
disable_rcache()
{
	disable_rt_cache();
	disable_rs_cache();
}

void
rcache_invoke()
{
	lock_task(rcache_lock);
	rcache_start_flag = 1;
	wakeup_task((int)&rcache_start_flag);
	unlock_task(rcache_lock,"rcache_invoke");
	
}


void
rcache_task()
{
	for ( ; ; ) {
		lock_task(rcache_lock);
		for ( ; rcache_start_flag == 0 ; ) {
			sleep_task((int)&rcache_start_flag,rcache_lock);
			lock_task(rcache_lock);
		}
		rcache_start_flag = 0;
		unlock_task(rcache_lock,"rcache_task");

		routing_cache_invoke();
		resource_cache_invoke();
	}
}



