/**********************************************************************
 
	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/VEditText.h"
#include	"v/VWindow.h"
#include	"machine/v_object.h"

extern "C" {
#include	"memory_debug.h"
#include	"utils.h"
void setup_edit_menu(GtkEditable *editable, VMenuItem *items);
#include "machine/v_object.h"
}

extern "C" void
on_insert_text_integer_only(
	GtkEditable *editable,
	const gchar	*text,
	gint			length,
	gint			*position,
	gpointer		data)
{
	int i, j, beep=FALSE;
	gchar *result = g_new(gchar, length);
	
	j = 0;
	for ( i = 0 ; i < length ; i++ )
		if ( text[i] >= '0' && text[i] <= '9' )
			result[j++] = text[i];
		else
			beep = TRUE;
	if ( beep )
		gdk_beep();
	
	gtk_signal_handler_block_by_func(GTK_OBJECT(editable),
		GTK_SIGNAL_FUNC(on_insert_text_integer_only), data);
	gtk_editable_insert_text(editable, result, j, position);
	gtk_signal_handler_unblock_by_func (GTK_OBJECT(editable),
		GTK_SIGNAL_FUNC(on_insert_text_integer_only), data);
	
	gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
	
	g_free(result);
}

extern "C" gboolean
v_edit_text_focused(GtkEditable *widget, GdkEventFocus *event, VEditText* obj)
{
	obj->focus_event(event->in);
	return false;
}

VInfo *
v_edit_text_create_do(VEditText *obj, VEditText::edit_text_set *set, bool integer_only)
{
	VInfo *info = gtk_entry_new_with_max_length(set->max_len);
	gtk_entry_set_width_chars(GTK_ENTRY(info), set->min_len);
	g_object_ref(info);
	g_signal_connect(info, "changed", G_CALLBACK(::descriptor_changed), obj);
	if ( integer_only )
		g_signal_connect(info, "insert_text", G_CALLBACK(on_insert_text_integer_only), obj);
	g_signal_connect(info, "focus-in-event", G_CALLBACK(v_edit_text_focused), obj);
	g_signal_connect(info, "focus-out-event", G_CALLBACK(v_edit_text_focused), obj);
	return info;
}

VExError
VEditText::create_do(const VObjectStatus* s, int flags, 
		VObject * nmp,void * arg)
{
	edit_text_set *set = (edit_text_set*)arg;
	min_len = set->min_len;
	info = v_serialized_exec_func(
		v_edit_text_create_do, this, set,
		(flags & VSF_ATTR) && (s->attr & integer_only));
	return return_create_do(this,nmp,&sts,s,flags);
}

void
VEditText::destroy_do(VObject * nmp)
{
	nmp->remove_child_do(this);
	v_serialized_exec_sub(gtk_widget_destroy, info);
	v_serialized_exec_sub(g_object_unref, info);
}

VEditText::~VEditText()
{
}

VExError
VEditText::get_status(VObjectStatus *s, int flags) const
{
	V_OP_START_EX
	VExError err = v_get_status_standard(s, &flags, info);
	
	if ( (flags & VSF_VALUE) && (sts.attr & integer_only) ) {
		s->value = atoi(v_serialized_exec_func(gtk_entry_get_text, GTK_ENTRY(info)));
		flags &= ~VSF_VALUE;
	}
	if ( flags & VSF_DESC ) {
		s->descriptor = l_string(&utf8_cm,
			(char*)v_serialized_exec_func(gtk_entry_get_text, GTK_ENTRY(info)));
		flags &= ~VSF_DESC;
	}
	err.subcode1 = flags;

	VExError err2 = VObject::get_status(s,flags);
	if ( err2.code )
		err = merge_VExError_vstatus_type(err,err2);
	
	V_OP_END
	return err;
};


VExError
VEditText::set_status(const VObjectStatus *s, int flags)
{
	V_OP_START_EX
	VExError err = v_set_status_standard(s, flags, info);
	err = VObject::set_status(s,flags&~VSF_VALUE);
	if ( err.code ) {
		V_OP_END
		return err;
	}
	
	if ( (flags & VSF_VALUE) && (sts.attr & integer_only) ) {
		if ( atoi(v_serialized_exec_func(gtk_entry_get_text, GTK_ENTRY(info))) != s->value ) {
			char buf[32];
			sprintf(buf, "%d", s->value);
			v_serialized_exec_sub(gtk_entry_set_text, GTK_ENTRY(info), buf);
		}
		err.subcode1 &= ~VSF_VALUE;
	}
	if ( flags & (VSF_WS | VSF_FSIZE) ) {
		if ( sts.ws ) {
			char *font = _set_styled_descriptor_get_font(sts.descriptor, sts.ws, sts.fsize);
			v_serialized_exec_sub(_set_styled_descriptor_style, info, font, 0);
			d_f_ree(font);
		}
		err.subcode1 &= ~(VSF_WS | VSF_FSIZE);
	}
	if ( flags & VSF_DESC ) {
		if ( sts.descriptor ) {
			v_serialized_exec_sub(gtk_entry_set_text,
				GTK_ENTRY(info), ucd_n_string(sts.descriptor));
		}
		else {
			v_serialized_exec_sub(gtk_entry_set_text, GTK_ENTRY(info),"");
		}
		err.subcode1 &= ~VSF_DESC;
	}

	V_OP_END
		
	if ( flags & (VSF_ALIGN | VSF_PADDING ) ) {
		if ( sts.parent )
			sts.parent->child_status_changed(this, info);
		err.subcode1 &= ~(VSF_ALIGN | VSF_PADDING );
	}
	return err;
}

void
VEditText::redraw(VRect* rect) const
{
}

bool
VEditText::command_status(int type) const
{
	switch ( type ) {
	  case VMT_UNDO:
	  case VMT_REDO:
		/* not yet supported */
		return false;
	  case VMT_CUT:
	  case VMT_COPY:
	  case VMT_CLEAR:
		return gtk_editable_get_selection_bounds(GTK_EDITABLE(info),0,0);
	  case VMT_PASTE:
		return gtk_clipboard_wait_is_text_available(
			gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
	  case VMT_SEL_ALL:
		gchar *c = gtk_editable_get_chars(GTK_EDITABLE(info), 0, 1);
		gchar c0 = c[0];
		g_free(c);
		return c0 != 0;
	}
	return false;
}

bool
VEditText::obey_command(int type)
{
	switch ( type ) {
	  case VMT_CUT:
		gtk_editable_cut_clipboard(GTK_EDITABLE(info));
		return true;
	  case VMT_COPY:
		gtk_editable_copy_clipboard(GTK_EDITABLE(info));
		return true;
	  case VMT_PASTE:
		gtk_editable_paste_clipboard(GTK_EDITABLE(info));
		return true;
	  case VMT_CLEAR:
		gtk_editable_delete_selection(GTK_EDITABLE(info));
		return true;
	  case VMT_SEL_ALL:
		gtk_editable_select_region(GTK_EDITABLE(info), 0, -1);
		return true;
	}
	return false;
}

void
VEditText::focus()
{
	v_serialized_exec_sub(gtk_widget_grab_focus, info);
}
