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

XL_SEXP * xl_InsertCompose();
XL_SEXP * xl_DeleteCompose();


typedef struct file_list {
	struct file_list *	next;
	int			dp;
	char *			filename;
} FILE_LIST;

void
init_InsertCompose(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"InsertCompose"),
		get_func_prim(xl_InsertCompose,FO_NORMAL,0,5,5));
	set_env(env,l_string(std_cm,"DeleteCompose"),
		get_func_prim(xl_DeleteCompose,FO_NORMAL,0,3,3));
}

FILE_LIST * get_file_list(int * flag,char * filename)
{
FILE_LIST * ret, ** fp, * f1, * f2;
FILE * fd;
char buf[100];
char fname[100];
int fdp;
char * ptr;
int er;

	*flag = 0;
	ret = 0;
	fp = &ret;
	fd = fopen(filename,"r+");
	if ( fd == 0 ) {
		*flag = 1;
		return 0;
	}
	for ( ; ; ) {
		ptr = fgets(buf,100,fd);
		if ( ptr == 0 )
			break;
		er = sscanf(buf,"%s %i\n",fname,&fdp);
		if ( er < 1 )
			continue;
		if ( er < 2 ) {
			*flag = 1;
			fdp = 0;
		}
		for ( f2 = ret ; f2 ; f2 = f2->next )
			if ( strcmp(f2->filename,fname) == 0 ) {
				*flag = 1;
				goto next;
			}
		f1 = *fp = d_alloc(sizeof(*f1),12);
		f1->next = 0;
		f1->filename = copy_str(fname);
		f1->dp = fdp;
		fp = &f1->next;
	next:	{}
	}
	fclose(fd);
	if ( ret && ret->next )
		for ( f1 = ret ; f1->next ; f1 = f1->next ) {
			if ( f1->dp > f1->next->dp )
				goto sort;
		}
	return ret;
sort:
	*flag = 1;
	for ( f1 = ret ; f1->next ; f1 = f1->next ) {
		if ( f1->dp <= f1->next->dp )
			continue;
		break;
	}
	if ( f1->next == 0 )
		return ret;
	f2 = f1->next;
	f1->next = f2->next;
	for ( fp = &ret ; *fp ; fp = &(*fp)->next ) {
		if ( (*fp)->dp > f2->dp )
			break;
	}
	f2->next = *fp;
	*fp = f2;
	goto sort;
}

FILE_LIST *
sort_file_list(FILE_LIST * ret,int *flag)
{
FILE_LIST * f1, * f2, ** fp;
	if ( ret == 0 )
		return 0;
sort:
	for ( f1 = ret ; f1->next ; f1 = f1->next ) {
		if ( f1->dp <= f1->next->dp )
			continue;
		break;
	}
	if ( f1->next == 0 )
		return ret;
	*flag = 1;
	f2 = f1->next;
	f1->next = f2->next;
	for ( fp = &ret ; *fp ; fp = &(*fp)->next ) {
		if ( (*fp)->dp > f2->dp )
			break;
	}
	f2->next = *fp;
	*fp = f2;
	goto sort;
}

void
free_file_list(FILE_LIST * f)
{
FILE_LIST * f1;
	for ( ; f ; ) {
		f1 = f->next;
		d_f_ree(f);
		f = f1;
	}
}

void
save_file_list(char * filename,FILE_LIST * f)
{
FILE * fd;
	fd = fopen(filename,"w");
	if ( fd == 0 )
		return;
	for ( ; f ; f = f->next )
		fprintf(fd,"%s\t%i\n",f->filename,f->dp);
	fclose(fd);
}

XL_SEXP *
xl_InsertCompose(XLISP_ENV * env,XL_SEXP * s)
{
XL_SEXP * cfile;
XL_SEXP * ins;
XL_SEXP * target;
FILE * fd;
FILE_LIST * f1, ** fp, * f2;
XLISP_ENV * e;
int flag;
STREAM * st;
XL_SEXP * ret1, * ret2;
XL_SEXP * quote_trace();
XL_SEXP * dp;
	cfile = eval(env,get_el(s,1));
	switch ( get_type(cfile) ) {
	case XLT_STRING:
		break;
	case XLT_ERROR:
		return cfile;
	default:
		goto type_missmatch;
	}
	ins = eval(env,get_el(s,2));
	switch ( get_type(ins) ) {
	case XLT_STRING:
		break;
	case XLT_ERROR:
		return ins;
	default:
		goto type_missmatch;
	}
	dp = eval(env,get_el(s,3));
	switch ( get_type(dp) ) {
	case XLT_INTEGER:
		break;
	case XLT_ERROR:
		return dp;
	default:
		goto type_missmatch;
	}
	target = get_el(s,4);
	f1 = get_file_list(&flag,n_string(std_cm,cfile->string.data));
	if ( dp->integer.data < 0 )
		goto next;
	for ( fp = &f1 ; *fp ; fp = &(*fp)->next ) {
		if ( strcmp(n_string(std_cm,ins->string.data),
				(*fp)->filename) == 0 ) {
			if ( (*fp)->dp != dp->integer.data ) {
				flag = 1;
				(*fp)->dp = dp->integer.data;
			}
			goto next;
		}
	}
	flag = 1;
	f2 = *fp = d_alloc(sizeof(*f2),2);
	f2->filename = ln_copy_str(std_cm,ins->string.data);
	f2->dp = dp->integer.data;
	f2->next = 0;
next:
	f1 = sort_file_list(f1,&flag);
	e = new_env(env);
	ret1 = 0;
	for ( f2 = f1 ; f2 ; f2 = f2->next ) {
		st = s_open_file(f2->filename,O_RDONLY,0644);
		if ( st == 0 )
			set_env(e,l_string(std_cm,"elem"),0);
		else	set_env(e,l_string(std_cm,"elem"),
				init_parse(st,
					l_string(std_cm,f2->filename),
					l_string(std_cm,f2->filename)));
		ret1 = cons(quote_trace(e,target),ret1);
	}
	ret2 = 0;
	for ( ; ret1 ; ret1 = cdr(ret1) )
		ret2 = cons(car(ret1),ret2);
	if ( flag == 0 )
		goto end;
	save_file_list(n_string(std_cm,cfile->string.data),f1);
end:
	free_file_list(f1);
	return ret2;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"InsertCompose"),
		0);
}

XL_SEXP *
xl_DeleteCompose(XLISP_ENV * env,XL_SEXP * s)
{
XL_SEXP * cfile;
XL_SEXP * del;
FILE * fd;
FILE_LIST * f1, ** fp, * f2;
int flag;
	cfile = eval(env,get_el(s,1));
	switch ( get_type(cfile) ) {
	case XLT_STRING:
		break;
	case XLT_ERROR:
		return cfile;
	default:
		goto type_missmatch;
	}
	del = eval(env,get_el(s,2));
	switch ( get_type(del) ) {
	case XLT_STRING:
		break;
	case XLT_ERROR:
		return del;
	default:
		goto type_missmatch;
	}
	f1 = get_file_list(&flag,n_string(std_cm,cfile->string.data));
	for ( fp = &f1 ; *fp ;  ) {
		if ( strcmp(n_string(std_cm,del->string.data),
				(*fp)->filename) == 0 ) {
			f2 = *fp;
			*fp = f2->next;
			d_f_ree(f2->filename);
			d_f_ree(f2);
			flag = 1;
		}
		else 	fp = &(*fp)->next;
	}
	f1 = sort_file_list(f1,&flag);
	if ( flag )
		save_file_list(n_string(std_cm,cfile->string.data),f1);
	return 0;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"DeleteCompose"),
		0);
}


