/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2004-2009 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>

#include "list.h"

/* returns new node */
struct list_item *list_create(void *item)
{
   struct list_item *this = malloc(sizeof *this);
   if (this == NULL)
      abort();
   this->next = NULL;
   this->item = item;
   return this;
}

struct list_item *list_create_marena(void *item, struct marena *arena)
{
   struct list_item *this = marena_alloc(arena, sizeof(*this));
   this->next = NULL;
   this->item = item;
   return this;
}

/* returns list head */
struct list_item *list_prepend(struct list_item *head, struct list_item *node)
{
   node->next = head;
   return node;
}

/* returns number of nodes */
size_t list_count(struct list_item * head)
{
   size_t count = 0;
   for (; head != NULL; head = head->next)
      ++count;
   return count;
}

/* calls fn on each item */
void list_apply(struct list_item *head, void (*fn) (void *))
{
   for (; head != NULL; head = head->next)
      fn(head->item);
}

struct list_item *list_find(struct list_item *node,
   int (*pred) (const void *))
{
   for (; node != NULL; node = node->next)
      if (pred(node->item))
         return node;
   return NULL;
}

/* finds first item that compares equal with arg */
struct list_item *list_find2(struct list_item *node, int (*cmp) (const void *,
      const void *), const void *arg)
{
   for (; node != NULL; node = node->next)
      if (cmp(node->item, arg) == 0)
         return node;
   return NULL;
}

void
list_apply2(struct list_item *head, void (*fn) (void *, void *), void *arg)
{
   for (; head != NULL; head = head->next)
      fn(head->item, arg);
}

/* calls fn on each item, and assigns the result */
void list_transform(struct list_item *head, void *(*fn) (void *))
{
   for (; head != NULL; head = head->next)
      head->item = fn(head->item);
}

/* destroys the entire list, if fn is non-null it will be called on each item */
void list_destroy(struct list_item *head, void (*fn) (void *))
{
   struct list_item *next;
   if (fn)
      for (; head != NULL; head = next) {
         next = head->next;
         fn(head->item);
         free(head);
      }
   else
      for (; head != NULL; head = next) {
         next = head->next;
         free(head);
      }
}

/* creates a vector of all items */
void **list_to_vector(struct list_item *head)
{
   size_t count;
   void **result;
   struct list_item *node;

   for (count = 0, node = head; node != NULL; node = node->next)
      ++count;
   result = malloc(sizeof *result * count);
   if (result == NULL)
      return NULL;
   for (count = 0, node = head; node != NULL; node = node->next)
      result[count++] = node->item;
   return result;
}

list_t list_revert(list_t list)
{
   list_t result = NULL;
   while (list) {
      list_t next = list->next;
      if (result) {
         list->next = result;
         result = list;
      } else {
         result = list;
         result->next = NULL;
      }
      list = next;
   }
   return result;
}
