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

XL_SEXP* HTMLDataBase;	//データベース本体へのポインタ
extern char http_hostname[];
extern int http_port;
XLISP_ENV * env_HTMLdb;

XL_SEXP* PrimitiveFunctions;

typedef int (*PRIMITIVE_FUNC)(STREAM*,L_CHAR*,L_CHAR*);

void init_html_db()
{
	HTMLDataBase = 0;
	init_htmldb_function();
}

void
gc_htmldb()
{
	gc_gb_sexp(HTMLDataBase);
/*
	gc_gb_sexp(CurrentPage);
*/
}


XL_SEXP* RemoveElement(L_CHAR* url,XL_SEXP* db)//データベースの要素を削除
{
	int i,j,k;
	L_CHAR (*buf)[32][256];			
	L_CHAR* cmp1;
	int flag = 0;
	int IsRemoved = 0;
	
	XL_SEXP* temp;
	XL_SEXP* ret = 0;

	buf = d_alloc(sizeof(L_CHAR)*32*256,1234);

	cmp1 = l_string(std_cm,"/");
	
	if(url[0] == cmp1[0])
		i = 1;
	else 
		i = 0;
/*		
	printf("url := %s\n",n_string(std_cm,url));
*/
				
	for(j = 0 ; ; i++,j++)//urlを/で分割する
	{
		for(k = 0 ; (url[i] != cmp1[0]) && (url[i] != 0) ; i++,k++)
			(*buf)[j][k] = url[i];
			
		(*buf)[j][k] = 0;	
/*
		printf("buf[%d] := %s\n",j,n_string(std_cm,(*buf)[j]));
*/
		
		if(url[i] == 0)
			break;
	}
	j++;
	
	for(temp = db ; get_type(temp) ; temp = cdr(temp))
	{
		int n,m;
		XL_SEXP* dbdata;
		L_CHAR* elem;
				
		dbdata = car(temp);
		n = car(dbdata)->integer.data;

		flag = 0;
		
		if(n < 0)
			n = -n;
		if(n == j)// /で区切られた部分の数は等しい
		{
			flag = 1;
			for(m = 0 ; (m < n)  && flag ; m++)
			{	
				dbdata = cdr(dbdata);
				elem = car(dbdata)->string.data;
				
				if(l_strcmp((*buf)[m],elem))
					//データは一致しなかった
					flag = 0;
			}
		}
		if(!flag)//削除しない
			ret = cons(car(temp),ret);
	}

	d_f_ree(buf);

	return ret;
}

int
_db_inc(int * count,int len,int stop_len)
{
int i,j;
int total;
	for ( i = 0 ; i < len ; ) {
		for ( ; i < len ; i ++ ) {
			if ( count[i] )
				break;
		}
		if ( i == len )
			return -1;
		count[i] ++;
		total = 0;
		for ( j = 0 ; j < len ; j ++ ) {
			if ( count[j] )
				total += count[j];
			else	total ++;
		}
		if ( total <= stop_len )
			return 0;
		count[i] = 1;
		i ++;
	}
	return -1;
}


int
__cmp_db_str(L_CHAR * a,L_CHAR * b,int * count,int len)
{
int i,j;
int c;
int alen;
	alen = l_strlen(a);
	j = 0;
	for ( i = 0 ; i < len && j < alen ; i ++ , b ++ ) {
		c = count[i];
		if ( c == 0 ) {
			if ( *a++ != *b )
				return -1;
			j ++;
		}
		else {
			for ( ; c > 0 ; c -- ) {
				a ++;
				j ++;
			}
		}
	}
	if ( i == len && j == alen )
		return 0;
	return -1;
}

int
__cmp_db_url(L_CHAR * a,L_CHAR * b)
{
int * count;
int len,alen;
int i,j;
	len = l_strlen(b);
	alen = l_strlen(a);
	count = d_alloc(sizeof(int)*len,235);
	for ( i = 0; i < len ; i ++ ) {
		if ( b[i] == '*' )
			count[i] = 1;
		else	count[i] = 0;
	}
	for ( ; ; ) {
		if ( __cmp_db_str(a,b,count,len) == 0 ) {
			d_f_ree(count);
			return 0;
		}
		if ( _db_inc(count,len,alen) < 0 ) {
			d_f_ree(count);
			return -1;
		}
	}
}

int
_cmp_db_url(L_CHAR ** buf,int len,XL_SEXP * db,int * count,int db_len)
{
int i,j;
XL_SEXP * r;
int c;
	i = 0;
	j = 0;
	db = cdr(db);
	for ( i = 0 ; i < db_len && j < len ; i ++ , db = cdr(db) ) {
		c = count[i];
		if ( c == 0 ) {
			r = car(db);
			if ( __cmp_db_url(buf[j],r->string.data) )
				return -1;
			j ++;
		}
		else {
			for ( ; c > 0 ; c -- )
				j ++;
		}
	}
	if ( j == len && i == db_len )
		return 0;
	return -1;
}

int
cmp_db_url(L_CHAR ** buf,int len,XL_SEXP * db)
{
int db_url_size;
int * count;
int i;
XL_SEXP * dbp, * r;

	get_type(get_el(db,0));
	db_url_size = get_el(db,0)->integer.data;
	if ( db_url_size < 0 )
		db_url_size = - db_url_size;
	count = d_alloc(sizeof(int)*db_url_size,234);
	dbp = cdr(db);
	for ( i = 0 ; i < db_url_size ; i ++ , dbp = cdr(dbp) ) {
		r = car(dbp);
		if ( l_strcmp(r->string.data,l_string(std_cm,"**")) == 0 )
			count[i] = 1;
		else	count[i] = 0;
	}
	for ( ; ; ) {
		if ( _cmp_db_url(buf,len,db,count,db_url_size) == 0 ) {
			d_f_ree(count);
			return 0;
		}
		if ( _db_inc(count,db_url_size,len) < 0 )
			break;
	}
	d_f_ree(count);
	return -1;
}

XL_SEXP* GetElement(L_CHAR* url,XL_SEXP* db)
{
	int i,j,k;
	L_CHAR ** buf;
	L_CHAR * u;
	int flag = 0;
	
	XL_SEXP* temp;

	buf = d_alloc(sizeof(L_CHAR*)*32,12);
/*
printf("start GetElement>>>>>\n");
*/
	u = ll_copy_str(url,1498);
	if ( u[0] == '/' )
		i = 1;
	else	i = 0;
	j = 0;
	for ( ; ; ) {
		if ( j == 32 )
			break;
		buf[j++] = &u[i];
		for ( ; u[i] && u[i] != '/' ; i ++ );
		switch ( u[i] ) {
		case 0:
			goto loop_end;
		case '/':
			u[i] = 0;
			i ++;
		}
		continue;
	loop_end:
		break;
	}

	for(temp = db ; get_type(temp) ; temp = cdr(temp))
	{
		if( cmp_db_url(buf,j,car(temp)) == 0 ) {
/*
			printf("<<<<<End GetElement(with find)\n");
*/
			d_f_ree(u);
			d_f_ree(buf);
			return car(temp);	
		}
	}
	d_f_ree(u);
	d_f_ree(buf);
/*
	printf("<<<<<End GetElement(without find)\n");
*/
	return 0;
}


L_CHAR* GetOption(L_CHAR* name,XL_SYM_FIELD * sf)
{
	XL_SYM_FIELD * tmp;
	
	for (tmp = sf ; tmp ; tmp = tmp->next ) 
	{
		if(l_strcmp(tmp->name,name) == 0)
			return tmp->data;
	}
	return 0;
}

XL_SEXP* MakeURLList(L_CHAR* URLString,XLISP_ENV * env)
{
	XL_SEXP * elem;
	XL_SEXP * URL = 0;
	
	int i,j,k;
	L_CHAR (*buf)[32][256];
	L_CHAR* cmp1;
	int flag = 0;


	buf = d_alloc(sizeof(L_CHAR)*32*256,1234);

	cmp1 = l_string(std_cm,"/");
			
	if(URLString[0] == cmp1[0])
		i = 1;
	else 
		i = 0;
		
	for(j = 0 ;  ; i++,j++)
	{
		for(k = 0 ; (URLString[i] != cmp1[0]) && (URLString[i] != 0) ; i++,k++)
			(*buf)[j][k] = URLString[i];
			
		(*buf)[j][k] = 0;	
/*
		printf("%s\n",n_string(std_cm,(*buf)[j]));
*/
				
		if(URLString[i] == 0)
			break;
	}
	for(i = j ; i >= 0 ; i--)
	{
		URL = cons(get_string((*buf)[i]),URL);
					
		if(l_strcmp((*buf)[i],l_string(std_cm,"**")) == 0)
			flag = 1;
	}
	j++;
	URL = cons(get_integer(flag?-j:j,0),URL);
	set_env(env,URL->symbol.data,URL);

	d_f_ree(buf);

	return URL;
}

ElementType CheckElementType(XL_SEXP* elem)
{
	int i,n;
	XL_SEXP *tmp;
	
	n = car(elem)->integer.data;
	if(n < 0)
	 	n = -n;
	for(i = 0,tmp = elem ; i <= n ; i++)
		tmp = cdr(tmp);
	tmp = car(tmp);
/*
	printf("type := %s\n",n_string(std_cm,tmp->string.data));
*/
	if(l_strcmp(tmp->string.data,l_string(std_cm,"HTML")) == 0)
		return HTMLDoc;
	else if(l_strcmp(tmp->string.data,l_string(std_cm,"XL")) == 0)
		return XLScript;
	else if(l_strcmp(tmp->string.data,l_string(std_cm,"Raw")) == 0 )
		return Raw;
	else	return Primitive;
}


void ExecScript(XL_SEXP* elem)
{
	//未実装
	//引数未定
	//スクリプトを受け取り実行
	//envがない場合どのようにeval()するのだろうか？
	/*
	
	
	
	*/
}

PRIMITIVE_FUNC GetFunctionAddr(L_CHAR* FunctionName)
{
	XL_SEXP* tmp;
	for(tmp = PrimitiveFunctions ; tmp ; tmp = cdr(tmp))
	{
		if(l_strcmp(car(car(tmp))->string.data,FunctionName) == 0)
			return (PRIMITIVE_FUNC)
				car(cdr(car(tmp)))->integer.data;
	}
	return 0;
}

L_CHAR * GetKey(XL_SEXP* elem)
{
	int i,n;
	XL_SEXP *tmp;
	
	n = car(elem)->integer.data;
	if(n < 0)
	 	n = -n;
	n += 2;
	for(i = 0,tmp = elem ; i <= n ; i++)
		tmp = cdr(tmp);
	tmp = car(tmp);
	
	return tmp->string.data;
}

L_CHAR * GetFunctionName(XL_SEXP* elem)
{
	int i,n;
	XL_SEXP *tmp;
	
	n = car(elem)->integer.data;
	if(n < 0)
	 	n = -n;
	n++;
	for(i = 0,tmp = elem ; i <= n ; i++)
		tmp = cdr(tmp);
	tmp = car(tmp);
	
	return tmp->string.data;
}

int ExecPrimitive(STREAM* st,XL_SEXP* elem)
{
	//引数未定
	//プリミティブ関数を実行
	return (GetFunctionAddr(GetFunctionName(elem)))(st,GetURLString(elem),GetKey(elem));
}

L_CHAR* GetURLString(XL_SEXP* elem)
{
	L_CHAR (*buf)[1024];
	L_CHAR* ret;
	L_CHAR* SLASH;
	int i,n;
	int len = 0;
	XL_SEXP* tmp,*t;
	
	SLASH = l_string(std_cm,"/");

	buf = d_alloc(sizeof(L_CHAR)*1024,1234);

	n = car(elem)->integer.data;
	if(n < 0)
	 	n = -n;
	for(i = 0,tmp = cdr(elem) ; i < n ; i++,tmp = cdr(tmp))
	{
		t = car(tmp);
		(*buf)[len] = SLASH[0];
		len++;
		l_strcpy(&(*buf)[len],t->string.data);
		len += l_strlen(t->string.data);
	}
	(*buf)[len] = 0;
	
	ret = d_alloc(sizeof(L_CHAR)*len+1,235);
	l_strcpy(ret,buf);

	d_f_ree(buf);

	return ret;
}

int CheckWildCard(L_CHAR* URLString)
{
	int i,n;
	L_CHAR* cmp;
	
	n = l_strlen(URLString);
	cmp = l_string(std_cm,"*");
	for(i = 0 ; i < n ; i++)
	{
		if(URLString[i] == cmp[0])
			return 1;
	}
	return 0;
}

HTMLFileType CheckFileType(L_CHAR * url)
{	
	L_CHAR (*buf)[256];
	int i,n;
	L_CHAR* cmp;
	HTMLFileType ret;

	buf = d_alloc(sizeof(L_CHAR)*256,1234);

	cmp = l_string(std_cm,".");
	(*buf)[255] = 0;
	for(i = l_strlen(url) - 1,n = 254 ; url[i] != cmp[0] ; i--,n--)
		(*buf)[n] = url[i];
		
	if(l_strcmp(&(*buf)[n],l_string(std_cm,"html")) == 0)
		ret = html;
	else if(l_strcmp(&(*buf)[n],l_string(std_cm,"cgi")) == 0)
		ret = cgi;
	else
		ret = other;
	d_f_ree(buf);
	return ret;
}

UpdateOption CheckUpdateOption(L_CHAR * update)
{
	if(!update)
		return non;
	else if(l_strcmp(update,l_string(std_cm,"force")) == 0)
		return force;
	else if(l_strcmp(update,l_string(std_cm,"immediate")) == 0)
		return immediate;
	else if(l_strcmp(update,l_string(std_cm,"regist")) == 0)
		return regist;
	return non;
}

EvalType CheckEvalType(L_CHAR * eval)
{
	if(l_strcmp(eval,l_string(std_cm,"on")) == 0)
		return EvalOn;
	else if(l_strcmp(eval,l_string(std_cm,"off")) == 0)
		return EvalOff;

	return 0;
}

XL_SEXP* GetDocument(XL_SEXP* elem)
{
	int i,n;
	XL_SEXP *tmp;
	
	n = car(elem)->integer.data;
	if(n < 0)
	 	n = -n;
	n++;
	for(i = 0,tmp = elem ; i <= n ; i++)
		tmp = cdr(tmp);
	tmp = car(tmp);
	
	return tmp;
}

XL_SEXP* GetScript(XL_SEXP* elem)
{
	int i,n;
	XL_SEXP *tmp;
	
	n = car(elem)->integer.data;
	if(n < 0)
	 	n = -n;
	n++;
	for(i = 0,tmp = elem ; i <= n ; i++)
		tmp = cdr(tmp);
	tmp = car(tmp);
	
	return tmp;
}

