/******************************************************
 *
 * This file is based on iem_objlist.h by IOhannes m zmlnig
 *
 * Original copyleft (c):
 *   IOhannes m zmlnig
 *
 *   2008:forum::fr::umlute:2008
 *
 *   institute of electronic music and acoustics (iem)
 *
 ******************************************************
 *
 * license: GNU General Public License v.2
 *
 ******************************************************/

/* this file implements some helperr functions for dealing with lists of
 * objects (containing other objects)
 *
 * used for callbacks to enumerated objects without $0 tricks
 */



//#include "m_pd.h"

/*
 The basic element is a parent.
 Elements can then be added/removed to/from this parent.
 
 */


/* ------------------------- helper methods for callbacks ---------------------------- */

typedef struct _objectlist_element {
  const t_pd* obj;
  struct _objectlist_element* next;
} t_objectlist_element;

typedef struct _objectlist_list {
  const t_pd* parent;
  t_objectlist_element* obj;

  struct _objectlist_list *next;
} t_objectlist_list;

static t_objectlist_list* static_list=0;


// Find a list with the specified parent
static t_objectlist_list* getList(const t_pd*parent) {
  t_objectlist_list* list = static_list;
  if(0==parent  || 0==list)
    return 0;

  for(list=static_list; list; list=list->next) {
    if(parent == list->parent) {
      return list;
    }
  }
  return 0; 
}

static t_objectlist_list* addList(const t_pd* parent)
{
  t_objectlist_list* list=getList(parent);
  if(!list) {
    list=(t_objectlist_list*)getbytes(sizeof(t_objectlist_list));
    list->parent=parent;
    list->obj=0;
    list->next=0;

    if(0==static_list) {
      /* new list */
      static_list=list;
    } else {
      /* add to the end of existing list */
      t_objectlist_list* dummy=static_list;
      while(dummy->next)
        dummy=dummy->next;
      dummy->next = list;
    }
  }
  return list;
}

static t_objectlist_element* getElements (const t_pd*parent) {
  t_objectlist_list* list = getList(parent);
  if(list)
    return list->obj;

  return 0;
}

// Add element to a list
static void addElement (const t_pd*parent, const t_pd*obj) {
  t_objectlist_list* p=addList(parent);
  t_objectlist_element* list=0;
  t_objectlist_element* entry=0;
  if(!p || !obj)
    return;
  list=p->obj;

  if(list&&obj==list->obj)
    return;

  while(list && list->next) {
    if(obj==list->obj) /* obj already in list */
      return;
    list=list->next;
  }

  /* we are at the end of the list that does not contain obj yet, so add it */
  entry=(t_objectlist_element*)getbytes(sizeof(t_objectlist_element));
  entry->obj=obj;
  entry->next=0;
  if(list) {
    list->next=entry;
  } else {
    p->obj=entry;
  }
}

// Remove element from list
static void removeElement(const t_pd*parent, const t_pd*obj) {
  t_objectlist_list* p=getList(parent);
  t_objectlist_element* list=0, *last=0, *next=0;
  if(!p || !obj)return;
  list=p->obj;
  if(!list)
    return;

  while(list && obj!=list->obj) {
    last=list;
    list=list->next;
  }

  if(!list) /* couldn't find this object */
    return;

  next=list->next;

  if(last)
    last->next=next;
  else
    p->obj=next;

  freebytes((void*)list, sizeof(t_objectlist_element));
  list=0;
}

// Remove element from all lists!
static void removeElementFromLists(const t_pd*obj) {
   t_objectlist_list* parents=static_list;

  while(parents) {
    removeElement(parents->parent, obj);
    parents=parents->next;
  }
}
