/* linkedlist-generic.c -- Generische einfach verkettete Liste (1. Versuch)
*/

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

struct generic_node {
  void *node_data;
  struct generic_node *next;
};

struct generic_list {
  struct generic_node *head;
};


struct generic_list *new_generic_list()
{
  struct generic_list *list = malloc(sizeof(struct generic_list));
  list->head = NULL;
  return list;
}

void free_generic_list(struct generic_list *list)
{
  struct generic_node *node = list->head;
  free(list);
  while (node != NULL) {
    struct generic_node *next = node->next;
    free(node->node_data);	/* assumes malloc()'ed node_data */
    free(node);
    node = next;
  }
}

void generic_list_push(struct generic_list *list, void *node_data)
{
  struct generic_node *node = malloc(sizeof(struct generic_node));
  node->node_data = node_data;
  node->next = list->head;
  list->head = node;
}

/* Funktion zum Iterieren */

typedef void (*generic_function)(void *node_data, void *function_data);

void generic_list_for_each(struct generic_list *list,
			   generic_function function,
			   void *function_data)
{
  struct generic_node *node = list->head;
  while (node != NULL) {
    (*function)(node->node_data, function_data);
    node = node->next;
  }
}

/* Zeichenketten-Liste; Gesamtlaenge aller Zeichenketten: */

struct generic_list *new_string_list()
{
  return new_generic_list();
}

void add_to_length(void *node_data, void *function_data)
{
  char *text = node_data;	/* Impliziter Typecast */
  int *length_p = function_data;
  (*length_p) += strlen(text);
}
			  
int total_length(struct generic_list *list)
{
  int length = 0;
  generic_list_for_each(list, add_to_length, &length);
  return length;
}

/* Integer-Liste; Produkt aller Zahlen */

struct generic_list *new_int_list()
{
  return new_generic_list();
}

void do_multiply(void *node_data, void *function_data)
{
  int factor = (int) node_data; /* Expliziter Typecast */
  int *result_p = function_data;
  (*result_p) *= factor;
}

int product(struct generic_list *list)
{
  int result = 1;
  generic_list_for_each(list, do_multiply, &result);
  return result;
}

/* Hauptprozedur */

int main ()
{
  {
    /* Zeichenketten-Liste */
    struct generic_list *list = new_string_list();
    generic_list_push(list, strdup("Hello")); /* Impliziter Typecast */
    generic_list_push(list, strdup("Good-bye"));
    printf("Gesamtlaenge: %d\n", total_length(list));
    free_generic_list(list);
  }
  {
    /* Integer-Liste */
    struct generic_list *list = new_int_list();
    generic_list_push(list, (void *) 7); /* Expliziter Typecast */
    generic_list_push(list, (void *) 673);
    printf("Produkt: %d\n", product(list));
    free_generic_list(list);
  }
  return 0;
}
