/*****************************************************************************/
/* Obj.c - A library for object list.                                        */
/*                                                                           */
/* Obj.c Copyright (c) 2000 Sakai Hiroaki.                                   */
/* All Rights Reserved.                                                      */
/*****************************************************************************/

#include "ObjP.h"

/*****************************************************************************/
/* ObjListData 型の操作                                                      */
/*****************************************************************************/

static ObjListData ObjListData_Create(Obj obj, Obj (*destructor)())
{
  ObjListData list_data;

  list_data = (ObjListData)malloc(sizeof(_ObjListData));

  list_data->obj = obj;
  list_data->destructor = destructor;

  return (list_data);
}

static ObjListData ObjListData_Destroy(ObjListData list_data)
{
  if (list_data == NULL) return (NULL);

  /* デストラクタの実行 */
  if (list_data->destructor)
    (*(list_data->destructor))(list_data->obj);

  free(list_data);

  return (NULL);
}

/*****************************************************************************/
/* ObjList 型オブジェクトの操作                                              */
/*****************************************************************************/

Obj ObjListData_GetObj(ObjListData data)
{
  if (data == NULL) return (NULL);
  return (data->obj);
}

Obj ObjListData_GetPrev(ObjListData data)
{
  if (data == NULL) return (NULL);
  return (data->prev);
}

Obj ObjListData_GetNext(ObjListData data)
{
  if (data == NULL) return (NULL);
  return (data->next);
}

int ObjList_GetLength(ObjList list)
{
  if (list == NULL) return (-1);
  return (list->length);
}

ObjListData ObjList_GetStartEdge(ObjList list)
{
  if (list == NULL) return (NULL);
  return (list->start_edge);
}

ObjListData ObjList_GetEndEdge(ObjList list)
{
  if (list == NULL) return (NULL);
  return (list->end_edge);
}

ObjListData ObjList_GetStart(ObjList list)
{
  if (list == NULL) return (NULL);
  return (list->start_edge->next);
}

ObjListData ObjList_GetEnd(ObjList list)
{
  if (list == NULL) return (NULL);
  return (list->end_edge->prev);
}

int ObjList_IsEmpty(ObjList list)
{
  if (list == NULL) return (1);
  return (list->start_edge->next == list->end_edge);
}

int ObjList_IsStartEdge(ObjList list, ObjListData data)
{
  if (list == NULL) return (0);
  return (data == list->start_edge);
}

int ObjList_IsEndEdge(ObjList list, ObjListData data)
{
  if (list == NULL) return (0);
  return (data == list->end_edge);
}

int ObjList_IsStart(ObjList list, ObjListData data)
{
  if (list == NULL) return (0);
  return (data == list->start_edge->next);
}

int ObjList_IsEnd(ObjList list, ObjListData data)
{
  if (list == NULL) return (0);
  return (data == list->end_edge->prev);
}

ObjListData ObjList_InsertObjToPrev(ObjList list, ObjListData current,
				    Obj obj, Obj (*destructor)())
{
  ObjListData data;

  if (list == NULL) return (NULL);
  if (ObjList_IsStartEdge(list, current)) return (NULL);

  data = ObjListData_Create(obj, destructor);
  if (data == NULL) return (NULL);

  data->prev = current->prev;
  data->next = current;
  current->prev->next = data;
  current->prev = data;
  (list->length)++;

  return (data);
}

ObjListData ObjList_InsertObjToNext(ObjList list, ObjListData current,
				    Obj obj, Obj (*destructor)())
{
  ObjListData data;

  if (list == NULL) return (NULL);
  if (ObjList_IsEndEdge(list, current)) return (NULL);

  data = ObjListData_Create(obj, destructor);
  if (data == NULL) return (NULL);

  data->next = current->next;
  data->prev = current;
  current->next->prev = data;
  current->next = data;
  (list->length)++;

  return (data);
}

ObjListData ObjList_InsertObjToStart(ObjList list, Obj obj,
				     Obj (*destructor)())
{
  ObjListData current;
  current = ObjList_GetStart(list);
  return (ObjList_InsertObjToPrev(list, current, obj, destructor));
}

ObjListData ObjList_InsertObjToEnd(ObjList list, Obj obj,
				   Obj (*destructor)())
{
  ObjListData current;
  current = ObjList_GetEnd(list);
  return (ObjList_InsertObjToNext(list, current, obj, destructor));
}

ObjListData ObjList_DeleteObjToPrev(ObjList list, ObjListData current)
{
  ObjListData ret;

  if (list == NULL) return (NULL);
  if (ObjList_IsStartEdge(list, current) || ObjList_IsEndEdge(list, current))
    return (NULL);

  current->prev->next = current->next;
  current->next->prev = current->prev;

  ret = current->prev;
  ObjListData_Destroy(current);
  (list->length)--;

  return (ret);
}

ObjListData ObjList_DeleteObjToNext(ObjList list, ObjListData current)
{
  ObjListData ret;

  if (list == NULL) return (NULL);
  if (ObjList_IsStartEdge(list, current) || ObjList_IsEndEdge(list, current))
    return (NULL);

  current->prev->next = current->next;
  current->next->prev = current->prev;

  ret = current->next;
  ObjListData_Destroy(current);
  (list->length)--;

  return (ret);
}

ObjListData ObjList_DeleteObjFromStart(ObjList list)
{
  ObjListData current;
  if (list == NULL) return (NULL);
  current = ObjList_GetStart(list);
  return (ObjList_DeleteObjToNext(list, current));
}

ObjListData ObjList_DeleteObjFromEnd(ObjList list)
{
  ObjListData current;
  if (list == NULL) return (NULL);
  current = ObjList_GetEnd(list);
  return (ObjList_DeleteObjToPrev(list, current));
}

ObjListData ObjList_MoveObjToPrev(ObjList list,
				  ObjListData current,
				  ObjListData to)
{
  if (list == NULL) return (NULL);
  return (ObjList_MoveObjToPrevOfOtherList(list, current, list, to));
}

ObjListData ObjList_MoveObjToNext(ObjList list,
				  ObjListData current,
				  ObjListData to)
{
  if (list == NULL) return (NULL);
  return (ObjList_MoveObjToNextOfOtherList(list, current, list, to));
}

ObjListData ObjList_MoveObjToStart(ObjList list, ObjListData current)
{
  if (list == NULL) return (NULL);
  return (ObjList_MoveObjToStartOfOtherList(list, current, list));
}

ObjListData ObjList_MoveObjToEnd(ObjList list, ObjListData current)
{
  if (list == NULL) return (NULL);
  return (ObjList_MoveObjToEndOfOtherList(list, current, list));
}

ObjList ObjList_Create() /* ObjList 型オブジェクトを作成する */
{
  ObjList list;

  list = (ObjList)malloc(sizeof(_ObjList));
  if (list == NULL) return (NULL);

  list->start_edge   = ObjListData_Create(NULL, NULL);
  list->end_edge     = ObjListData_Create(NULL, NULL);
  list->length  = 0;    /* 現在存在しているデータの数 */

  list->start_edge->prev = NULL;
  list->start_edge->next = list->end_edge;
  list->end_edge->prev   = list->start_edge;
  list->end_edge->next   = NULL;

  return (list);
}

ObjList ObjList_Destroy(ObjList list) /*  */
{
  if (list == NULL) return (NULL);

  while (!ObjList_IsEmpty(list))
    ObjList_DeleteObjFromStart(list);

  if (list->start_edge)
    list->start_edge = ObjListData_Destroy(list->start_edge);
  if (list->end_edge)
    list->end_edge = ObjListData_Destroy(list->end_edge);

  free(list);

  return (NULL);
}

/*===========================================================================*/
/* 複数のリスト間での操作                                                    */
/*===========================================================================*/

ObjListData ObjList_MoveObjToPrevOfOtherList(ObjList list, ObjListData current,
					     ObjList to_list, ObjListData to)
{
  if (list == NULL) return (NULL);
  if (to_list == NULL) return (NULL);
  if (ObjList_IsStartEdge(list, current) || ObjList_IsEndEdge(list, current))
    return (NULL);

  if (ObjList_IsStartEdge(to_list, to)) return (NULL);
  if ((list == to_list) && (current == to)) return (current);

  current->prev->next = current->next;
  current->next->prev = current->prev;

  current->prev = to->prev;
  current->next = to;
  to->prev->next = current;
  to->prev = current;

  (list->length)--;
  (to_list->length)++;

  return (current);
}

ObjListData ObjList_MoveObjToNextOfOtherList(ObjList list, ObjListData current,
					     ObjList to_list, ObjListData to)
{
  if (list == NULL) return (NULL);
  if (ObjList_IsStartEdge(list, current) || ObjList_IsEndEdge(list, current))
    return (NULL);

  if (ObjList_IsEndEdge(to_list, to)) return (NULL);
  if ((list == to_list) && (current == to)) return (current);

  current->prev->next = current->next;
  current->next->prev = current->prev;

  current->next = to->next;
  current->prev = to;
  to->next->prev = current;
  to->next = current;

  (list->length)--;
  (to_list->length)++;

  return (current);
}

ObjListData ObjList_MoveObjToStartOfOtherList(ObjList list,
					      ObjListData current,
					      ObjList to_list)
{
  ObjListData to;
  if (list == NULL) return (NULL);
  if (to_list == NULL) return (NULL);
  to = ObjList_GetStart(to_list);
  return (ObjList_MoveObjToPrevOfOtherList(list, current, to_list, to));
}

ObjListData ObjList_MoveObjToEndOfOtherList(ObjList list,
					    ObjListData current,
					    ObjList to_list)
{
  ObjListData to;
  if (list == NULL) return (NULL);
  if (to_list == NULL) return (NULL);
  to = ObjList_GetEnd(to_list);
  return (ObjList_MoveObjToNextOfOtherList(list, current, to_list, to));
}

ObjList ObjList_Concatenate(ObjList list1, ObjList list2)
{
  ObjListData tmp;

  if (list1 == NULL) {
    list1 = list2;
    return (list1);
  }
  if (list2 == NULL) return (list1);

  list1->end_edge->prev->next = list2->start_edge->next;
  list2->start_edge->next->prev = list1->end_edge->prev;

  tmp = list1->end_edge;
  list1->end_edge = list2->end_edge;
  list2->end_edge = tmp;

  list2->start_edge->next = list2->end_edge;
  list2->end_edge->prev = list2->start_edge;

  list1->length += list2->length;
  list2->length = 0;

  ObjList_Destroy(list2);

  return (list1);
}

/* End of File. */
