/**********************************************************************
 
	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	"memory_debug.h"
#include	"memory_routine.h"
#include	"xlerror.h"
#include	"pdb.h"
#include	"utils.h"
#include	"task.h"
#include	"search.h"

void gc_gb_sexp();

typedef struct si_work {
	STREAM *	info_file;
	char *		infofilename;
	int		if_ptr;
	unsigned int	linear_offset;
	unsigned int	linear_length;
	char		encoding[ENCODING_SIZE];
	L_CHAR *	unit;
} SI_WORK;

int pdbp_file_header_info();
int pdbp_2d_draw_header_info();


int (*pdbp_table_info[])() = {
	0,
	pdbp_file_header_info,
	pdbp_2d_draw_header_info,
	0,
	0,
	0,
	0,
	0
};


int
pdbp_file_header_info(PDB * p,
	unsigned int nextofs,
	void * opt,
	PN_FILE_HEADER * f,
	SI_WORK * w)
{
REQUEST * opt2;
	if ( f->type != FT_2D_DRAW )
		return -1;
	if ( strcmp(f->version,VERSION) != 0 )
		return -1;
	w->linear_offset = f->linear;
	w->linear_length = f->linear_length;
	strcpy(w->encoding,f->encoding);
	insert_request(p,nextofs,0);
	return 1;
}

int
pdbp_2d_draw_header_info(PDB * p,
	unsigned int nextofs,
	REQUEST * opt,
	PN_2D_DRAW_HEADER * d,
	SI_WORK * w)
{
REQUEST * opt2;
	strcpy(&w->infofilename[w->if_ptr],d->infofile);
	w->info_file = s_open_file(w->infofilename,O_RDONLY);
	w->unit = nl_copy_str(std_cm,d->unit);
	if ( w->info_file == 0 )
		return -1;
	return 0;
}

XL_SEXP *
search_info(char * filename,XL_SEXP * id_list,XL_FILE * f,int line)
{
PDB * p;
XL_SEXP * ret;
int er;
SI_WORK sw;
unsigned int ofs;
int id,code;
XL_SEXP * info;
int i;
XL_SEXP * i_header;
char * status;
char buf[32];
CODE_INDEX ci;


	sw.infofilename = d_alloc(strlen(filename) + INFO_FILENAME_SIZE);
	strcpy(sw.infofilename,filename);
	for ( i = strlen(filename)-1 ; i >= 0 ; i -- )
		if ( sw.infofilename[i] == '/' ) {
			i ++;
			break;
		}
	if ( i < 0 )
		i = 0;
	sw.if_ptr = i;
	p = open_pdb(filename,O_RDONLY,0,0);

	insert_request(p,0,0);
	for ( ; p->request || p->next_request ; ) {
		er = delete_request(p,pdbp_table_info,&sw);
		if ( er < 0 ) {
			if ( er == E_DR_NO_REQUEST ) {
				break;
			}
			d_f_ree(sw.infofilename);
			return get_error(
				f,line,
				XLE_PROTO_INV_RESOURCE,
				l_string(std_cm,"GetInfo"),
				List(
					n_get_string(
						"invalid file format"),
					get_integer(er,0),
					-1));
		}
	}
/*
ss_printf("infofile = %s ",sw.infofilename);
*/
	ret = 0;
	for ( ; get_type(id_list) ; id_list = cdr(id_list) ) {
		code = car(id_list)->integer.data;
		sprintf(buf,"%i",code);
		id = code/NO_PITCH;
		ofs = id*sizeof(CODE_INDEX);
		if ( ofs > sw.linear_length - sizeof(CODE_INDEX) ) {
			status = "overrun-error";
			goto err;
		}
		ofs += sw.linear_offset;
		d_lseek(p,ofs,SEEK_SET);
		er = d_read(p,&ci,sizeof(ci));
		if ( er != sizeof(ci) ) {
			status = "read-error";
			goto err;
		}
		change_endian_code_index(&ci);
		s_seek_file(sw.info_file,ci.fofs,SEEK_SET);
		gc_push(0,0,"search_info");
		info = init_parse(sw.info_file,
			l_string(std_cm,sw.infofilename),
			l_string(std_cm,sw.infofilename));
		if ( info && info->h.file->st )
			_q_xml_encoding(info,l_string(std_cm,sw.encoding));
		
		if ( get_type(info) != XLT_PAIR ) {
			gc_pop(0,0);
			status = "inf-file-format-error";

ss_printf("offset = %i %s ",ci.fofs,sw.infofilename);
print_sexp(s_stdout,info,0);
ss_printf("\n");
			goto err;
		}
		get_type(cdr(info));
		info = car(info);
		if ( get_type(info) == XLT_ERROR )
			status = "error";
		else	status = "ok";
		gc_pop(info,gc_gb_sexp);
	end:
		i_header = get_symbol(l_string(std_cm,"i"));
		set_attribute(i_header,
			l_string(std_cm,"code"),
			l_string(std_cm,buf));
		set_attribute(i_header,
			l_string(std_cm,"sts"),
			l_string(std_cm,status));
		ret = cons(
			List(i_header,
			  List(get_symbol(l_string(std_cm,"mr")),
			    List(
			      List(	get_floating(ci.minrect.tl.x,sw.unit),
					get_floating(ci.minrect.tl.y,sw.unit),
					-1),
			      List(	get_floating(ci.minrect.br.x,sw.unit),
					get_floating(ci.minrect.br.y,sw.unit),
					-1),
				-1),
				-1),
			   info,
				-1),
			ret);
		continue;
	err:
		i_header = get_symbol(l_string(std_cm,"i"));
		set_attribute(i_header,
			l_string(std_cm,"code"),
			l_string(std_cm,buf));
		set_attribute(i_header,
			l_string(std_cm,"sts"),
			l_string(std_cm,status));
		ret = cons(List(i_header,-1),ret);
	}
	close_pdb(p);
	d_f_ree(sw.infofilename);
	d_f_ree(sw.unit);
	return ret;
}
