/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.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 <stdlib.h>

#include "v/VTableView.h"
#include "v/vobj_utils.h"
#include "StDisposer.h"

extern "C" {
#include "xl.h"
#include "xlerror.h"

XL_SEXP *
vobj_VTableView(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);
XL_SEXP *
vobj_ResizeTable(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf);

XL_SEXP *
vobj_VTableView(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	VTableView *obj;
	XL_SEXP *_ref;
	VObjectStatus _sts;
	struct VTableView::table_set ts;
	short rows,cols;

	L_CHAR *l_rows  = get_sf_attribute(sf, l_string(std_cm, "rows"));
	L_CHAR *l_cols  = get_sf_attribute(sf, l_string(std_cm, "cols"));
	if ( ( l_rows && l_cols ) ) {
		rows  = atoi(n_string(std_cm, l_rows));
		cols  = atoi(n_string(std_cm, l_cols));
		ts.rows = rows;
		ts.cols = cols;
		_ref = get_refered_object<VTableView>
				(&obj,env,arg,sf,VO_TBLV,"VTableView",&_sts,0,(void*)&ts);
	}
	else {
		rows = cols = 0;
		_ref = get_refered_object<VTableView>
				(&obj,env,arg,sf,VO_TBLV,"VTableView",&_sts,0,0);
	}
	if ( get_type(_ref) != XLT_INTEGER )
		return _ref;

	if ( !( l_rows && l_cols ) )
		return vobj_get_error(initial_VExError(V_ER_PARAM,0,0), arg);

	XL_SEXP *ret = 0;
	short row, col;
	int i, j;
/*
	VObjectStatus sts;
	VObject::FreeList *free_list;
	int flags = get_sts_from_sf(env,&sts,0, sf, &free_list);
	VExError err;

	XL_SEXP *p = eval(env, n_get_symbol("__parent"));
	if ( get_type(p) == XLT_ERROR )
		return p;
	if ( get_type(p) != XLT_INTEGER )
		return vobj_get_error(initial_VExError(V_ER_PARENT,0,0), arg);
	VObject *parent = VObject::get_object_by_id(p->integer.data);
	
	sts.parent = parent;
	flags |= VSF_PARENT;
	
	VTableView *obj = VTableView::create(&sts, flags, rows, cols, &err);
	if ( err.code != V_ER_NO_ERR )
		return vobj_get_error(err, arg);
	obj->free_on_release_list(free_list);
*/
	obj->get_status(&_sts, VSF_ID);

	char *occupied = new char[rows*cols];
	for ( i = 0 ; i < rows*cols ; i++ )
		occupied[i] = 0;
		
	{
		StDisposer<char> sd_oc(occupied);
	
		row = -1;
		for ( arg = cdr(arg) ; get_type(arg) == XLT_PAIR ; arg = cdr(arg) ) {

			XL_SEXP *tr = car(arg);
			if ( get_type(tr) != XLT_PAIR )
				goto type_missmatch;
			XL_SEXP *tr_s = car(tr);
			if ( get_type(tr_s) != XLT_SYMBOL
					|| l_strcmp(tr_s->symbol.data, l_string(std_cm, "TR")) != 0 )
				return get_error(
					arg->h.file,
					arg->h.line,
					XLE_PROTO_INV_PARAM,
					l_string(std_cm,"VTableView"),
					n_get_string("TR is expected"));
			
			row++;
			if ( row >= rows )
				return get_error(
					arg->h.file,
					arg->h.line,
					XLE_PROTO_INV_PARAM,
					l_string(std_cm,"VTableView"),
					n_get_string("too many TR"));
			col = -1;
			
			for ( tr = cdr(tr) ; get_type(tr) == XLT_PAIR ; tr = cdr(tr) ) {
				XL_SEXP *td = car(tr);
				if ( get_type(td) != XLT_PAIR )
					goto type_missmatch;
				XL_SEXP *td_s = car(td);
				if ( get_type(td_s) != XLT_SYMBOL
						|| l_strcmp(td_s->symbol.data, l_string(std_cm, "TD")) != 0 )
					return get_error(
						arg->h.file,
						arg->h.line,
						XLE_PROTO_INV_PARAM,
						l_string(std_cm,"VTableView"),
						n_get_string("TD is expected"));
				L_CHAR *l_rs  = get_symbol_field(td_s, l_string(std_cm, "rowspan"));
				L_CHAR *l_cs  = get_symbol_field(td_s, l_string(std_cm, "colspan"));
				short rowspan = l_rs ? atoi(n_string(std_cm, l_rs)) : 1;
				short colspan = l_cs ? atoi(n_string(std_cm, l_cs)) : 1;

				do {
					col++;
					if ( col >= cols )
						return get_error(
							arg->h.file,
							arg->h.line,
							XLE_PROTO_INV_PARAM,
							l_string(std_cm,"VTableView"),
							n_get_string("too many TD"));
				} while ( occupied[row*cols + col] );
				
				XL_SEXP *res = vobj_eval_child(_sts.id, env, td);
				if ( get_type(res) == XLT_ERROR )
					return res;

				for ( XL_SEXP *child = res ; get_type(child) == XLT_PAIR ; child = cdr(child) ) {
					XL_SEXP *list = car(child);
					if ( get_type(list) != XLT_PAIR )
						goto type_missmatch;
					XL_SEXP *c_id = get_el(list, 1);
					if ( get_type(c_id) != XLT_INTEGER )
						goto type_missmatch;
					VObject *c_obj = VObject::get_object_by_id(c_id->integer.data);
					if ( c_obj == 0 )
						return vobj_get_error(initial_VExError(V_ER_PARENT,0,0), arg);
					obj->attach_child(c_obj, row, col, rowspan, colspan);
					for ( j = row ; j < row+rowspan ; j++ )
						for ( i = col ; i < col+colspan ; i++ )
							occupied[i+cols*j] = 1;
						
	printf("attach child %d %d %d %d\n", row, col, rowspan, colspan);
				}
				
				ret = append(ret, res);
			}
			if ( get_type(tr) ) {
				arg = tr;	// to error check;
				break;
			}
		}
	}
	
	if ( get_type(arg) == XLT_ERROR )
		return arg;
	if ( get_type(arg) )
		goto type_missmatch;

	return vobj_get_id_list(_ref->integer.data, ret, sf,0);

type_missmatch:
	return get_error(
		arg->h.file,
		arg->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm, "VTableView"),
		n_get_string("type missmatch"));
}

XL_SEXP *
vobj_ResizeTable(XLISP_ENV *env, XL_SEXP *arg, XLISP_ENV *a, XL_SYM_FIELD *sf)
{
	XL_SEXP *target = get_el(arg, 1);
	XL_SEXP *rows = get_el(arg, 2);
	XL_SEXP *cols = get_el(arg, 3);
	if ( get_type(target) != XLT_INTEGER || get_type(rows) != XLT_INTEGER ||
				get_type(cols) != XLT_INTEGER )
		return get_error(
			arg->h.file,
			arg->h.line,
			XLE_SEMANTICS_TYPE_MISSMATCH,
			l_string(std_cm,"ResizeTable"),
			n_get_string("type missmatch"));
	VTableView *obj = dynamic_cast<VTableView*>(
		VObject::get_object_by_id(target->integer.data));
	if ( obj == 0 )
		return vobj_get_error(initial_VExError(V_ER_NOT_FOUND,0,0), arg);
	
	VExError err = obj->resize_table(rows->integer.data, cols->integer.data);
	return vobj_get_error(err, arg);
}

void
init_VTableView(XLISP_ENV *env)
{
	set_env(env,l_string(std_cm,"VTableView"),
		get_func_prim((XL_SEXP*(*)())vobj_VTableView,FO_NORMAL,0,1,-1));

	set_env(env,l_string(std_cm,"ResizeTable"),
		get_func_prim((XL_SEXP*(*)())vobj_ResizeTable,FO_APPLICATIVE,0,4,4));
}


} // extern "C"
