/****************************************************************************
 * This file is part of the project AqHome.
 * AqHome (c) by 2025 Martin Preuss, all rights reserved.
 *
 * The license for this file can be found in the file COPYING which you
 * should have received along with this file.
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "./object_p.h"



/* ------------------------------------------------------------------------------------------------
 * forward declarations
 * ------------------------------------------------------------------------------------------------
 */

static AQH_LINK *AQH_Link_new();
static void AQH_Link_free(AQH_LINK *ln);

static AQH_LINK *_findLink(AQH_OBJECT *o, uint32_t signalId, uint32_t slotId, AQH_OBJECT *targetObject);



/* ------------------------------------------------------------------------------------------------
 * list, inherit
 * ------------------------------------------------------------------------------------------------
 */

GWEN_LIST_FUNCTIONS(AQH_LINK, AQH_Link)

GWEN_INHERIT_FUNCTIONS(AQH_OBJECT)
GWEN_LIST_FUNCTIONS(AQH_OBJECT, AQH_Object)
GWEN_LIST2_FUNCTIONS(AQH_OBJECT, AQH_Object)



/* ------------------------------------------------------------------------------------------------
 * code
 * ------------------------------------------------------------------------------------------------
 */

AQH_OBJECT *AQH_Object_new(AQH_EVENT_LOOP *eventLoop)
{
  AQH_OBJECT *o;

  GWEN_NEW_OBJECT(AQH_OBJECT, o);
  o->refCount=1;
  GWEN_INHERIT_INIT(AQH_OBJECT, o);
  GWEN_LIST_INIT(AQH_OBJECT, o);
  o->eventLoop=eventLoop;
  o->linkList=AQH_Link_List_new();

  return o;
}



void AQH_Object_IncRefCount(AQH_OBJECT *o)
{
  if (o && o->refCount>0)
    o->refCount++;
}



void AQH_Object_free(AQH_OBJECT *o)
{
  if (o && o->refCount>0) {
    if (--(o->refCount)==0) {
      AQH_Link_List_free(o->linkList);
      GWEN_LIST_FINI(AQH_OBJECT, o);
      GWEN_INHERIT_FINI(AQH_OBJECT, o);

      GWEN_FREE_OBJECT(o);
    }
  }
}



uint32_t AQH_Object_GetFlags(const AQH_OBJECT *o)
{
  return (o && o->refCount)?o->flags:0;
}



void AQH_Object_SetFlags(AQH_OBJECT *o, uint32_t i)
{
  if (o && o->refCount)
    o->flags=i;
}



void AQH_Object_AddFlags(AQH_OBJECT *o, uint32_t i)
{
  if (o && o->refCount)
    o->flags|=i;
}



void AQH_Object_SubFlags(AQH_OBJECT *o, uint32_t i)
{
  if (o && o->refCount)
    o->flags&=~i;
}



AQH_EVENT_LOOP *AQH_Object_GetEventLoop(const AQH_OBJECT *o)
{
  return (o && o->refCount)?o->eventLoop:NULL;
}



AQH_LINK *_findLink(AQH_OBJECT *o, uint32_t signalId, uint32_t slotId, AQH_OBJECT *targetObject)
{
  if (o && o->refCount) {
    AQH_LINK *ln;

    ln=AQH_Link_List_First(o->linkList);
    while(ln) {
      if (ln->signalIdForSender==signalId &&
	  ln->signalIdForTarget==slotId &&
	  ln->targetObject==targetObject)
	return ln;
      ln=AQH_Link_List_Next(ln);
    }
  }
  return NULL;
}



void AQH_Object_AddLink(AQH_OBJECT *o, uint32_t signalId, uint32_t slotId, AQH_OBJECT *targetObject)
{
  AQH_LINK *ln;

  ln=_findLink(o, signalId, slotId, targetObject);
  if (ln==NULL) {
    ln=AQH_Link_new();
    ln->signalIdForSender=signalId;
    ln->signalIdForTarget=slotId;
    ln->targetObject=targetObject;
    AQH_Link_List_Add(ln, o->linkList);
  }
}



void AQH_Object_DelLink(AQH_OBJECT *o, uint32_t signalId, uint32_t slotId, AQH_OBJECT *targetObject)
{
  AQH_LINK *ln;

  ln=_findLink(o, signalId, slotId, targetObject);
  if (ln) {
    AQH_Link_List_Del(ln);
    AQH_Link_free(ln);
  }
}



int AQH_Object_EmitSignal(AQH_OBJECT *o, uint32_t signalId, int param1, void *param2)
{
  int signalWasHandled=0;

  if (o && o->refCount) {
    AQH_LINK *ln;

    ln=AQH_Link_List_First(o->linkList);
    while(ln) {
      if (ln->signalIdForSender==signalId && ln->targetObject) {
	if (AQH_Object_HandleSignal(ln->targetObject, ln->signalIdForTarget, o, param1, param2))
	  signalWasHandled=1;
      }
      ln=AQH_Link_List_Next(ln);
    }
  }
  return signalWasHandled;
}



int AQH_Object_HandleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2)
{
  if (o && o->refCount && o->signalHandlerFn)
    return o->signalHandlerFn(o, slotId, senderObject, param1, param2);
  return 0;
}



void AQH_Object_Enable(AQH_OBJECT *o)
{
  if (o && o->refCount && o->enableFn)
    o->enableFn(o);
}



void AQH_Object_Disable(AQH_OBJECT *o)
{
  if (o && o->refCount && o->disableFn)
    o->disableFn(o);
}



AQH_OBJECT_SIGNALHANDLER_FN AQH_Object_SetSignalHandlerFn(AQH_OBJECT *o, AQH_OBJECT_SIGNALHANDLER_FN f)
{
  if (o && o->refCount) {
    AQH_OBJECT_SIGNALHANDLER_FN oldFn;

    oldFn=o->signalHandlerFn;
    o->signalHandlerFn=f;
    return oldFn;
  }
  return NULL;
}



AQH_OBJECT_ENABLE_FN AQH_Object_SetEnableFn(AQH_OBJECT *o, AQH_OBJECT_ENABLE_FN f)
{
  if (o && o->refCount) {
    AQH_OBJECT_ENABLE_FN oldFn;

    oldFn=o->enableFn;
    o->enableFn=f;
    return oldFn;
  }
  return NULL;
}



AQH_OBJECT_DISABLE_FN AQH_Object_SetDisableFn(AQH_OBJECT *o, AQH_OBJECT_DISABLE_FN f)
{
  if (o && o->refCount) {
    AQH_OBJECT_DISABLE_FN oldFn;

    oldFn=o->disableFn;
    o->disableFn=f;
    return oldFn;
  }
  return NULL;
}






AQH_LINK *AQH_Link_new()
{
  AQH_LINK *ln;

  GWEN_NEW_OBJECT(AQH_LINK, ln);
  GWEN_LIST_INIT(AQH_LINK, ln);

  return ln;
}



void AQH_Link_free(AQH_LINK *ln)
{
  if (ln) {
    GWEN_LIST_FINI(AQH_LINK, ln);
    GWEN_FREE_OBJECT(ln);
  }
}





