/**********************************************************************
 
	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	<fcntl.h>
#include	"xlerror.h"
#include	"memory_debug.h"
#include	"xl.h"
#include	"long_char.h"
#include	"utils.h"
#include	"u_file.h"

XL_GETFILE * getfile_hash[GETFILE_HASH_SIZE];
L_CHAR * agent_name;
//L_CHAR * docs_path;
//L_CHAR * sys_path;

/*
typedef struct path_pair {
	L_CHAR * sys_path;
	L_CHAR * docs_path;
	L_CHAR * url_base;
	struct path_pair * next;
} path_pair;
*/

struct path_pair * start = NULL;



unsigned int
getfile_hash_key(L_CHAR * prefix)
{
unsigned int key;
	key = 0;
	for ( ; *prefix ; prefix ++ )
		key += *prefix;
	return key%GETFILE_HASH_SIZE;
}


XL_GETFILE *
search_getfile(L_CHAR * prefix,L_CHAR * agent,L_CHAR *fname)
{
unsigned int key;
XL_GETFILE * gf;
	key = getfile_hash_key(prefix);
	for ( gf = getfile_hash[key];
			gf;
			gf = gf->next )
		if ( l_strcmp(gf->prefix,prefix) == 0 &&
				l_strcmp(gf->agent,agent) == 0 ) {
			if ( fname == 0 )
				return gf;
			if ( l_strcmp(gf->cmd_sym,fname) == 0 )
				return gf;
		}
	return 0;
}


XL_GETFILE *
search_getfile_by_prefix(L_CHAR * prefix,XL_GETFILE * gfin)
{
unsigned int key;
XL_GETFILE * gf;
	if ( gfin == 0 ) { 
		key = getfile_hash_key(prefix);
		gf = getfile_hash[key];
	}
	else {
		gf = gfin->next;
	}
	for ( ;	gf ; gf = gf->next )
		if ( l_strcmp(gf->prefix,prefix) == 0 )
			return gf;
	return 0;
}

void
_insert_getfile(L_CHAR * prefix,L_CHAR * agent,L_CHAR * mode,int flags,
	L_CHAR * cmd);


void
_insert_getfile(L_CHAR * prefix,L_CHAR * agent,L_CHAR * mode,int flags,
	L_CHAR * cmd)
{
XL_GETFILE * gf;
int key;
	gf = search_getfile(prefix,agent,cmd);
	if ( gf == 0 ) {
		gf = d_alloc(sizeof(*gf));
		gf->prefix = ll_copy_str(prefix);
		gf->agent = ll_copy_str(agent);
		gf->mode = ll_copy_str(mode);
		gf->cmd_sym = ll_copy_str(cmd);
		gf->flags = flags;
		key = getfile_hash_key(prefix);
		gf->next = getfile_hash[key];
		getfile_hash[key] = gf;
	}
	else {
		if ( gf->mode )
			d_f_ree(gf->mode);
		gf->mode = ll_copy_str(mode);
		if ( gf->cmd_sym )
			d_f_ree(gf->cmd_sym);
		gf->cmd_sym = ll_copy_str(cmd);
		gf->flags = flags;
	}
}

void
insert_getfile(L_CHAR * prefix,L_CHAR * agent,L_CHAR * mode,int flags,
	XL_SEXP * cmd)
{
XL_SEXP * c;
	for ( ; get_type(cmd) ; cmd = cdr(cmd) ) {
		c = car(cmd);
		if ( get_type(c) != XLT_STRING )
			er_panic("insert_getfile");
		_insert_getfile(prefix,agent,mode,flags,c->string.data);
	}
}

L_CHAR *
get_synth_path(L_CHAR * b,L_CHAR * filepath)
{
L_CHAR * path;
int len,len_f;
	len = l_strlen(b);
	path = d_alloc(sizeof(L_CHAR) * (len + 2));
	l_strcpy(path,b);
	if(b[len-1]!='/')
	{
        	if(filepath[0]!='/' && filepath[0]!='.')
        	{

        	        l_strcpy(&path[len],l_string(std_cm,"/"));
			len++;
        	}
	}
	else
	{
		if(filepath[0]=='/')
		{
			memset(&path[len-1],(L_CHAR)0,sizeof(L_CHAR));
			len--;
		}
	}
	len_f = l_strlen(filepath);
	path = d_re_alloc(path,(len+len_f+1)*sizeof(L_CHAR));
	l_strcpy(&path[len],filepath);
/*	memcpy(&path[len],filepath,(len_f+1)*sizeof(L_CHAR));*/
	return path;
}

L_CHAR * get_url_path(L_CHAR * fullpath,L_CHAR * userpath)
{
int ulen,flen,len,hit=0;
L_CHAR * lpath, * upath;
L_CHAR * lprefix;
struct path_pair * wp;
L_CHAR * _u;
	flen = l_strlen(fullpath);
	/* check xldocs */
	for(wp=start;wp != NULL;wp=wp->next)
	{
		len = l_strlen(wp->docs_path);
		lpath = d_alloc(sizeof(L_CHAR)*(flen + 2));
		l_strcpy(lpath,fullpath);
		if(l_strlen(lpath)>=len)
		{
			lprefix = d_alloc(sizeof(L_CHAR)*(flen + 2));
			l_strcpy(lprefix,&lpath[len]);
			memset(&lpath[len],(L_CHAR)0,sizeof(L_CHAR));
			if(l_strcmp(wp->docs_path,lpath)==0)
			{
				ulen = l_strlen(wp->url_base);
				upath = d_alloc(sizeof(L_CHAR)*(ulen+2));
				l_strcpy(upath,wp->url_base);
				upath = get_synth_path(_u=upath,lprefix);
				d_f_ree(_u);
				hit = 1;
			}
			d_f_ree(lprefix);
		}
		d_f_ree(lpath);
		if(hit==1)
			goto get_url_path_End;
	}
	/* chech xlsys */
	for(wp=start;wp != NULL;wp=wp->next)
	{
		len = l_strlen(wp->sys_path);
		lpath = d_alloc(sizeof(L_CHAR)*(flen + 2));
		l_strcpy(lpath,fullpath);
		if(l_strlen(lpath)>=len)
		{
			lprefix = d_alloc(sizeof(L_CHAR)*(flen + 2));
			l_strcpy(lprefix,&lpath[len]);
			memset(&lpath[len],(L_CHAR)0,sizeof(L_CHAR));
			if(l_strcmp(wp->sys_path,lpath)==0)
			{
				ulen = l_strlen(wp->url_base);
				upath = d_alloc(sizeof(L_CHAR)*(ulen+2));
				l_strcpy(upath,wp->url_base);
				upath = get_synth_path(_u=upath,lprefix);
				d_f_ree(_u);
				hit = 1;
			}
			d_f_ree(lprefix);
		}
		d_f_ree(lpath);
		if(hit==1)
			goto get_url_path_End;
	}
	
get_url_path_End:
	if(hit==1)
	{
		userpath = d_alloc(sizeof(L_CHAR)*(l_strlen(upath)+2));
		l_strcpy(userpath,upath);
		d_f_ree(upath);
	}
	else	userpath = ll_copy_str(userpath);
	return userpath;
}

L_CHAR * docs_path_search(L_CHAR *f)
{
int len;
L_CHAR * c, * wc;
struct path_pair * wp;
L_CHAR dum[2];
	if(f[0]!='/')
	{
		c = d_alloc(sizeof(L_CHAR) * (l_strlen(f) + 2));
		l_strcpy(c,l_string(std_cm,"/"));
		l_strcpy(&c[1],f);
	}
	else
	{
		c = d_alloc(sizeof(L_CHAR) * (l_strlen(f) + 1));
		l_strcpy(c,f);
	}
	for(wp=start;wp != NULL;wp=wp->next)
	{
		wc = d_alloc(sizeof(L_CHAR) * (l_strlen(f) + 2));
		l_strcpy(wc,c);
		len = l_strlen(wp->url_base);
		if((l_strlen(wc))>=len)
		{
			memset(&wc[len],(L_CHAR)0,sizeof(L_CHAR));
			if(l_strcmp(wp->url_base,wc)==0)
			{
				if((len-1)>0)
				{
					l_strcpy(f,&c[len-1]);
/*
					f = d_re_alloc(f,sizeof(L_CHAR)*(l_strlen(c) + 1));
					l_strcpy(f,c);
*/
				}
				d_f_ree(wc);
				d_f_ree(c);
				return wp->docs_path;
			}
		}
		d_f_ree(wc);
	}
	d_f_ree(c);
	dum[0] = '/';
	dum[1] = 0;
	return docs_path_search(dum);
}

L_CHAR * sys_path_search(L_CHAR *f)
{
int len;
L_CHAR * c, * wc;
struct path_pair * wp;
L_CHAR dum[2];
	if(f[0]!='/')
	{
		c = d_alloc(sizeof(L_CHAR) * (l_strlen(f) + 2));
		l_strcpy(c,l_string(std_cm,"/"));
		l_strcpy(&c[1],f);
	}
	else
	{
		c = d_alloc(sizeof(L_CHAR) * (l_strlen(f) + 1));
		l_strcpy(c,f);
	}
	for(wp=start;wp != NULL;wp=wp->next)
	{
        	wc = d_alloc(sizeof(L_CHAR) * (l_strlen(f) + 2));
                l_strcpy(wc,c);
                len = l_strlen(wp->url_base);
		if((l_strlen(wc))>=len)
		{
			memset(&wc[len],(L_CHAR)0,sizeof(L_CHAR));
			if(l_strcmp(wp->url_base,wc)==0)
			{
				if((len-1)>0)
				{
					l_strcpy(f,&c[len-1]);
/*
					f = d_re_alloc(f,sizeof(L_CHAR)*(l_strlen(c) + 1));
					l_strcpy(f,c);
*/
				}
				d_f_ree(wc);
				d_f_ree(c);
				return wp->sys_path;
			}
		}
		d_f_ree(wc);
	}
	d_f_ree(c);
	dum[0] = '/';
	dum[1] = 0;
	return sys_path_search(dum);
}


L_CHAR *
get_xldocs(L_CHAR * f)
{
L_CHAR * path, * fpath, * dpath;
	if(f[0]=='/' && f[1]=='/')
	{
		fpath = ll_copy_str((f+1));
	}
	else
	{
		fpath = ll_copy_str(f);
	}
	dpath = docs_path_search(fpath);
	path = get_synth_path(dpath,fpath);
	d_f_ree(fpath);
	return path;
}

L_CHAR *
get_xlsys(L_CHAR * f)
{
L_CHAR * path, * fpath, * dpath;
	if(f[0]=='/' && f[1]=='/')
	{
		fpath = ll_copy_str((f+1));
	}
	else
	{
		fpath = ll_copy_str(f);
	}
	dpath = sys_path_search(fpath);
	path = get_synth_path(dpath,fpath);
	d_f_ree(fpath);
	return path;
}


XL_SEXP *
get_path(
	L_CHAR * target[2],
	XL_GETFILE ** gfp,
	L_CHAR * _filename,XL_SEXP * s,L_CHAR * func_name)
{
int p,len2;
L_CHAR * ptr;
XL_GETFILE * gf;
int line;
XL_FILE * file;
	if ( s ) {
		file = s->h.file;
		line = s->h.line;
	}
	else {
		file = 0;
		line = 0;
	}
	if ( agent_name == 0 )
		return get_error(
			file,
			line,
			XLE_SYSTEM_INTERNAL,
			func_name,
			n_get_string("dbpath and agent name is undefined"));

	p = l_strlen(_filename)-1;
	for ( ; p >= 0 && _filename[p] != '.' &&
			_filename[p] != '/' ; p -- );
	if ( p < 0 || _filename[p] == '/' )
		return get_error(
			file,
			line,
			XLE_PROTO_INV_PARAM,
			func_name,
			n_get_string("invalid file path"));
	if ( _filename[0] != '/' )
		return get_error(
			file,
			line,
			XLE_PROTO_INV_PARAM,
			func_name,
			n_get_string("invalid file path"));
	for ( ptr = _filename; *ptr ; ptr ++ ) {
		if ( *ptr != '.' )
			continue;
		if ( ptr[1] == '.' )
			return get_error(
				file,
				line,
				XLE_PROTO_INV_PARAM,
				func_name,
				n_get_string("invalid file path"));
	}

	gf = search_getfile(&_filename[p],agent_name,func_name);
	if ( gf == 0 )
		return get_error(
			file,
			line,
			XLE_PROTO_UNDEF_RESOURCE,
			func_name,
			n_get_string("undefined prefix"));
	*gfp = gf;
	len2 = l_strlen(_filename);

	target[0] = target[1] = 0;
	switch ( gf->flags & XLGFM_XLDIR ) {
	case XLGF_XLSYS_ONLY:
		target[0] = get_xlsys(_filename);
		break;
	case XLGF_XLDOC_ONLY:
		target[0] = get_xldocs(_filename);
		
		break;
	case XLGF_XLSYS_PRECEDENCE:
		target[0] = get_xlsys(_filename);
		target[1] = get_xldocs(_filename);
		
		break;
	case XLGF_XLDOC_PRECEDENCE:
		target[1] = get_xlsys(_filename);
		target[0] = get_xldocs(_filename);
		
		break;
	}
	return 0;
}

int
path_check(L_CHAR * filepath)
{
L_CHAR * p;
char * p1,* p2;
int f;
int ret;
int er;
	ret = 0;
	p = get_xldocs(filepath);
	p2 = change_delim_str(p1 = n_string(std_cm,p));
	f = u_open(p2,O_RDONLY);
	if ( p2 != p1 )
		d_f_ree(p2);
	d_f_ree(p);
	if ( f >= 0 ) {
	retry2_c:
		er = u_close(f);
		if ( er < 0 && errno == EINTR )
			goto retry2_c;
		ret |= 1;
	}
	p = get_xlsys(filepath);
	p2 = change_delim_str(p1 = n_string(std_cm,p));
	f = u_open(p2,O_RDONLY);
	if ( p2 != p1 )
		d_f_ree(p2);
	d_f_ree(p);
	if ( f >= 0 ) {
	retry1_c:
		er = u_close(f);
		if ( er < 0 && errno == EINTR )
			goto retry1_c;
		ret |= 2;
	}
	return ret;
}

int Reg_List_pathpair(L_CHAR * path,L_CHAR * url)
{
int len;
L_CHAR * path_docs, * path_sys, * url_base;
struct path_pair * wp, * nwp, * tmp ;
L_CHAR * _u;
	len = l_strlen(path);
	
	path_docs = d_alloc(sizeof(L_CHAR) * (len + 1));
	l_strcpy(path_docs,path);
	path_docs = get_append_path(_u=path_docs,"xldocs/");
	d_f_ree(_u);

	path_sys = d_alloc(sizeof(L_CHAR) * (len + 1));
	l_strcpy(path_sys,path);
	path_sys = get_append_path(_u=path_sys,"xlsys/");
	d_f_ree(_u);
	
	url_base = d_alloc(sizeof(L_CHAR) * (len + 1));
	l_strcpy(url_base,url);

	nwp = d_alloc(sizeof(path_pair));
	nwp->sys_path = path_sys;
	nwp->docs_path = path_docs;
	nwp->url_base = url_base;
	nwp->next = NULL;
	if(start==NULL)
	{
		start = nwp;
	}
	else
	{
		for(wp = start;wp->next != NULL;wp = wp->next)
		{
			if((l_strcmp(wp->url_base,nwp->url_base))<0)
			{
				nwp->next = wp;
				if(start == wp)
					start = nwp;
				else
					tmp->next = nwp;
				break;
			}
			else if((l_strcmp(wp->url_base,nwp->url_base))==0)
			{
				d_f_ree(nwp);
				goto Reg_List_pathpair_end;
			}
			tmp = wp;
		}
		if(nwp->next == NULL)
		{
			wp->next = nwp;
		}
	}
Reg_List_pathpair_end:;
	return 0;
}

XL_SEXP *
get_pathpair(L_CHAR * path)
{
int len;
L_CHAR * wc, * c;
struct path_pair * wp;
	len = l_strlen(path);
	if(path[len-1]!='/')
	{
		c = d_alloc(sizeof(L_CHAR) * (l_strlen(path) + 2));
		l_strcpy(c,path);
		l_strcpy(&c[len],l_string(std_cm,"/"));
	}
	else
	{
		c = d_alloc(sizeof(L_CHAR) * (l_strlen(path) + 1));
		l_strcpy(c,path);
	}
	for(wp=start;wp != NULL;wp=wp->next)
	{
		wc = d_alloc(sizeof(L_CHAR) * (l_strlen(path) + 1));
		l_strcpy(wc,c);
		len = l_strlen(wp->docs_path);
		memset(&wc[len],(L_CHAR)0,sizeof(L_CHAR));
		if(l_strcmp(wp->docs_path,wc)==0)
		{
			d_f_ree(wc);
			d_f_ree(c);
			return List(get_string(wp->docs_path),get_string(wp->sys_path),get_string(wp->url_base),-1);
		}
		d_f_ree(wc);
	}
	d_f_ree(c);
	return 0;
}


L_CHAR *
get_append_path(L_CHAR * d,char * c)
{
L_CHAR * lc;
L_CHAR * ret;
//	lc = d_alloc(sizeof(L_CHAR)*(strlen(c)+1));
	lc = nl_copy_str(std_cm,c);
	ret = get_synth_path(d,lc);
	d_f_ree(lc);
	return ret;
}

L_CHAR *
get_xldocs_path(URL * u)
{
L_CHAR * path, * f;
        f = get_url_filepath(u);
	path = get_xldocs(f);
   	d_f_ree(f);
        return path;
}

L_CHAR *
get_xlsys_path(URL * u)
{
L_CHAR * path, * f; 
        f = get_url_filepath(u);
	path = get_xlsys(f);
        d_f_ree(f);
        return path;
}

L_CHAR *
get_xldocs_apppath(URL * u,char * c)
{
L_CHAR * path;
L_CHAR * ret;
        path = get_xldocs_path(u);
        ret = get_append_path(path,c);
	d_f_ree(path);
	return ret;
}

L_CHAR *
get_xlsys_apppath(URL * u,char * c)
{
L_CHAR * path;
L_CHAR * ret;
        path = get_xlsys_path(u);
        ret = get_append_path(path,c);
	d_f_ree(path);
	return ret;
}

L_CHAR *
get_sys_path(char *c)
{
L_CHAR dum[2];
	dum[0] = '/';
	dum[1] = 0;
	return get_append_path(sys_path_search(dum),c);
}


