/*
** Verwaltung der Rechnungsliste
**
** Copyright (C) 1996 by Stefan Scherer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for non-commerical use and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation.  This software is provided "as is" without
** express or implied warranty.
*/

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

#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <dos/exall.h>
#include <clib/alib_protos.h>

#include "RechnungsListe.h"
#include "LocaleSupport.h"
#include "MiscSupport.h"

#define MAX_LINE_LEN 100

/* die kleinste Jahreszahl, ab der die Rechnungen verwaltet werden können */

#define BASE_YEAR 1993

/* der Pfadname für jeden Jahrgang. Die Jahreszahl wird noch angehängt */

#define BASE_DIR  "Rechnungen"


/* die Liste enthält Node-Strukturen mit den Auftragsdaten */

struct InvoiceNode
  {
    struct Node Node;
    struct MinInvoice invoice;
  };

/* 3.3.96, ss: zum Korrigieren der Artikelmengen */
static struct MinInvoice miLastLoaded;	/* zuletzt geladene Rechnung */


/* jeder Jahrgang wird zusätzlich verwaltet */

struct YearNode
  {
    struct Node Node;	/* Node zum verketten */
    struct List List;	/* Liste aller Rechnungen in diesem Jahr */
    struct InvoiceNode *aktInvoice;  /* die aktuelle Rechnung dieses Jahrs */
    UWORD itemCount;	/* Anzahl Rechnungen in diesem Jahr */
    UWORD aktNummer;	/* Nummer des aktuellen Eintrags in der Liste */
    UWORD Year;
  };


static struct YearNode *aktList;
static struct List invYears;
static UWORD yearCount;

/* Zeiger auf den Memory-Pool */

static void *poolHeader = NULL;	/* Zeiger für Memory-Pool */


/* intern wird ein Status mitgeführt, der anzeigt, was alles geladen wurde */

enum
  {
    STATUS_NOTHING,		/* es wurde noch nichts geladen */
    STATUS_LISTS		/* es wurden alle Auftragslisten geladen */
  };

static int status;


/* private Prototypen */

static int ReadDir (UWORD year);
static int WriteDir (UWORD year);
static int CompareNumbers (struct InvoiceNode *l, struct InvoiceNode *r);


/*
** Fehlercode und Fehlerstrings
*/

static int error;
static const STRPTR errormsg[] =
{
  "",				//   ERR_IL_OK
   "ungültiges Jahr",		//   ERR_IL_YEAR
   "Liste ist leer",		//   ERR_IL_LISTEMPTY
   "Eintrag nicht in Liste",	//   ERR_IL_NOITEM
   "kein Speicher",		//   ERR_IL_NOMEM
   "kein memorypool",		//   ERR_IL_NOPOOL
   "Fehler bei Pfad",		//   ERR_IL_NOPATH
   "Fehler bei ExAll()",	//   ERR_IL_EXALL
   "",				//   ERR_IL_INVOICE -> I_GetErrorMsg()
   "Konnte File nicht erzeugen",	//   ERR_IL_CANTCREATEFILE
   "Fehler beim speichern",	//   ERR_IL_SAVE
};


int 
ConstructInvoiceList (void)
{
  int i;
  ULONG year;

  IL_ResetLastLoaded ();

  NewList (&invYears);
  aktList = NULL;
  yearCount = 0;

  status = STATUS_NOTHING;

  /* neuen Memory-Pool anfordern */

  if (!(poolHeader = LibCreatePool (MEMF_CLEAR, 4000, 4000)))
    return (error = ERR_IL_NOPOOL);

  /* Files einlesen */

  year = GetThisYear ();
  for (i = BASE_YEAR; i < year; i++)
    {
      /* fügt ein Jahr in die Liste ein und dort noch die Aufträge */
      ReadDir (i);
    }

  ReadDir (year);

  status = STATUS_LISTS;

  IL_SetYear (year);

  return (0);
}


/*
** alles aufräumen
*/

void 
DestructInvoiceList (void)
{
//   UWORD year, i;
//
//   if( status == STATUS_LISTS )
//   {
//         /* Files speichern */
//
//         year = GetThisYear();
//         for( i = BASE_YEAR; i <= year; i++ )
//         {
//            WriteDir( i );  /* schreibt alle Listen der Jahrgänge in Files */
//         }
//      }

  if (poolHeader)
    {
      LibDeletePool (poolHeader);
      poolHeader = NULL;
    }
}


/*
** Setze den aktuellen Jahrgang
*/

int 
IL_SetYear (UWORD year)
{
  struct YearNode *node;

  for (node = (struct YearNode *) invYears.lh_Head;
       node->Node.ln_Succ && (year != node->Year);
       node = (struct YearNode *) node->Node.ln_Succ);

  if (node->Node.ln_Succ)
    {
      aktList = node;
      return (error = ERR_IL_OK);
    }
  else
    return (error = ERR_IL_YEAR);
}


/*
** ermittle das aktuelle Jahr
*/

UWORD 
IL_GetCurrentYear (void)
{
  if (!aktList)
    return (0);

  return (aktList->Year);
}


/*
** ermittle ein bestimmtes Jahr
*/

int 
IL_GetYear (UWORD num, UWORD * year)
{
  int i;
  struct YearNode *node;

  if (yearCount == 0)
    return (error = ERR_IL_YEAR);

  if (num >= yearCount)
    return (error = ERR_IL_YEAR);

  for (i = 0, node = (struct YearNode *) invYears.lh_Head;
       i < num && node->Node.ln_Succ;
       i++, node = (struct YearNode *) node->Node.ln_Succ);

  *year = node->Year;
  return (error = ERR_IL_OK);
}


/*
** bestimme die Nummer des aktuellen Jahres in der Liste
*/

UWORD 
IL_GetCurrentYearNumber (void)
{
  UWORD i;
  struct YearNode *node;

  if (yearCount == 0)
    return (0);

  for (i = 0, node = (struct YearNode *) invYears.lh_Head;
       node->Node.ln_Succ && (aktList->Year != node->Year);
       i++, node = (struct YearNode *) node->Node.ln_Succ);

  return (i);
}


/*
** ermittle die Anzahl der Jahre
*/

UWORD 
IL_GetYearCount (void)
{
  return (yearCount);
}


/*
** neue Rechnung in die Liste übernehmen 
*/

static int 
private_NewInvoice (struct MinInvoice *item)
{
  struct InvoiceNode *newitem;
  int result = ERR_IL_OK;

  if (!(newitem = LibAllocPooled (poolHeader, sizeof (struct InvoiceNode))))
      return (error = ERR_IL_NOMEM);

  newitem->invoice.invoiceNumber = item->invoiceNumber;
  newitem->invoice.invoiceYear = item->invoiceYear;
  strcpy (newitem->invoice.invoiceDate, item->invoiceDate);
  strcpy (newitem->invoice.Kunde, item->Kunde);
  newitem->invoice.orderNumber = item->orderNumber;
  newitem->invoice.orderYear = item->orderYear;
  strcpy (newitem->invoice.orderDate, item->orderDate);
  newitem->invoice.payment = item->payment;
  newitem->invoice.sum = item->sum;
  strcpy (newitem->invoice.payDate, item->payDate);
  strcpy (newitem->invoice.printDate, item->printDate);

  AddTail (&aktList->List, (struct Node *) newitem);

  aktList->aktInvoice = newitem;
  aktList->itemCount++;
  aktList->aktNummer = aktList->itemCount;	/* Zählung erfolgt von 1 ... */

  return (error = result);
}

/*
** Öffentlich: speichert noch die Rechnungsliste mit ab
*/

int 
IL_NewInvoice (struct MinInvoice *item)
{
  int result = ERR_IL_OK;

  result = private_NewInvoice (item);
  result = WriteDir (aktList->Year);

  return (error = result);
}


/*
** Rechnung aus Liste löschen
*/

int 
IL_DelInvoice (void)
{
  struct InvoiceNode *newakt;
  char filename[80];
  int result;

  if (aktList->itemCount == 0)
    return (error = ERR_IL_LISTEMPTY);

  /* File auch noch löschen */
  sprintf (filename, "%s%04d/%03d.%s", BASE_DIR,
	   aktList->aktInvoice->invoice.invoiceYear,
	   aktList->aktInvoice->invoice.invoiceNumber,
	   aktList->aktInvoice->invoice.Kunde);
  unlink (filename);

  if (aktList->aktNummer == aktList->itemCount)
    {
      if (aktList->itemCount > 1)
	newakt = (struct InvoiceNode *) aktList->aktInvoice->Node.ln_Pred;
      else
	newakt = NULL;

      RemTail (&aktList->List);
      LibFreePooled (poolHeader, aktList->aktInvoice,
                     sizeof (struct InvoiceNode));
      aktList->aktNummer--;
      aktList->itemCount--;
      aktList->aktInvoice = newakt;
    }
  else
    {
      if (aktList->itemCount > 1)
	newakt = (struct InvoiceNode *) aktList->aktInvoice->Node.ln_Succ;
      else
	{
	  newakt = NULL;
	  aktList->aktNummer = 0;
	}

      Remove ((struct Node *) aktList->aktInvoice);
      LibFreePooled (poolHeader, aktList->aktInvoice,
                     sizeof (struct InvoiceNode));
      aktList->itemCount--;
      aktList->aktInvoice = newakt;
    }

  result = WriteDir (aktList->Year);

  return (error = result);
}


/*
** aktuelle Rechnungsdaten in der Liste ändern
*/

int 
IL_ChangeInvoice (struct MinInvoice *item)
{
  int result;

  if (aktList->itemCount == 0)
    return (error = ERR_IL_LISTEMPTY);

  aktList->aktInvoice->invoice.invoiceNumber = item->invoiceNumber;
  aktList->aktInvoice->invoice.invoiceYear = item->invoiceYear;
  strcpy (aktList->aktInvoice->invoice.invoiceDate, item->invoiceDate);
  strcpy (aktList->aktInvoice->invoice.Kunde, item->Kunde);
  aktList->aktInvoice->invoice.orderNumber = item->orderNumber;
  aktList->aktInvoice->invoice.orderYear = item->orderYear;
  strcpy (aktList->aktInvoice->invoice.orderDate, item->orderDate);
  aktList->aktInvoice->invoice.payment = item->payment;
  aktList->aktInvoice->invoice.sum = item->sum;
  strcpy (aktList->aktInvoice->invoice.payDate, item->payDate);
  strcpy (aktList->aktInvoice->invoice.printDate, item->printDate);

  result = WriteDir (aktList->Year);

  return (error = result);
}


/*
** mache die Rechnung mit der Nummer 'number' zum aktuellen
**
** das ist NICHT die Position in der Liste !
*/

int 
IL_SetCurrentInvoiceNumber (UWORD number)
{
  int i;
  struct InvoiceNode *node;

  if (aktList->itemCount == 0)
    return (error = ERR_IL_LISTEMPTY);

  for (i = 0, node = (struct InvoiceNode *) aktList->List.lh_Head;
       node->Node.ln_Succ && (node->invoice.invoiceNumber != number);
       i++, node = (struct InvoiceNode *) node->Node.ln_Succ);

  if (node->Node.ln_Succ)
    {
      aktList->aktInvoice = node;
      aktList->aktNummer = i + 1;
      return (error = ERR_IL_OK);
    }
  else
    return (error = ERR_IL_NOITEM);
}


/*
** lies die Anzahl der Aufträge im aktuellen Jahr
*/

UWORD 
IL_GetInvoiceCount (void)
{
  return (aktList->itemCount);
}


/*
** lies die Daten einer Rechnung im aktuellen Jahr
*/

int 
IL_GetInvoice (UWORD num, struct MinInvoice *item)
{
  struct InvoiceNode *node;
  int i;

  if (aktList->itemCount == 0)
    return (error = ERR_IL_LISTEMPTY);

  if (num >= aktList->itemCount)
    return (error = ERR_IL_NOITEM);

  for (i = 0, node = (struct InvoiceNode *) aktList->List.lh_Head;
       i < num && node->Node.ln_Succ;
       i++, node = (struct InvoiceNode *) node->Node.ln_Succ);

  item->invoiceNumber = node->invoice.invoiceNumber;
  item->invoiceYear = node->invoice.invoiceYear;
  strcpy (item->invoiceDate, node->invoice.invoiceDate);
  strcpy (item->Kunde, node->invoice.Kunde);
  item->orderNumber = node->invoice.orderNumber;
  item->orderYear = node->invoice.orderYear;
  strcpy (item->orderDate, node->invoice.orderDate);
  item->payment = node->invoice.payment;
  item->sum = node->invoice.sum;
  strcpy (item->payDate, node->invoice.payDate);
  strcpy (item->printDate, node->invoice.printDate);

  return (error = ERR_IL_OK);
}


/*
** lies die Daten der aktuellen Rechnung im aktuellen Jahr
*/

int 
IL_GetCurrentInvoice (struct MinInvoice *item)
{
  if (aktList->itemCount == 0)
    return (error = ERR_IL_LISTEMPTY);

  item->invoiceNumber = aktList->aktInvoice->invoice.invoiceNumber;
  item->invoiceYear = aktList->aktInvoice->invoice.invoiceYear;
  strcpy (item->invoiceDate, aktList->aktInvoice->invoice.invoiceDate);
  strcpy (item->Kunde, aktList->aktInvoice->invoice.Kunde);
  item->orderNumber = aktList->aktInvoice->invoice.orderNumber;
  item->orderYear = aktList->aktInvoice->invoice.orderYear;
  strcpy (item->orderDate, aktList->aktInvoice->invoice.orderDate);
  item->payment = aktList->aktInvoice->invoice.payment;
  item->sum = aktList->aktInvoice->invoice.sum;
  strcpy (item->payDate, aktList->aktInvoice->invoice.payDate);
  strcpy (item->printDate, aktList->aktInvoice->invoice.printDate);

  return (error = ERR_IL_OK);
}


/*
** ermittle die Nummer des aktuellen Eintrags in der Liste
**
** das ist NICHT die Nummer (=Position) in der Liste!
*/

int 
IL_GetCurrentInvoiceNumber (void)
{
  if (aktList->aktInvoice)
    return (aktList->aktInvoice->invoice.invoiceNumber);
  else
    return (0);
}


/*
** Lies das Directory anhand des angegebenen Jahrganges ein
** und baue die Auftrags-Liste auf.
*/

static int 
ReadDir (UWORD year)
{
  struct YearNode *newitem;
  char dirname[30];
  char filename[50];
  FILE *file;
  BPTR lock;
  BOOL ok = TRUE;
  struct MinInvoice mininvoice;
  char buffer[MAX_LINE_LEN];
  STRPTR p;
  int result = ERR_IL_OK;

  if (!(newitem = LibAllocPooled (poolHeader, sizeof (struct YearNode))))
      return (error = ERR_IL_NOMEM);

  newitem->Year = year;
  NewList (&newitem->List);
  newitem->aktInvoice = NULL;
  newitem->aktNummer = 0;
  AddTail (&invYears, (struct Node *) newitem);
  yearCount++;

  IL_SetYear (year);

  /* Directory einlesen und im Jahrgang einfügen */
  /* wenn Dir nicht vorhanden, dann neu anlegen */

  sprintf (dirname, "%s%04d", BASE_DIR, year);
  sprintf (filename, "%s%04d/RechnungsListe", BASE_DIR, year);

  /* wenn Pfad nicht vorhanden, dann neu anlegen */
  if (!(lock = Lock (dirname, ACCESS_READ)))
    {
      lock = CreateDir (dirname);
    }

  if (lock)
    {
      /* Pfad vorhanden */
      if (file = fopen (filename, "r"))
	{
	  while (ok)
	    {
	      /*
	      ** · Rechnungsnummer/jahr
	      */

	      if (ok && !fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;
	      if (p = strchr (buffer, '\n'))
		*p = 0;

	      if (ok)
		{
		  STRPTR p;
		  if (p = strchr (buffer, '/'))
		    {
		      mininvoice.invoiceYear = atol (buffer);
		      mininvoice.invoiceNumber = atol (p + 1);
		    }
		  else
		    {
		      mininvoice.invoiceYear = 0;
		      mininvoice.invoiceNumber = 0;
		    }
		}

	      /*
	      ** · Rechnungsdatum
	      */

	      if (ok && !fgets (mininvoice.invoiceDate, 12, file))
		ok = FALSE;
	      if (p = strchr (mininvoice.invoiceDate, '\n'))
		*p = 0;

	      /*
	      ** · Kunde
	      */

	      if (!fgets (mininvoice.Kunde, 100, file))
		ok = FALSE;
	      if (p = strchr (mininvoice.Kunde, '\n'))
		*p = 0;

	      /*
	      ** · Auftragsnummer/jahr
	      */

	      if (ok && !fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;
	      if (p = strchr (buffer, '\n'))
		*p = 0;

	      if (ok)
		{
		  STRPTR p;
		  if (p = strchr (buffer, '/'))
		    {
		      mininvoice.orderYear = atol (buffer);
		      mininvoice.orderNumber = atol (p + 1);
		    }
		  else
		    {
		      mininvoice.orderYear = 0;
		      mininvoice.orderNumber = 0;
		    }
		}

	      /*
	      ** · Auftragsdatum
	      */

	      if (ok && !fgets (mininvoice.orderDate, 12, file))
		ok = FALSE;
	      if (p = strchr (mininvoice.orderDate, '\n'))
		*p = 0;

	      /*
	      ** · (bisher) bezahlter Betrag
	      */

	      if (ok && !fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;
	      mininvoice.payment = ScanMonetaryMulti (buffer);

	      /*
	      ** · Rechnungssumme
	      */

	      if (ok && !fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;
	      mininvoice.sum = ScanMonetaryMulti (buffer);

	      /*
	      ** · Zahlungsdatum
	      */

	      if (ok && !fgets (mininvoice.payDate, 12, file))
		ok = FALSE;
	      if (p = strchr (mininvoice.payDate, '\n'))
		*p = 0;

	      /*
	      ** · Druckdatum
	      */

	      if (ok && !fgets (mininvoice.printDate, 12, file))
		ok = FALSE;
	      if (p = strchr (mininvoice.printDate, '\n'))
		*p = 0;

	      /*
	      ** · Leerzeile
	      */

	      if (ok && !fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;

	      if (ok && private_NewInvoice (&mininvoice))
		ok = FALSE;
	    }

	  fclose (file);
	}
      else
	{
	  /* "Rechnungsliste.dat" ist noch nicht vorhanden, also
	  ** neu aufbauen
	  */

	  struct ExAllData *ead;
	  struct ExAllControl *eac;
	  struct InvoiceNode *newitem;
	  struct ExAllData *mem;
	  char patsrc[10], pattern[32];
	  BOOL more;
	  struct MinInvoice mininvoice;

	  strcpy (patsrc, "???.#?");

	  eac = AllocDosObject (DOS_EXALLCONTROL, NULL);
	  if (eac)
	    {
	      if (mem = calloc (10000, 1))
		{
		  eac->eac_LastKey = 0;
		  ParsePatternNoCase (patsrc, pattern, 30);
		  eac->eac_MatchString = pattern;
		  do
		    {
		      more = ExAll (lock, mem, 10000, ED_NAME, eac);
		      if ((!more) && (IoErr () != ERROR_NO_MORE_ENTRIES))
			{
			  /* ExAll failed abnormally */
			  result = ERR_IL_EXALL;
			  break;
			}
		      if (eac->eac_Entries == 0)
			{
			  /* ExAll failed normally with no entries */
			  continue;	/* ("more" is *usually* zero) */
			}
		      ead = (struct ExAllData *) mem;
		      do
			{
			  /* use ead here */
			  sprintf (filename, "%s/%s", dirname, ead->ed_Name);
			  if (I_LoadInvoice (filename, FALSE))
			    result = ERR_IL_INVOICE;
			  I_GetMinInvoice (&mininvoice);

			  if (newitem = LibAllocPooled (poolHeader,
			                         sizeof (struct InvoiceNode)))
			    {
			      newitem->invoice.invoiceNumber =
			                              mininvoice.invoiceNumber;
			      newitem->invoice.invoiceYear =
			                              mininvoice.invoiceYear;
			      strcpy (newitem->invoice.invoiceDate,
			              mininvoice.invoiceDate);
			      strcpy (newitem->invoice.Kunde,
			              mininvoice.Kunde);
			      newitem->invoice.orderNumber =
			                              mininvoice.orderNumber;
			      newitem->invoice.orderYear =
			                              mininvoice.orderYear;
			      strcpy (newitem->invoice.orderDate,
			              mininvoice.orderDate);
			      newitem->invoice.payment = mininvoice.payment;
			      newitem->invoice.sum = mininvoice.sum;
			      strcpy (newitem->invoice.payDate,
			              mininvoice.payDate);
			      strcpy (newitem->invoice.printDate,
			              mininvoice.printDate);

			      InsertSorted (&aktList->List,
			                    (struct Node *) newitem,
					    NULL, CompareNumbers);

			      aktList->aktInvoice = (struct InvoiceNode *)
			                            aktList->List.lh_TailPred;
			      aktList->itemCount++;
			      /* Zählung erfolgt von 1 ... */
			      aktList->aktNummer = aktList->itemCount;
			    }
			  else
			    result = ERR_IL_NOMEM;

			  /* get next ead */
			  ead = ead->ed_Next;
			}
		      while (ead);

		    }
		  while (more);

		  free (mem);
		}
	      else
		result = ERR_IL_NOMEM;
	      FreeDosObject (DOS_EXALLCONTROL, eac);
	    }
	  else
	    result = ERR_IL_NOMEM;
	}

      /* Lock auf Directory nun freigeben */
      UnLock (lock);
    }
  else
    result = ERR_IL_NOPATH;

  return (error = result);
}


/*
** Schreibe die intern verwaltete Rechnungs-Liste des angegebenen Jahres in
** ein File.
*/

static int 
WriteDir (UWORD year)
{
  char dirname[30];
  char filename[50];
  FILE *file;
  BPTR lock;
  BOOL ok = TRUE;
  struct InvoiceNode *node;
  char buf1[20], buf2[20];
  int result = ERR_IL_OK;

  IL_SetYear (year);

  /* Jahrgang im File speichern */
  /* wenn Dir nicht vorhanden, dann neu anlegen */

  sprintf (dirname, "%s%04d", BASE_DIR, year);
  sprintf (filename, "%s%04d/RechnungsListe", BASE_DIR, year);

  /* wenn Pfad nicht vorhanden, dann neu anlegen */
  if (!(lock = Lock (dirname, ACCESS_READ)))
    {
      lock = CreateDir (dirname);
    }

  if (lock)
    {
      /* Pfad vorhanden */
      UnLock (lock);
      if (file = fopen (filename, "w"))
	{
	  for (node = (struct InvoiceNode *) aktList->List.lh_Head;
	       ok && node->Node.ln_Succ;
	       node = (struct InvoiceNode *) node->Node.ln_Succ)
	    {
	      /*
	      ** · Rechnungsnummer/jahr
	      ** · Rechnungsdatum
	      ** · Kunde
	      ** · Auftragsnummer/jahr
	      ** · Auftragsdatum
	      ** · bezahlter Betrag
	      ** · Rechnungssumme
	      ** · Zahldatum
	      ** · Druckdatum
	      ** · Leerzeile
	      */

	      if (fprintf (file, "%04d/%d\n%s\n%s\n%04d/%d\n%s\n",
		     node->invoice.invoiceYear, node->invoice.invoiceNumber,
			   node->invoice.invoiceDate, node->invoice.Kunde,
			 node->invoice.orderYear, node->invoice.orderNumber,
			   node->invoice.orderDate) < 0)
		ok = FALSE;

	      PrintMonetary (buf1, node->invoice.payment);
	      PrintMonetary (buf2, node->invoice.sum);

	      if (ok && fprintf (file, "%s\n%s\n%s\n%s\n\n",
				 buf1, buf2, node->invoice.payDate,
				 node->invoice.printDate) < 0)
		ok = FALSE;
	    }
	  if (!ok)
	    result = ERR_IL_SAVE;

	  fclose (file);
	}
      else
	result = ERR_IL_CANTCREATEFILE;
    }
  else
    result = ERR_IL_NOPATH;

  return (error = result);
}


/*
** lies die Rechnungsnummer, die größer als die
** bisher größte ist. (saved+1)
*/

UWORD 
IL_GetNextInvoiceNumber (void)
{
  if (aktList)
    {
      if (IsListEmpty (&aktList->List))
	return (1);
      else
	return ((UWORD) (((struct InvoiceNode *)
	        (aktList->List.lh_TailPred))->invoice.invoiceNumber + 1));
    }
  return (0);
}


/*
** lade eine bestimmte Rechnung
*/

int 
IL_LoadInvoice (struct MinInvoice *mininvoice, BOOL bCorrectNumbers)
{
  char filename[150];
  int result = ERR_IL_OK;

  /* Daten geladener Rechnung merken zum evtl. Korrigieren der Art.-Mengen */
  memcpy (&miLastLoaded, mininvoice, sizeof (struct MinInvoice));

  /* Filename: z.B.   "Rechnungen1994/003.Scherer" */
  sprintf (filename, "%s%04d/%03d.%s", BASE_DIR, mininvoice->invoiceYear,
	   mininvoice->invoiceNumber, mininvoice->Kunde);

  if (I_LoadInvoice (filename, bCorrectNumbers))
    result = ERR_IL_INVOICE;

  return (error = result);
}


/*
** speichere eine bestimmte Rechnung
*/

int 
IL_SaveInvoice (struct MinInvoice *mininvoice, BOOL bCorrectNumbers)
{
  char filename[60];
  char dirname[30];
  char patsrc[10], pattern[32];
  BPTR lock;
  BOOL more;
  struct ExAllData *ead;
  struct ExAllControl *eac;
  struct ExAllData *mem;
  int result = ERR_IL_OK;

  /* Directory-Name und Pattern bestimmen */
  sprintf (dirname, "%s%04d", BASE_DIR, mininvoice->invoiceYear);
  sprintf (patsrc, "%03d.#?", mininvoice->invoiceNumber);


  /* wenn Pfad nicht vorhanden, dann neu anlegen */
  if (!(lock = Lock (dirname, ACCESS_READ)))
    {
      lock = CreateDir (dirname);
    }

  if (lock)
    {
      /* Pfad vorhanden */

      /* suche nach gleichen Auftragsnummern und lösche diese Dateien */

      eac = AllocDosObject (DOS_EXALLCONTROL, NULL);
      if (eac)
	{
	  if (mem = calloc (10000, 1))
	    {
	      eac->eac_LastKey = 0;
	      ParsePatternNoCase (patsrc, pattern, 30);
	      eac->eac_MatchString = pattern;
	      do
		{
		  more = ExAll (lock, mem, 10000, ED_NAME, eac);
		  if ((!more) && (IoErr () != ERROR_NO_MORE_ENTRIES))
		    {
		      /* ExAll failed abnormally */
		      result = ERR_IL_EXALL;
		      break;
		    }
		  if (eac->eac_Entries == 0)
		    {
		      /* ExAll failed normally with no entries */
		      continue;	/* ("more" is *usually* zero) */
		    }
		  ead = (struct ExAllData *) mem;
		  do
		    {
		      /* use ead here */
		      sprintf (filename, "%s/%s", dirname, ead->ed_Name);
		      unlink (filename);   /* lösche alle gefundenen Files */
		      /* get next ead */
		      ead = ead->ed_Next;
		    }
		  while (ead);

		}
	      while (more);

	      free (mem);
	    }
	  else
	    result = ERR_IL_NOMEM;
	  FreeDosObject (DOS_EXALLCONTROL, eac);
	}
      else
	result = ERR_IL_NOMEM;

      UnLock (lock);		/* Lock auf Directory freigeben */

      /* Filename: z.B.   "Rechnungen1994/003.Scherer" */
      sprintf (filename, "%s%04d/%03d.%s", BASE_DIR, mininvoice->invoiceYear,
	       mininvoice->invoiceNumber, mininvoice->Kunde);

      if (I_SaveInvoice (filename, bCorrectNumbers))
	result = ERR_IL_INVOICE;
    }
  else
    result = ERR_IL_NOPATH;

  return (error = result);
}




/*
** um die Einträge sortieren zu können, wird eine Vergleichsfunktion
** benötigt. Diese vergleich zwei Kundeneinträge miteinander und
** gibt einen Wert zurück, der dem Vergleich entspricht.
**
** mögliche Rückgabewerte:
**
**    l < r      l = r      l > r
**     -1          0          1
*/

static int 
CompareNumbers (struct InvoiceNode *l, struct InvoiceNode *r)
{
  return (l->invoice.invoiceNumber - r->invoice.invoiceNumber);
}


/*
** Fehlerstring erfragen
*/

STRPTR 
IL_GetErrorMsg (void)
{
  if (error == ERR_IL_INVOICE)
    return (I_GetErrorMsg ());
  else
    return (errormsg[error]);
}


/* 3.3.96, ss: korrigiere die Artikelmengen beim Abbruch einer Rechnung. */

int 
IL_CorrectArticleCount (void)
{
  int result = ERR_IL_OK;

  if (miLastLoaded.invoiceYear)
    {
      if (!(result = IL_LoadInvoice (&miLastLoaded, FALSE)))
	{
	  result = IL_SaveInvoice (&miLastLoaded, TRUE);
	}
    }


  return (result);
}

void 
IL_ResetLastLoaded (void)
{
  miLastLoaded.invoiceYear = 0;
}
