/**********************************************************************
 
	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	"memory_routine.h"
#include	"gbview.h"
#include	"cosmos.h"
#include	"xl.h"
#include	"xlerror.h"
#include	"utils.h"
#include	"lock_level.h"
#include	"win_flame.h"

L_CHAR * gv_redraw_format = 0;
L_CHAR * gv_redraw_quality = 0;

URL view_agent_url;
int view_agent_switch = 0;
int view_agent_ses;
SEM view_agent_session_lock;
extern COSMOS_FLAME cflame;

int gvagent_need_redraw = 0;
int call_sts_cache_valid = 0;

XL_SEXP * xl_gv_flame_switch();
XL_SEXP * xl_win_flame_event();

void
init_gv_flame_switch(XLISP_ENV * env)
{
L_CHAR * str;
	set_env(env,l_string(std_cm,"gv-flame-switch"),
		get_func_prim(xl_gv_flame_switch,FO_APPLICATIVE,0,2,3));
	view_agent_session_lock = new_lock(LL_VIEW_AGENT_SESSION);
}

INLINE XL_SEXP *
view_agent_session(L_CHAR * center_cmd, XL_SEXP * cmd)
{
XL_SEXP * ret;

	lock_task(view_agent_session_lock);
fflush(stdout);
s_printf(s_stdout," -> ");
print_sexp(s_stdout,cmd,0);
s_printf(s_stdout,"\n");
fflush(stdout);

	ret = remote_session(
		gblisp_top_env0,
		view_agent_ses,
		&view_agent_url,
		l_string(std_cm,"gbview"),
		l_string(std_cm,"user"),
		center_cmd,
		List(cmd,-1),
		0,0,1);

s_printf(s_stdout," <- ");
print_sexp(s_stdout,ret,PF_RAW_DISABLE);
s_printf(s_stdout,"\n");
fflush(stdout);

	unlock_task(view_agent_session_lock,"view_agent_session");
	return ret;
}

void
gvagent_redraw()
{
	if ( gvagent_need_redraw ) {
		if ( cflame.ix.type == 0 ) {
			gvagent_need_redraw = 0;
			interface_redraw_func(ET_REDRAW);
		}
	}
}

INLINE XL_SEXP * 
n_get_symbol_with_format(char * name)
{
	XL_SEXP * ret = n_get_symbol(name);
	if ( gv_redraw_format )
		set_attribute(ret,l_string(std_cm,"format"),gv_redraw_format);
	if ( gv_redraw_quality )
		set_attribute(ret,l_string(std_cm,"quality"),gv_redraw_quality);
	return ret;
}

XL_SEXP *
xl_gv_flame_switch(
	XLISP_ENV * e,
		XL_SEXP * s,
		XLISP_ENV * a_e,
		XL_SYM_FIELD * sf)
{
XL_SEXP * mode, * url, * result, * initial;
L_CHAR * parameter, * peripheral, * format, * quality;


printf("FLAME SWITCH\n");
	parameter = get_sf_attribute(sf,l_string(std_cm,"parameter"));		
	peripheral = get_sf_attribute(sf,l_string(std_cm,"peripheral"));	
	format = get_sf_attribute(sf,l_string(std_cm,"format"));	
	quality = get_sf_attribute(sf,l_string(std_cm,"quality"));	

	if ( format )
		gv_redraw_format = ll_copy_str(format);
	if ( quality )
		gv_redraw_quality = ll_copy_str(quality);

	mode = get_el(s,1);
	if ( get_type(mode) != XLT_INTEGER )
		goto type_missmatch;
	if ( mode->integer.data == 0 ) {
		view_agent_switch = 0;
		return 0;
	}
	
	url = get_el(s,2);
	if ( get_type(url) != XLT_STRING )
		goto type_missmatch;
	if ( get_url2(&view_agent_url,url->string.data) < 0 )
		goto param_error;
	
	set_env(gblisp_top_env0, l_string(std_cm,"win-flame-event"),
			get_func_prim(xl_win_flame_event,FO_APPLICATIVE,0,3,3));

	view_agent_ses = open_session(SEST_OPTIMIZE);
	view_agent_switch = 1;
	gc_push(0,0,"xl_gv_flame_switch");
	initial = n_get_symbol("gv-flame-initial");
	if ( parameter )
		set_attribute(initial,l_string(std_cm,"parameter"),parameter);
	if ( peripheral )
		set_attribute(initial,l_string(std_cm,"peripheral"),peripheral);
	result = view_agent_session(l_string(std_cm,"gv-flame-initial"),
		List(initial,-1));
	if ( get_type(result) == XLT_ERROR ) {
print_sexp(s_stdout,result,0);
ss_printf("\n");
		er_panic("gv-flame-initial failure");
	}
	gc_pop(0,0);
	new_tick(gvagent_redraw,1,0);
	return get_integer(view_agent_ses,0);

type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"gv-flame-switch"),
		List(n_get_string("type missmatch"),
			-1));
param_error:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"gv-flame-switch"),
		List(n_get_string("cannot resolve url"),
			-1));	
}

XL_SEXP *
xl_win_flame_event(
	XLISP_ENV * e,
	XL_SEXP * s)
{
GBVIEW_PLANE gbp;
GBVIEW_STATUS sts;
XL_SEXP * type, * w;

	type = get_el(s,1);
	if ( get_type(type) != XLT_INTEGER )
		goto type_missmatch;
		
print_sexp(s_stdout,s,PF_RAW_DISABLE);
s_printf(s_stdout,"\n");

	switch ( type->integer.data ) {
	case ET_REDRAW:
		gvagent_need_redraw = 1;
		break;
	case ET_CLICK:
		w = get_el(s,2);
		if ( list2gbp(w,&gbp) == 0 )
			goto param_error;
		interface_click_func(type,&gbp);
		wf_free_plane(&gbp);
		break;
	case ET_INFO:
		w = get_el(s,2);
		if ( list2gvstatus(w,&sts) < 0 )
			goto param_error;
		if ( sts.flags & (SF_REFERENCE | SF_ERROR) )
			interface_info_func(type,&sts);	// SF_INFOLIST is not supported
		wf_free_status(&sts);
		break;
	default:
		er_panic("xl_win_flame_event");
	}
	return 0;
	
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"win-flam-event"),
		List(n_get_string("type missmatch"),
			-1));
param_error:
	fflush(stdout);
	print_sexp(s_stdout,s,0);
	s_printf(s_stdout," - INVALID PARAM\n");
	
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"win-flam-event"),
		List(n_get_string("invalid event parameter"),
			-1));
}


void call_wf_status(GBVIEW_STATUS * sts, int call_sts_cache_flag)
{
XL_SEXP * result;
static GBVIEW_STATUS sts_cache;
INDICATE * in, * in1;
GBVIEW_FLAME * gf;

	gf = wf_next_gf(0,GVFM_LIVE);

	if ( view_agent_switch == 0 ) {
		wf_status(gf,sts);
		return;
	}

	if ( call_sts_cache_flag == CALL_STS_CACHE_NORMAL && call_sts_cache_valid ) {
		lock_task(view_agent_session_lock);
		*sts = sts_cache;
		sts->indicate = 0;
		for ( in = sts_cache.indicate ; in ; in = in->next ) {
			in1 = d_alloc(sizeof(*in1));
			*in1 = *in;
			copy_url(&in1->url,&in->url);
			in1->next = sts->indicate;
			sts->indicate = in1;
		}
		if ( sts_cache.flame_base_unit )
			sts->flame_base_unit = ll_copy_str(sts_cache.flame_base_unit);
		unlock_task(view_agent_session_lock,"call_wf_status(1)");
		return;
	}

	gc_push(0,0,"call_wf_status");
	result = view_agent_session(l_string(std_cm,"gv-flame-status"),
			List(n_get_symbol("gv-flame-status"),-1));

	lock_task(view_agent_session_lock);
	list2gvstatus(result, sts);
	if ( sts->layer_nos ) {
		wf_free_status(&sts_cache);
		sts_cache = *sts;
		sts_cache.indicate = 0;
		for ( in = sts->indicate ; in ; in = in->next ) {
			in1 = d_alloc(sizeof(*in1));
			*in1 = *in;
			copy_url(&in1->url,&in->url);
			in1->next = sts_cache.indicate;
			sts_cache.indicate = in1;
		}
		if ( sts->flame_base_unit )
			sts_cache.flame_base_unit = ll_copy_str(sts->flame_base_unit);
		call_sts_cache_valid = 1;
	}
	unlock_task(view_agent_session_lock,"call_wf_status(2)");
	gc_pop(0,0);
}

int call_wf_set_status(GBVIEW_STATUS * e)
{
XL_SEXP * result;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	
	if ( view_agent_switch == 0 ) {
		return wf_set_status(gf,e);
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_set_status");

	result = view_agent_session(l_string(std_cm,"gv-flame-set-status"),
				List(n_get_symbol("gv-flame-set-status"),
					List(n_get_symbol("quote"),gvstatus2list(e),-1),
					-1));
	if ( get_type(result) == XLT_INTEGER )
		ret = result->integer.data;
	else
		ret = 0;
	gc_pop(0,0);

	return ret;
}

int call_wf_click(GBVIEW_STATUS * sts,GBVIEW_PLANE * p,int x,int y)
{
XL_SEXP * result, * seq;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	
	if ( view_agent_switch == 0 ) {
		return wf_click(gf,sts,p,x,y);
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_set_status");
	result = view_agent_session(l_string(std_cm,"gv-flame-click"),
		List(n_get_symbol_with_format("gv-flame-click"),
		get_integer(x,0),get_integer(y,0),-1));
	ret = 0;
	if ( get_type(result) != XLT_ERROR ) {
		seq = car(result);
		if ( get_type(seq) == XLT_INTEGER )
			ret = seq->integer.data;
		if ( ret )
			list2gbp(car(cdr(cdr(result))),p);
		list2gvstatus(car(cdr(result)),sts);
	}
	else {
		fflush(stdout);
		s_printf(s_stdout,"gv-flalme-click -> ");
		print_sexp(s_stdout,result,0);	
		s_printf(s_stdout,"\n");
	}
	gc_pop(0,0);
	return ret;
}

int call_wf_zoom(GBVIEW_PLANE * p,REAL1 zoom)
{
int ow, oh;
int ret;
XL_SEXP * result;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	
	if ( view_agent_switch == 0 ) {
		return wf_zoom(gf,p,zoom);
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_zoom");
	result = view_agent_session(l_string(std_cm,"gv-flame-zoom"),
		List(n_get_symbol("gv-flame-zoom"),
			get_floating(zoom,0),-1));
	if ( get_type(result) != XLT_INTEGER ) {
		gc_pop(0,0);
		return 0;
	}
	ret = result->integer.data;
	gc_pop(0,0);
	
	if ( p ) {
		ow  = cflame.im->vimage.w;
		oh  = cflame.im->vimage.h;
		p->h.type = GPT_ZOOM;
		p->h.seq = ret;
		p->z.index_x = d_alloc(sizeof(int)*ow);
		p->z.index_y = d_alloc(sizeof(int)*oh);
		wf_make_zoom_index(p->z.index_x,p->z.index_y,zoom,ow,oh);
	}
	return ret;
}

int call_wf_move(VPOINT from,VPOINT to)
{
XL_SEXP * result;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);

	if ( view_agent_switch == 0 ) {
		return wf_move(gf,from,to);
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_move");
	result = view_agent_session(l_string(std_cm,"gv-flame-move"),
		List(n_get_symbol("gv-flame-move"),
			get_integer(from.x,0),
			get_integer(from.y,0),
			get_integer(to.x,0),
			get_integer(to.y,0),
			-1));
	if ( get_type(result) == XLT_INTEGER )
		ret = result->integer.data;
	else
		ret = 0;
	gc_pop(0,0);
	return ret;
}

int call_wf_rotate(GB_POINT from,GB_POINT to)
{
XL_SEXP * result;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	
	if ( view_agent_switch == 0 ) {
		return wf_rotate(gf,from,to);
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_rotate");
	result = view_agent_session(l_string(std_cm,"gv-flame-rotate"),
		List(n_get_symbol("gv-flame-rotate"),
			get_integer(from.x,0),
			get_integer(from.y,0),
			get_integer(to.x,0),
			get_integer(to.y,0),
			-1));
	if ( get_type(result) == XLT_INTEGER )
		ret = result->integer.data;
	else
		ret = 0;
	gc_pop(0,0);
	return ret;
}

int call_wf_redraw(GBVIEW_PLANE * p,int x,int y,int w,int h)
{
XL_SEXP * result, * seq;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	
	if ( view_agent_switch == 0 ) {
		return wf_redraw(gf,p,x,y,w,h);
	}

	gc_push(0,0,"call_wf_redraw");
	result = view_agent_session(l_string(std_cm,"gv-flame-redraw"),
		List(n_get_symbol_with_format("gv-flame-redraw"),
			get_integer(x,0),
			get_integer(y,0),
			get_integer(w,0),
			get_integer(h,0),
			-1));
/*
	if ( get_type(result) != XLT_PAIR ) {
		fflush(stdout);
		s_printf(s_stdout, "gv-flame-redraw -> ");
		print_sexp(s_stdout, result, 0);
		s_printf(s_stdout, "\n");
		fflush(stdout);
	}
*/
	seq = car(result);
	if ( get_type(seq) == XLT_INTEGER )
		ret = seq->integer.data;
	else
		ret = 0;
	if ( ret != 0 ) {
		list2gbp(result,p);
	}
	else {
		p->h.type = GPT_REDRAW;
		p->h.seq = 0;
		p->r.r.tl.x = p->r.r.br.x = 0;
		p->r.r.tl.y = p->r.r.br.y = 0;
		p->r.plane = 0;
		ret = 0;
	}
	gc_pop(0,0);
	return ret;
}

void call_wf_indicate(GBVIEW_STATUS * sts,int x,int y,int button)
{
XL_SEXP * result;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	
	if ( view_agent_switch == 0 ) {
		wf_indicate(gf,sts,x,y,button);
		return;
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_indicate");
	result = view_agent_session(l_string(std_cm,"gv-flame-point-status"),
		List(n_get_symbol("gv-flame-point-status"),
			get_integer(x,0),
			get_integer(y,0),
			-1));
	if ( sts && get_type(result) == XLT_PAIR )
		list2gvstatus(result,sts);
	gc_pop(0,0);
}

int call_wf_purge_select()
{
XL_SEXP * result;
int ret;
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	if ( view_agent_switch == 0 ) {
		return wf_purge_select(gf);
	}
	
	call_sts_cache_valid = 0;

	gc_push(0,0,"call_wf_purge_select");
	result = view_agent_session(l_string(std_cm,"gv-flame-purge-select"),
		cons(n_get_symbol("gv-flame-purge-select"),0));
	if ( get_type(result) == XLT_INTEGER )
		ret = result->integer.data;
	else
		ret = 0;
	gc_pop(0,0);
	return ret;
}

void call_wf_get_coordinate_info(L_CHAR ** name,int * rid,GB_POINT * ptr,int ptr_len)
{
GBVIEW_FLAME * gf;
	gf = wf_next_gf(0,GVFM_LIVE);
	if ( view_agent_switch == 0 ) {
		wf_get_coordinate_info(gf,name,rid,ptr,ptr_len);
		return;
	}
	
	*rid = 0;
	return;
}

