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

  gbx_c_observer.c

  (c) 2000-2017 Benoît Minisini <benoit.minisini@gambas-basic.org>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, or (at your option)
  any later version.

  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.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  MA 02110-1301, USA.

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

#define __GBX_C_OBSERVER_C

#include "gbx_info.h"

#ifndef GBX_INFO

#include "gbx_exec.h"
#include "gbx_api.h"
#include "gbx_event.h"
#include "gbx_c_observer.h"

//#define DEBUG_ME 1

void COBSERVER_lock(COBSERVER *this, bool lock)
{
	if (lock)
		this->locked++;
	else
		this->locked--;
}

void COBSERVER_attach(COBSERVER *this, void *parent, const char *name)
{
	#if DEBUG_ME
	fprintf(stderr, "COBSERVER_attach: %p: %s %p\n", this, parent ? OBJECT_class(parent)->name : "", parent);
	#endif
	if (this->object && this->event)
		EVENT_search(OBJECT_class(this->object), this->event, name, parent);	
}

void COBSERVER_detach(COBSERVER *this)
{
	#if DEBUG_ME
	fprintf(stderr, "COBSERVER_detach: %p\n", this);
	#endif
	
	if (this->event)
		FREE(&this->event);
}

BEGIN_METHOD(Observer_new, GB_OBJECT object; GB_BOOLEAN after)

	OBJECT *object;
	OBJECT_EVENT *ev;
	char *name;
	CLASS *class;
	void *parent;
	
	object = (OBJECT *)VARG(object);
	if (GB_CheckObject(object))
		return;
	
	parent = OBJECT_parent(THIS);
	
	if (!parent)
		return;
	
	class = OBJECT_class(object);
	if (class->n_event == 0)
		return;
	
	name = EVENT_Name;
	if (!name || !*name)
		return;
	
	#if DEBUG_ME
	fprintf(stderr, "Observer_new: %p %d %s (%s %p)\n", THIS, OBJECT_class(object)->n_event, name, GB_GetClassName(parent), parent);
	#endif
	
	ev = OBJECT_event(object);
  
  THIS->after = VARGOPT(after, FALSE);
  
	ALLOC_ZERO(&THIS->event, sizeof(ushort) * class->n_event);

	THIS->object = object;
	OBJECT_attach((OBJECT *)THIS, parent, name);
	COBSERVER_attach(THIS, parent, name);

	LIST_insert((void **)&ev->observer, THIS, &THIS->list);
  OBJECT_REF(THIS);
	
END_METHOD


BEGIN_METHOD_VOID(Observer_free)

	#if DEBUG_ME
	fprintf(stderr, "Observer_free: %p\n", THIS);
	#endif
	
	GB_StoreVariant(NULL, &THIS->tag);
	COBSERVER_detach(THIS);

END_METHOD

BEGIN_PROPERTY(Observer_Object)

	GB_ReturnObject(THIS->object);
	
END_PROPERTY

BEGIN_PROPERTY(Observer_Tag)

	if (READ_PROPERTY)
		GB_ReturnVariant(&THIS->tag);
	else
		GB_StoreVariant(PROP(GB_VARIANT), &THIS->tag);
	
END_PROPERTY

BEGIN_METHOD_VOID(Observer_Detach)

	OBJECT_EVENT *ev;
	
	if (!THIS->object)
		return;
	
	ev = OBJECT_event(THIS->object);
	LIST_remove((void **)&ev->observer, THIS, &THIS->list);
	THIS->object = NULL;
	OBJECT_UNREF(_object);

END_METHOD

#endif

GB_DESC NATIVE_Observer[] =
{
  GB_DECLARE("Observer", sizeof(COBSERVER)), 

  GB_METHOD("_new", NULL, Observer_new, "(Object)o[(After)b]"),
  GB_METHOD("_free", NULL, Observer_free, NULL),
  
  GB_PROPERTY_READ("Object", "o", Observer_Object),
  GB_PROPERTY("Tag", "v", Observer_Tag),
  
  GB_METHOD("Detach", NULL, Observer_Detach, NULL),
  
  GB_END_DECLARE
};
