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

typedef struct ws_work {
	int 			mode;
#define WSWM_UN			0
#define WSWM_ALTA		1
	FONT_PRI_NAME **	target;
	FONT_PRI_NAME *		un;
	FONT_PRI_NAME * 	ja;
	FONT_PRI_NAME * 	tw;
	FONT_PRI_NAME * 	cn;
	FONT_PRI_NAME * 	kr;
} WS_WORK;

XL_SEXP * xl_WritingStyle();
void free_font_pri_name(FONT_PRI_NAME * f);
void free_ws_work(WS_WORK * w);
void insert_fpn(FONT_PRI_NAME ** target,FONT_PRI_NAME * fpn);
XL_SEXP * xl_Font(WS_WORK * w,XL_SEXP * s);
XL_SEXP * xl_Locale(WS_WORK * w,XL_SEXP * s);



void
init_WritingStyle(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"WritingStyle"),
		get_func_prim(xl_WritingStyle,FO_NORMAL,0,1,-1));
}

XL_SEXP * ws_loop();

void
free_font_pri_name(FONT_PRI_NAME * f)
{
int i;
	for ( i = 0 ; f[i].font ; i ++ )
		d_f_ree(f[i].font);
	d_f_ree(f);
}


void
free_ws_work(WS_WORK * w)
{
	if ( w->un )
		free_font_pri_name(w->un);
	if ( w->ja )
		free_font_pri_name(w->ja);
	if ( w->tw )
		free_font_pri_name(w->tw);
	if ( w->cn )
		free_font_pri_name(w->cn);
	if ( w->kr )
		free_font_pri_name(w->kr);
}

void
insert_fpn(FONT_PRI_NAME ** target,FONT_PRI_NAME * fpn)
{
FONT_PRI_NAME * t;
int len;
	if ( *target == 0 ) {
		*target = t = d_alloc(sizeof(*t)*2);
		*t = *fpn;
		t->font = ll_copy_str(fpn->font);
		t[1].font = 0;
	}
	else {
		len = fpn_len(*target);
		t = *target = d_re_alloc(*target,
				sizeof(*t)*(len+2));
		t[len] = *fpn;
		t[len].font = ll_copy_str(fpn->font);
		t[len+1].font = 0;
	}
}


XL_SEXP *
xl_Font(WS_WORK * w,XL_SEXP * s)
{
L_CHAR * fontname;
L_CHAR * method;
L_CHAR * lcz0,* mask0;
L_CHAR * lcz1,* mask1;
FONT_PRI_NAME fpn;
	fontname = get_sf_attribute(s->symbol.field,
				l_string(std_cm,"fontname"));
	method = get_sf_attribute(s->symbol.field,
				l_string(std_cm,"method"));
	lcz0 = get_sf_attribute(s->symbol.field,
				l_string(std_cm,"lcz0"));
	mask0 = get_sf_attribute(s->symbol.field,
				l_string(std_cm,"mask0"));
	lcz1 = get_sf_attribute(s->symbol.field,
				l_string(std_cm,"lcz1"));
	mask1 = get_sf_attribute(s->symbol.field,
				l_string(std_cm,"mask1"));
	if ( fontname == 0 ) {	
		return get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_INV_PARAM,
			l_string(std_cm,"WritingStyle:Font"),
			n_get_string("fontname is required"));
	}
	fpn.font = fontname;
	if ( method == 0 )
		fpn.method = FST_JUST;
	else if ( l_strcmp(method,l_string(std_cm,"just")) == 0 )
		fpn.method = FST_JUST;
	else if ( l_strcmp(method,l_string(std_cm,"nearly")) == 0 )
		fpn.method = FST_NEARLY;
	else if ( l_strcmp(method,l_string(std_cm,"small")) == 0 )
		fpn.method = FST_SMALL;
	else if ( l_strcmp(method,l_string(std_cm,"large")) == 0 )
		fpn.method = FST_LARGE;
	else	return get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_INV_PARAM,
			l_string(std_cm,"WritingStyle:Font"),
			n_get_string("method value"));
	if ( lcz0 == 0 ) {
		fpn.lcz[0] = LCC_ERROR;
	}
	else {
		sscanf(n_string(std_cm,lcz0),"%li",&fpn.lcz[0]);
	}
	if ( mask0 == 0 ) {
		fpn.mask[0] = LCZM_ALL;
	}
	else {
		sscanf(n_string(std_cm,mask0),"%li",&fpn.mask[0]);
	}

	if ( lcz1 == 0 ) {
		fpn.lcz[1] = LCC_ERROR;
	}
	else {
		sscanf(n_string(std_cm,lcz1),"%li",&fpn.lcz[1]);
	}
	if ( mask1 == 0 ) {
		fpn.mask[1] = LCZM_ALL;
	}
	else {
		sscanf(n_string(std_cm,mask1),"%li",&fpn.mask[1]);
	}

	if ( w->mode == WSWM_UN ) {
		insert_fpn(&w->un,&fpn);
	}
	else {
		if ( w->target )
			insert_fpn(w->target,&fpn);
		else {
			insert_fpn(&w->ja,&fpn);
			insert_fpn(&w->kr,&fpn);
			insert_fpn(&w->tw,&fpn);
			insert_fpn(&w->cn,&fpn);
		}
	}
	return 0;
}


XL_SEXP *
xl_Locale(WS_WORK * w,XL_SEXP * s)
{
XL_SEXP * sym, * ret;
L_CHAR * locale;
FONT_PRI_NAME ** target_backup;
	sym = car(s);
	locale = get_sf_attribute(sym->symbol.field,l_string(std_cm,"locale"));
	if ( locale == 0 ) {
		return get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_INV_PARAM,
			l_string(std_cm,"WritingStyle:Locale"),
			n_get_string("locale is required"));
	}
	if ( w->mode == WSWM_UN ) {
		w->mode = WSWM_ALTA;
		w->ja = copy_font_pri_name(w->un);
		w->kr = copy_font_pri_name(w->un);
		w->cn = copy_font_pri_name(w->un);
		w->tw = copy_font_pri_name(w->un);
		free_font_pri_name(w->un);
		w->un = 0;
		target_backup = 0;
	}
	else {
		target_backup = w->target;
	}
	if ( l_strcmp(locale,l_string(std_cm,"ja")) == 0 )
		w->target = &w->ja;
	else if ( l_strcmp(locale,l_string(std_cm,"cn")) == 0 )
		w->target = &w->cn;
	else if ( l_strcmp(locale,l_string(std_cm,"kr")) == 0 )
		w->target = &w->kr;
	else if ( l_strcmp(locale,l_string(std_cm,"tw")) == 0 )
		w->target = &w->tw;
	else	w->target = 0;
	ret = ws_loop(w,cdr(s));
	w->target = target_backup;
	if ( get_type(ret) == XLT_ERROR )
		return ret;
	return 0;
}


XL_SEXP *
ws_loop(WS_WORK * w,XL_SEXP * s)
{
XL_SEXP * r, * sym, * ret;
	ret = 0; 
	for ( ; get_type(s) == XLT_PAIR ; s = cdr(s) ) {
		r = car(s);
		if ( get_type(r) != XLT_PAIR )
			continue;
		sym = car(r);
		if ( get_type(sym) != XLT_SYMBOL )
			goto type_missmatch1;
		if ( l_strcmp(sym->symbol.data,
				l_string(std_cm,"Font")) == 0 )
			ret = xl_Font(w,sym);
		else if ( l_strcmp(sym->symbol.data,
				l_string(std_cm,"Locale")) == 0 )
			ret = xl_Locale(w,r);
		else 	goto type_missmatch2;
		if ( get_type(ret) == XLT_ERROR )
			return ret;
	}
	if ( get_type(s) == XLT_ERROR )
		return s;
	return ret;
type_missmatch1:
	return get_error(
		r->h.file,
		r->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"WritingStyle:loop 1"),
		r);
type_missmatch2:
	return get_error(
		r->h.file,
		r->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"WritingStyle:loop 2"),
		r);
}


XL_SEXP *
xl_WritingStyle(XLISP_ENV * env,XL_SEXP * _s,XLISP_ENV * a,XL_SYM_FIELD * sf)
{
L_CHAR * style,* parent, * child;
WS_WORK w;
XL_SEXP * ret, * s;
LC_WRITING_STYLE * ws,* ws2;
	s = _s;
	style = get_sf_attribute(sf,l_string(std_cm,"stylename"));
	if ( style == 0 )
		goto attr_req;
	w.un = w.kr = w.ja = w.cn = w.tw = 0;
	w.target = 0;
	w.mode = WSWM_UN;
	s = gb_quote_trace(env,cdr(s),0);
	ret = ws_loop(&w,s);
	if ( get_type(ret) == XLT_ERROR ) {
		free_ws_work(&w);
		return ret;
	}
	ws = get_ws(style);
	if ( ws == 0 ) {
		ws = new_ws(style,
			w.un,
			w.ja,
			w.tw,
			w.cn,
			w.kr);
	}
	else {
		if ( list_length(_s) != 1 )
			goto invalid_arg;
	}
	child = get_sf_attribute(sf,l_string(std_cm,"childof"));
	if ( child ) {
		ws2 = get_ws(child);
		if ( ws2 == 0 )
			goto invalid_stylename;
		set_ws_child(ws2,ws);
	}
	parent = get_sf_attribute(sf,l_string(std_cm,"parentof"));
	if ( parent ) {
		ws2 = get_ws(parent);
		if ( ws2 == 0 )
			goto invalid_stylename;
		set_ws_child(ws,ws2);
	}
	free_ws_work(&w);
	return 0;
attr_req:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"WritingStyle"),
		n_get_string("stylename is required"));
invalid_stylename:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"WritingStyle"),
		n_get_string("invalid stylename (parentof/childof)"));
invalid_arg:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"WritingStyle"),
		n_get_string("invalid stylename argment (Font)"));
}


