/* loes12-04.c
  Implementation of a simple linked list.
  This module encapsulates the list and defines some functions to work with the list.
*/

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

typedef int t_Content;  // data type of list content

typedef struct Element {
  t_Content Content;
  struct Element * pNext;
} t_Element;

#define szFormat "%i\n"  // conversation string corresponding to the data type
#define TRUE  1
#define FALSE  0

void Init(void);
void Print(void);
void Add (t_Content newContent);
void InsertAtBegin (t_Content newContent);
void InsertAfter (t_Content oldContent, t_Content newContent);
int Remove(t_Content oldContent);
t_Element* Search (t_Content oldContent);

t_Element* pFirst;   // pointer to first element
t_Element* pLast;    // pointer to last element

void Init(void)
{
  t_Element* pEl;    // pointer to current element
  t_Element* pNextEl;  // pointer to element after current element

  // if the list is not empty, then delete the list

  pEl = pFirst;
  while (pEl != NULL) {
    pNextEl = pEl->pNext;
    free (pEl);
    pEl = pNextEl;
  }

  // init the pointers for an empty list

  pFirst = NULL;
  pLast  = NULL;
}


void Print(void)
{
  t_Element* pEl;    // pointer to current element

  pEl = pFirst;
  while (pEl != NULL) {
    printf(szFormat, pEl->Content);
    pEl = pEl->pNext;
  }
  printf("-------\n");
}


void WriteToFile (const char* szFileName)
{
  FILE *fout;
  t_Element* pEl;    // pointer to current element

  fout = fopen(szFileName, "w");

  pEl = pFirst;
  while (pEl != NULL) {
    fprintf(fout, szFormat, pEl->Content);
    pEl = pEl->pNext;
  }
  fclose(fout);
}


int ReadFromFile (const char* szFileName)
{
  FILE *fin;
  t_Content ElRead;
  int n = 0;

  if ( (fin = fopen(szFileName, "r")) == NULL) {
    printf("ReadFromFile: File %s not found\n", szFileName);
    return 0;
  }

  while (fscanf(fin, szFormat, &ElRead) != EOF) {
    Add(ElRead);
    n++;
  }
  fclose(fin);
  return n;
}


// add a element at the end of the list

void Add (t_Content newContent)
{
  if (pLast != NULL) {
    pLast->pNext = (t_Element*) malloc (sizeof (t_Element));
    pLast = pLast->pNext;
  }
  else { // the list is empty
    pFirst = pLast = (t_Element*) malloc (sizeof (t_Element));
  }
  pLast->Content = newContent;
  pLast->pNext = NULL;
}


void InsertAtBegin (t_Content newContent)
{
  t_Element* pEl;

  if (pFirst == NULL) {
    Add (newContent);
  }
  else {
    pEl = (t_Element*) malloc (sizeof (t_Element));
    pEl->Content = newContent;
    pEl->pNext = pFirst;  // we insert the new element before the first element
    pFirst = pEl;         // we have a new first element
  }
}


// insert a element after the first element with content oldContent
// if oldContent is not a list element, we add the element at the end

void InsertAfter (t_Content oldContent, t_Content newContent)
{
  t_Element* pEl;

  pEl = Search(oldContent);
  if (pEl == NULL) {
    Add(newContent);
  }
  else {
    t_Element* pNew;
    pNew = (t_Element*) malloc (sizeof (t_Element));
    pNew->pNext = pEl->pNext;
    pNew->Content = newContent;
    pEl->pNext = pNew;
  }
}


// remove (delete) the first element with content oldContent

int Remove(t_Content oldContent)
{
  t_Element* pEl;
  t_Element* pPrev;

  pEl = Search(oldContent);
  if (pEl == NULL)
    return FALSE;

  // Look for the element in front of the element to be deleted.
  pPrev = pFirst;
  while (pPrev->pNext != pEl)
    pPrev = pPrev->pNext;

  // save the pointer to the next element
  pPrev->pNext = pEl->pNext;
  // delete the element
  free(pEl);
  return TRUE;
}


t_Element* Search (t_Content oldContent)
{
  t_Element* pEl;    // pointer to current element

  pEl = pFirst;
  while (pEl != NULL && pEl->Content != oldContent) {
    pEl = pEl->pNext;
  }
  return pEl;
}




// simple test code

int main(void)
{
  Init();
  Add(1);
  Add(2);
  Add(3);
  Print();          // 1 2 3
  Remove(2);        // 1 3
  InsertAtBegin(0);
  Print();          // 0 1 3
  InsertAfter(1, 2);  // 0 1 2 3
  Print();
  InsertAfter(2, 2);  // 0 1 2 2 3
  Print();
  InsertAfter(3, 4);  // 0 1 2 2 3 4
  Print();
  WriteToFile("Liste.txt");
  Init();
  Print();
  ReadFromFile("Liste.txt");
  Print();

  return 0;

}