/*
** Verwaltung der Briefe
**
** 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.
*/

#define LOAD_BUF_SIZE 64000
#define LOAD_LINEBUF_SIZE 8000

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

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

#include "Briefe.h"
#include "LocaleSupport.h"

/* die Rechnung erhält allgemeine Daten
** prinzipiell könnte man daraus auch schon eine Rechnungsliste
** machen und alle Funktionen erweitern, so daß sie nur mit Zeigern
** auf solche Strukturen arbeiten.
*/

struct Letter
  {
    struct MinCustomer customer;	/* der Kunde dieser Rechnung */

    UWORD letterNumber;
    UWORD letterYear;		/* bilden beide die komplette Rech-Nr. */
    char letterDate[12];	/* Tag, an dem Rechnung erstellt wurde */

    char printDate[12];		/* Tag, an dem Rechnung gedruckt wurde */

    char orderDate[12];		/* Tag, an dem Auftrag erstellt wurde */

    char Betreff[100];		/* kurzer Kommentar für den Brief */

/* alle Artikel werden in einer Liste gehalten. Zusätzlich werden noch ein
** paar Informationen mitgeführt 
*/
    ULONG Size;			/* Länge des Textes in Byte */
    STRPTR Contents;		/* Inhalt des Briefes als ASCII-Text */

/* 17.11.94: neue Einträge */

    char Unit[8];		/* Währung als String, DM */
    char GroupSeparator[8], DecimalPoint[8], FracGroupSeparator[8];
  };

/* Länge einer Zeile im Rechnungsfile (Bezeichnung + Rest in einer Zeile ) */

#define MAX_LINE_LEN 200


/* intern wird nur eine Rechnung im Speicher gehalten. */

static struct Letter let;


/* Zeiger auf den Memory-Pool */

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


/* der Status, ob die Rechnung verändert wurde
** TRUE  - geändert (-> muß noch gespeichert werden...)
** FALSE - nicht geändert
*/

static BOOL status;


/* Fehlercode und Fehlerstrings */

static int error;
static const STRPTR errormsg[] =
{
  "",				//   ERR_LET_OK
   "kein memorypool",		//   ERR_LET_NOPOOL
   "kein Speicher",		//   ERR_LET_NOMEM
   "Liste ist leer",		//   ERR_LET_LISTEMPTY
   "Eintrag nicht in Liste",	//   ERR_LET_NOITEM
   "File nicht gefunden",	//   ERR_LET_FILENOTFOUND
   "Konnte File nicht erzeugen",	//   ERR_LET_CANTCREATEFILE
   "Fehler beim laden",		//   ERR_LET_LOAD
   "Fehler beim schreiben",	//   ERR_LET_SAVE
};

/*
** Konstruktor-Funktion zum Initialisieren 
*/

int 
ConstructLetter (void)
{
  return (LE_NewLetter ());
}


/*
** Destruktor-Funktion
*/

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


/*
** neuen Brief beginnen. Alle Daten werden zurückgesetzt.
*/

int 
LE_NewLetter (void)
{
  status = FALSE;

  let.customer.Adresse1[0] = 0;
  let.customer.Adresse2[0] = 0;
  let.customer.Adresse3[0] = 0;
  let.customer.Adresse4[0] = 0;
  let.customer.Adresse5[0] = 0;
  let.customer.KundenNummer = 0;
  let.customer.Zeichen[0] = 0;

  let.letterNumber = 0;
  let.letterYear = GetThisYear ();

  /* Briefdatum auf heutigen Tag setzen */
  let.letterDate[0] = 0;
  CorrectDate (let.letterDate);

  let.printDate[0] = 0;
  let.orderDate[0] = 0;

  let.Betreff[0] = 0;

  let.Contents = NULL;
  let.Size = 0;

  strcpy (let.Unit, Locale->loc_MonCS);
  strcpy (let.GroupSeparator, Locale->loc_MonGroupSeparator);
  strcpy (let.DecimalPoint, Locale->loc_MonDecimalPoint);
  strcpy (let.FracGroupSeparator, Locale->loc_MonFracGroupSeparator);

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

  /* neuen Memory-Pool anfordern */
  if (!(poolHeader = LibCreatePool (MEMF_CLEAR, 4000, 4000)))
    return (error = ERR_LET_NOPOOL);

  return (error = ERR_LET_OK);
}


/*
** neue Kundenadresse übernehmen
*/

void 
LE_SetLetterAddress (struct MinCustomer *cust)
{
  status = TRUE;
  strcpy (let.customer.Adresse1, cust->Adresse1);
  strcpy (let.customer.Adresse2, cust->Adresse2);
  strcpy (let.customer.Adresse3, cust->Adresse3);
  strcpy (let.customer.Adresse4, cust->Adresse4);
  strcpy (let.customer.Adresse5, cust->Adresse5);
  strcpy (let.customer.Zeichen, cust->Zeichen);
  let.customer.KundenNummer = cust->KundenNummer;
}

void 
LE_GetLetterAddress (struct MinCustomer *cust)
{
  strcpy (cust->Adresse1, let.customer.Adresse1);
  strcpy (cust->Adresse2, let.customer.Adresse2);
  strcpy (cust->Adresse3, let.customer.Adresse3);
  strcpy (cust->Adresse4, let.customer.Adresse4);
  strcpy (cust->Adresse5, let.customer.Adresse5);
  strcpy (cust->Zeichen, let.customer.Zeichen);
  cust->KundenNummer = let.customer.KundenNummer;
}

/*
**  Ändere den aktuellen Inhalt
*/

int 
LE_SetLetterContents (STRPTR text, ULONG size)
{
  status = TRUE;

  if (let.Contents)
    LibFreePooled (poolHeader, let.Contents, let.Size + 1);

  if (!(let.Contents = LibAllocPooled (poolHeader, size + 1)))
    return (error = ERR_LET_NOMEM);
  strncpy (let.Contents, text, size);
  let.Contents[size] = 0;
  let.Size = size;

  return (error = ERR_LET_OK);
}


/*
**  Lese den Inhalt aus
*/

int 
LE_GetLetterContents (STRPTR * text)
{
  if (let.Contents == 0)
    *text = "";
  else
    *text = let.Contents;

  return (error = ERR_LET_OK);
}

int 
LE_GetDummyLetterContents (STRPTR * text)
{
  if (let.Contents == 0)
    *text = "";
  else
    {
      if (let.Size > 500)
	*text = "";
      else
	*text = let.Contents;
    }

  return (error = ERR_LET_OK);
}

/*
**  neue Rechnungsnummer erstellen
**
**  Die Rechnungsnummer wird nach der Form "Jahr/Nr" in den Puffer geschrieben.
*/

void 
LE_GetLetterNumber (STRPTR buffer)
{
  sprintf (buffer, "%04d/%d", let.letterYear, let.letterNumber);
}


/*
**  setze die Rechnungsnummer auf einen bestimmten Wert
**
**  Der übergebene String wird automatisch korrigiert !!
*/

void 
LE_SetLetterNumber (STRPTR buffer)
{
  STRPTR p;

  status = TRUE;
  if (p = strchr (buffer, '/'))
    {
      let.letterYear = atol (buffer);
      let.letterNumber = atol (p + 1);
    }
  else
    {
      let.letterYear = GetThisYear ();
      let.letterNumber = atol (buffer);
      LE_GetLetterNumber (buffer);
    }
}


/*
** Datum der Rechnungserstellung setzen
*/

void 
LE_SetLetterDate (STRPTR date)
{
  status = TRUE;
  strncpy (let.letterDate, date, 10);
  let.letterDate[10] = 0;
}

/*
** Datum der Auftragserstellung setzen
*/

void 
LE_SetOrderDate (STRPTR date)
{
  status = TRUE;
  strncpy (let.orderDate, date, 10);
  let.orderDate[10] = 0;
}

/*
** Datum des Ausdrucks setzen
*/

void 
LE_SetPrintDate (STRPTR date)
{
  status = TRUE;
  strncpy (let.printDate, date, 10);
  let.printDate[10] = 0;
}

void 
LE_SetBetreff (STRPTR betreff)
{
  status = TRUE;
  strncpy (let.Betreff, betreff, 99);
  let.Betreff[99] = 0;
}


/*
** Datum der Rechnungserstellung lesen
** Zielpuffer muß min. 11 Zeichen lang sein!
*/

void 
LE_GetLetterDate (STRPTR date)
{
  strncpy (date, let.letterDate, 10);
  date[10] = 0;
}

/*
** Datum der Auftragserstellung lesen
** Zielpuffer muß min. 11 Zeichen lang sein!
*/

void 
LE_GetOrderDate (STRPTR date)
{
  strncpy (date, let.orderDate, 10);
  date[10] = 0;
}

/*
** Datum des Ausdrucks lesen
** Zielpuffer muß min. 11 Zeichen lang sein!
*/

void 
LE_GetPrintDate (STRPTR date)
{
  strncpy (date, let.printDate, 10);
  date[10] = 0;
}

void 
LE_GetBetreff (STRPTR betreff)
{
  strncpy (betreff, let.Betreff, 99);
  betreff[99] = 0;
}


/*
**  Rechnung laden
**  Die bisherige Rechnung wird gelöscht!
**
** Die Rechnung wird als ASCII-Text gelesen und hat folgenden Inhalt:
**
**
** Zeile  Inhalt
** 
** 1      Anrede TAB Betreff
** 2      Kundenadresse
** 3      Kundenadresse
** 4      Kundenadresse
** 5      Kundenadresse
** 6      Kundennummer
**
** 17.11.94:
**------
** 6a     TAB
**
** 6b     Währung TAB
** 6c     Trenner vorkomma TAB
** 6d     Komma TAB
** 6e     Trenner nachkomma
**------
** 7      Ihre Zeichen
** 8      Briefjahr / Briefnummer
** 9      Datum für Feld "Ihr Schreiben vom"
** 10     Datum der Brieferstellung
** 11     Datum des Ausdrucks des Briefes
**
** 12  1  Modus1 TAB
**        Fließtext in einer Zeile
** 
** 12  2  Modus2 TAB
**        Position (links/rechts/zentriert) TAB
**        Schriftart (fett/kursiv...) TAB
**        Textzeile
** 
** 12  3  Modus3 TAB
**        Artikelbezeichnung TAB
**        Einzel-brutto(!)
** 
** 13     Abschluß der Liste mit einer Leerzeile
** 
** 
*/

int 
LE_LoadLetter (STRPTR filename)
{
  FILE *file;
  int result;
  STRPTR buffer, p, oldp, text, linebuffer;
  BOOL ok = TRUE, loop;
  int mode, linemode, fontmode;
  char minbuf[20];

  result = LE_NewLetter ();

  if (!result)
    {
      if (buffer = LibAllocPooled (poolHeader, LOAD_BUF_SIZE))
	{
	  *buffer = 0;
	  if (linebuffer = LibAllocPooled (poolHeader, LOAD_LINEBUF_SIZE))
	    {
	      *linebuffer = 0;

	      if (file = fopen (filename, "r"))
		{
		  /*
		  ** · Anrede TAB Betreff
		  ** · Kundenadresse (4 Zeilen)
		  */
		  if (!fgets (linebuffer, 2 * MAX_LET_LEN, file))
		    ok = FALSE;

		  if (p = strchr (linebuffer, '\t'))
		    {
		      *p++ = 0;
		      oldp = p;

		      strcpy (let.customer.Adresse1, linebuffer);
		      if (p = strchr (oldp, '\n'))
			*p++ = 0;
		      strcpy (let.Betreff, oldp);
		    }
		  else
		    {
		      if (p = strchr (linebuffer, '\n'))
			*p = 0;
		      strcpy (let.customer.Adresse1, linebuffer);
		      strcpy (let.Betreff, "");
		    }

		  if (ok && !fgets (let.customer.Adresse2, MAX_LET_LEN, file))
		    ok = FALSE;
		  if (p = strchr (let.customer.Adresse2, '\n'))
		    *p = 0;
		  if (ok && !fgets (let.customer.Adresse3, MAX_LET_LEN, file))
		    ok = FALSE;
		  if (p = strchr (let.customer.Adresse3, '\n'))
		    *p = 0;
		  if (ok && !fgets (let.customer.Adresse4, MAX_LET_LEN, file))
		    ok = FALSE;
		  if (p = strchr (let.customer.Adresse4, '\n'))
		    *p = 0;
		  if (ok && !fgets (let.customer.Adresse5, MAX_LET_LEN, file))
		    ok = FALSE;
		  if (p = strchr (let.customer.Adresse5, '\n'))
		    *p = 0;

		  /*
		  ** · Kundennummer
		  */
		  if (ok && !fgets (linebuffer, MAX_LET_LEN, file))
		    ok = FALSE;
		  if (ok)
		    let.customer.KundenNummer = atol (linebuffer);

		  /* alte Rechnung geladen, Währung IST deutsch */
		  strcpy (let.Unit, "DM");
		  strcpy (let.GroupSeparator, ".");
		  strcpy (let.DecimalPoint, ",");
		  strcpy (let.FracGroupSeparator, ".");


		  if (p = strchr (linebuffer, '\t'))
		    {
		      oldp = ++p;

		      if (p = strchr (oldp, '\t'))
			{
			  *p++ = 0;
			  strcpy (let.Unit, oldp);	/* Währung */
			  oldp = p;

			  if (p = strchr (oldp, '\t'))
			    {
			      *p++ = 0;
			      /* Trenner vorkomma */
			      strcpy (let.GroupSeparator, oldp);
			      oldp = p;

			      if (p = strchr (oldp, '\t'))
				{
				  *p++ = 0;
				  /* Komma */
				  strcpy (let.DecimalPoint, oldp);
				  oldp = p;

				  if (p = strchr (oldp, '\n'))
				    {
				      *p++ = 0;
				      /* Trenner nachkomma */
				      strcpy (let.FracGroupSeparator, oldp);
				    }
				}
			    }
			}
		    }


		  /*
		  ** · Ihre Zeichen
		  */
		  if (ok && !fgets (let.customer.Zeichen, MAX_LET_LEN, file))
		    ok = FALSE;
		  if (p = strchr (let.customer.Zeichen, '\n'))
		    *p = 0;

		  /*
		  ** · Briefjahr / Briefnummer
		  */
		  if (ok && !fgets (linebuffer, MAX_LINE_LEN, file))
		    ok = FALSE;
		  if (p = strchr (linebuffer, '\n'))
		    *p = 0;

		  if (ok)
		    {
		      STRPTR p;
		      if (p = strchr (linebuffer, '/'))
			{
			  let.letterYear = atol (linebuffer);
			  let.letterNumber = atol (p + 1);
			}
		      else
			{
			  let.letterYear = 1993;
			  let.letterNumber = atol (linebuffer);
			}
		    }

		  /*
		  ** · Datum für Feld "Ihr Schreiben vom"
		  */
		  if (ok && !fgets (let.orderDate, 12, file))
		    ok = FALSE;
		  if (p = strchr (let.orderDate, '\n'))
		    *p = 0;

		  /*
		  ** · Datum der Brieferstellung
		  */
		  if (ok && !fgets (let.letterDate, 12, file))
		    ok = FALSE;
		  if (p = strchr (let.letterDate, '\n'))
		    *p = 0;

		  /*
		  ** · Datum des Ausdrucks des Briefes
		  */
		  if (ok && !fgets (let.printDate, 12, file))
		    ok = FALSE;
		  if (p = strchr (let.printDate, '\n'))
		    *p = 0;


		  /* jetzt kommen die einzelnen Teile im Brief
		  ** bis eine Leerzeile kommt.
		  */
		  loop = TRUE;
		  while (loop && ok)
		    {
		      /*
		      **   1  Modus1 TAB
		      **      Fließtext in einer Zeile
		      ** 
		      **   2  Modus2 TAB
		      **      Position (links/rechts/zentriert) TAB
		      **      Schriftart (fett/kursiv...) TAB
		      **      Textzeile
		      ** 
		      **   3  Modus3 TAB
		      **      Artikelbezeichnung TAB
		      **      Einzel-brutto(!)
		      ** 
		      **   4  Modus4 TAB
		      **      Fließtext in einer Zeile (aber neue Version)
		      ** 
		      */
		      if (!fgets (linebuffer, LOAD_BUF_SIZE - 1, file))
			ok = FALSE;
		      if (ok)
			{
			  if (p = strchr (linebuffer, '\t'))
			    {
			      if (p != linebuffer)
				{
				  *p++ = 0;
				  mode = atoi (linebuffer);

				  text = p;
				  if (p = strchr (p, '\t'))
				    *p++ = 0;

				  switch (mode)
				    {
				    case LETMODE_LINE:
				      linemode = atoi (p);
				      if (p = strchr (p, '\t'))
					{
					  p++;
					  fontmode = atoi (p);
					}
				      if (linemode != LMODE_LEFT)
					strcat (buffer, "{ }");

				      if (fontmode == FMODE_BOLD)
					strcat (buffer, "{b}");

				      if (fontmode == FMODE_SLANTED)
					strcat (buffer, "{i}");

				      strcat (buffer, text);

				      if (fontmode != FMODE_NORMAL)
					strcat (buffer, "{n}");

				      if (linemode != LMODE_RIGHT)
					strcat (buffer, "{ }");

				      strcat (buffer, "\n");
				      break;

				    case LETMODE_ARTICLE:
				      PrintCurrency (minbuf,
				       ScanMonetaryNew (p,
				        let.GroupSeparator,
				        let.DecimalPoint,
				        let.FracGroupSeparator));
				      if (p = strchr (text, '\n'))
					*p++ = 0;
				      strcat (buffer, text);
				      strcat (buffer, " {d} ");
				      strcat (buffer, minbuf);
				      strcat (buffer, "\n");
				      break;

				    case LETMODE_TEXT:
				    default:
				      strcat (buffer, text);
				      strcat (buffer, "\n");
				      break;

				    case 4:
				      strcat (buffer, text);
				      break;
				    }
				}
			      else
				loop = FALSE;	/* letzter Eintrag erreicht */
			    }
			  else
			    loop = FALSE;	/* kein TAB vorhanden */
			}
		    }	/* liest alle Artikel ein, bis eine Leerzeile kommt */

		  LE_SetLetterContents (buffer, strlen (buffer));

		  status = FALSE;   /* geladene Rechnung wurde nicht geändert */

		  strcpy (let.Unit, Locale->loc_MonCS);
		  strcpy (let.GroupSeparator, Locale->loc_MonGroupSeparator);
		  strcpy (let.DecimalPoint, Locale->loc_MonDecimalPoint);
		  strcpy (let.FracGroupSeparator,
		          Locale->loc_MonFracGroupSeparator);

		  fclose (file);
		}
	      else
		result = ERR_LET_FILENOTFOUND;

	      LibFreePooled (poolHeader, linebuffer, LOAD_LINEBUF_SIZE);
	    }
	  else
	    result = ERR_LET_NOMEM;
	}
      else
	result = ERR_LET_NOMEM;
    }
  return (error = result);
}


/*
**  Brief speichern
**
** Der Brief wird als ASCII-Text gespeichert und hat folgenden Inhalt:
**
** Zeile  Inhalt
** 
** 1      Anrede TAB Betreff
** 2      Kundenadresse
** 3      Kundenadresse
** 4      Kundenadresse
** 5      Kundenadresse
**
** 17.11.94:
**------
** 6a     TAB
**
** 6b     Währung TAB
** 6c     Trenner vorkomma TAB
** 6d     Komma TAB
** 6e     Trenner nachkomma
**------
** 6      Kundennummer
** 7      Ihre Zeichen
** 8      Briefjahr / Briefnummer
** 9      Datum für Feld "Ihr Schreiben vom"
** 10     Datum der Brieferstellung
** 11     Datum des Ausdrucks des Briefes
**
** 12  1  Modus1 TAB
**        Fließtext in einer Zeile
** 
** 13     Abschluß der Liste mit einer Leerzeile
** 
** 
*/

int 
LE_SaveLetter (STRPTR filename)
{
  FILE *file;
  int result = ERR_LET_OK;
  BOOL ok = TRUE;
  STRPTR str, p, buffer, oldp;


  if (buffer = LibAllocPooled (poolHeader, let.Size + 1))
    {
      if (let.Contents)
	strcpy (buffer, let.Contents);
      else
	strcpy (buffer, "");

      if (file = fopen (filename, "w"))
	{
	  /*
	  ** · Anrede
	  ** · Kundenadresse
	  */
	  if (fprintf (file, "%s\t%s\n%s\n%s\n%s\n%s\n", let.customer.Adresse1,
		       let.Betreff, let.customer.Adresse2,
		       let.customer.Adresse3, let.customer.Adresse4,
		       let.customer.Adresse5) < 0)
	    ok = FALSE;

	  /*
	  ** · Kundennummer TAB Währung TAB Trenner vor TAB Komma
	  **   TAB Trenner nach
	  ** · Ihre Zeichen
	  ** · Briefjahr
	  ** · Briefnummer
	  */
	  if (ok && fprintf (file, "%d\t%s\t%s\t%s\t%s\n%s\n%04d/%d\n",
		    let.customer.KundenNummer, let.Unit, let.GroupSeparator,
			     let.DecimalPoint, let.FracGroupSeparator,
		let.customer.Zeichen, let.letterYear, let.letterNumber) < 0)
	    ok = FALSE;

	  /*
	  ** · Datum für Feld "Ihr Schreiben vom"
	  */
	  if (ok && fprintf (file, "%s\n", let.orderDate ) < 0)
	    ok = FALSE;

	  /*
	  ** · Datum der Brieferstellung
	  */
	  if (ok && fprintf (file, "%s\n", let.letterDate) < 0)
	    ok = FALSE;

	  /*
	  ** · Datum des Ausdrucks des Briefes
	  */
	  if (ok && fprintf (file, "%s\n", let.printDate) < 0)
	    ok = FALSE;

	  /* jetzt kommt die Liste aller Artikel */

	  for (p = buffer; ok && p && p < p + let.Size;)
	    {
	      /*
	      **  4  Modus4 TAB
	      **     Fließtext in einer Zeile
	      ** 
	      */
	      oldp = p;

	      if (p = strchr (oldp, '\n'))
		*p++ = 0;

	      if (p == oldp)
		str = " ";
	      else
		str = oldp;

	      if (fprintf (file, "4\t%s\n", str) < 0)
		ok = FALSE;
	    }

	  /* · Abschluß der Liste mit einer Leerzeile */

	  if (ok && fprintf (file, "\n") < 0)
	    ok = FALSE;

	  if (ok)
	    result = ERR_LET_OK;
	  else
	    result = ERR_LET_SAVE;

	  status = FALSE;   /* gespeicherte Rechnung wurde nicht geändert */

	  fclose (file);
	}
      else
	result = ERR_LET_CANTCREATEFILE;

      LibFreePooled (poolHeader, buffer, let.Size + 1);

    }
  else
    result = ERR_LET_NOMEM;

  return (error = result);
}


/*
** lies den Status aus, ob sich die Rechnung geändert hat (TRUE)
** oder nicht (FALSE).
*/

BOOL 
LE_GetStatus (void)
{
  return (status);
}


/*
** lies die wichtigsten Daten auf einen Schlag
*/

void 
LE_GetMinLetter (struct MinLetter *minletter)
{
  char buffer[100];

  minletter->letterNumber = let.letterNumber;
  minletter->letterYear = let.letterYear;
  strcpy (minletter->letterDate, let.letterDate);

  /* nur den Nachnamen finden */
  C_PrintName (&let.customer, buffer);
  strcpy (minletter->Kunde, buffer);
  strcpy (minletter->orderDate, let.orderDate);
  strcpy (minletter->printDate, let.printDate);
  strcpy (minletter->Betreff, let.Betreff);
}


/*
** Fehlerstring abholen
*/

STRPTR 
LE_GetErrorMsg (void)
{
  return (errormsg[error]);
}
