/**********************************************************************
 
	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.

**********************************************************************/



#ifndef ___V_OBJECT_H___
#define ___V_OBJECT_H___

extern "C" {
void er_panic(char*);
#include "long_char.h"
#include "task.h"
#include "utils.h"
}
#include "v/v_types.h"
#include "v/v_errors.h"
#include "machine/v_m.h"

#ifdef USE_V_LAYOUT
#include "v/VLayout.h"
#endif

#ifndef PRE_LOCK
#define PRE_LOCK
#endif
#ifndef POST_LOCK
#define POST_LOCK
#endif

#include "v/v_serialized_exec.h"
#include "v/VSemaphore.h"

void v_type_name_add(int, char*);
#define VRegisterClass(class) v_type_name_add(class::object_type, #class)


class VObject
{
  public:
	// initializer for all VObjects. must be called before usage of any methods
	static void			init();
	
	// feature of this class
 	enum { object_type = VO_VOBJ };
	virtual unsigned	get_type() const { return object_type; }
	virtual unsigned	max_children() const { return 0; }
	
	// create new object
	// static VObject*	create(const VObjectStatus *s, int flags, void *arg, VExError *err);
	
	// delete this object
	VError		destroy();
	
  public:
	
	// status accessor
	virtual VExError	get_status(VObjectStatus *, int flags) const;
	virtual VExError	set_status(const VObjectStatus *, int flags);
	
	// called from child on status change
	virtual void	child_status_changed(VObject *child, VInfo *info) {}
	
	virtual void	redraw(VRect* rect = 0) const;
	
	// utility method
	
	static VObject*	get_object_by_id(unsigned id);
	const char *	describe_self();

	VObject * get_nmc(int);	// get non macro child

	// free list on release this object
	struct FreeList {
		void 		*target;
		void		(*free_func)(int,void*);
#define VFLT_ZONBIE	1
#define VFLT_DELETE	2
		FreeList	*next;
	};
	void			free_on_release(void *target,void (*f)(int,void*)=0);
	void			free_on_release_list(FreeList *list);
	
	// *for internal* call these method on user interaction
	virtual void	value_changed() {
		if (sts.value_event_handler)
			vq_insert_callback(this,sts.value_event_handler,sts.value_eh_arg,0,0);
	};
	virtual void		descriptor_changed() {
		if ( sts.descriptor_event_handler )
			vq_insert_callback(this,sts.descriptor_event_handler,sts.desc_eh_arg,0,0);
	};
	virtual XL_SEXP *	get_object_by_name(L_CHAR * name) {
		return 0;
	}
	virtual void		waitsync(WAITSYNC_CLIENT * c,int type) {
	}

	virtual VInfo*		get_info_this()	const { return info; };
	virtual VExError	add_child_do(VObject* child) { 
		return initial_VExError(V_ER_NO_ERR,0,0);
	}
	virtual void	remove_child_do(VObject* child) { }

	// for VLayout
	void	lock_every_child() {
		lock(this,__FILE__,__LINE__);
		if ( destroy_time != V_OBJECT_ALIVE ) {
			unlock(this);
			return;
		}
		for ( VObjectList *list = sts.children ; list ; list = list->next )
			list->object->lock_every_child();
	}
	void	unlock_every_child() {
		if ( is_locked(this) == 1 ) {
			for ( VObjectList *list = sts.children ; list ; list = list->next )
				list->object->unlock_every_child();
			unlock(this);
		}
	}
	
  protected:
	
	// constructor and destructor. DON'T CALL DIRECTLY.
	// USE create / destroy METHOD INSTEAD.
	VObject();
	virtual	~VObject();
	
	// for VObject subclasses :: create implementation
	static VObject *create_tmp(VObject *(*new_object)(), unsigned obj_type, const VObjectStatus* s, int flags, VExError *err=0, void* arg=0);

	// toolkit-dependent object create / destroy
	VExError	create_fin(const VObjectStatus *, int flags,VObject * nmp, void * arg);
	virtual VExError create_do(const VObjectStatus *, int flags,VObject * nmp, void * arg) = 0;
	virtual VExError create_do_out_of_lock(const VObjectStatus *,int flags,VObject * nmp,void * arg);
	virtual void	destroy_do(VObject * nmp) = 0;
	virtual void	destroy_do_out_of_lock(VObject * nmp) {};
	virtual VError	accept_child_ex(long type, VObject* obj) const { return V_ER_NO_ERR; }
	
	// tree management
	VError				set_parent(VObject* parent);
	VError				accept_child(long type, VObject* obj = 0, VObjectList** last_item = 0) const;
	static VError	check_parent(VObject* parent, long type, VObject *obj = 0)
								{ return parent->accept_child(type, obj); }
	VError				add_child(VObject* child);
	VError				remove_child(VObject* child);
	
	// delay memory free
	void				v_zonbie_insert();
	static void			v_zonbie_tick();
	
	// lock
	static void			lock(const VObject *obj,char * __f,int __l) 
						{ PRE_LOCK; obj->v_lock->lock(__f,__l); }
	static void			unlock(const VObject *obj) { obj->v_lock->unlock(); POST_LOCK; }
	static int			is_locked(const VObject *obj) { return obj->v_lock->is_locked(); }
	static int			get_destroy_time(const VObject *obj) { return obj->destroy_time; }
	
	VError	lock_d(char * __f,int __l) {
		lock(this,__f,__l);
		if ( destroy_time != V_OBJECT_ALIVE ) {
			unlock(this);
			return V_ER_DESTROYED;
		}
		return V_ER_NO_ERR;
	}

	VSemaphore *		v_lock;
	
	// static variables
	static int				next_id;
	static VObjectList*		v_zonbie_list;
	static SEM				v_zonbie_lock;
	
	// status of this object
	VObjectStatus	sts;
	int				detached;
	char *			self_describe;
	int				destroy_time;
	VInfo *			info;	// toolkit-dependent infomation

	FreeList *		free_list;	// auto free data on releasing this object
	
  private:
  	VObject(const VObject&);		// No Copy
	VObject& operator=(const VObject&);	// No Copy
};

V_CALLBACK_D(v_object_destroyer);


#endif
