/*
** Verwaltung der Briefliste
**
** 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 "BriefListe.h"
#include "LocaleSupport.h"
#include "MiscSupport.h"

#define MAX_LINE_LEN 100

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

#define BASE_YEAR 1993

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

#define BASE_DIR  "Briefe"


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

struct LetterNode
  {
    struct Node Node;
    struct MinLetter letter;
  };


/* jeder Jahrgang wird zusätzlich verwaltet */

struct YearNode
  {
    struct Node Node;		/* Node zum verketten */
    struct List List;		/* Liste aller Briefe in diesem Jahr */
    struct LetterNode *aktLetter;	/* der akt. Brief dieses Jahrs */
    UWORD itemCount;		/* Anzahl Briefe in diesem Jahr */
    UWORD aktNummer;		/* Nummer des aktuellen Eintrags in Liste */
    UWORD Year;
  };


static struct YearNode *aktList;
static struct List letYears;
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 LetterNode *l, struct LetterNode *r);


/*
** Fehlercode und Fehlerstrings
*/

static int error;
static const STRPTR errormsg[] =
{
  "",				//   ERR_LL_OK
   "ungültiges Jahr",		//   ERR_LL_YEAR
   "Liste ist leer",		//   ERR_LL_LISTEMPTY
   "Eintrag nicht in Liste",	//   ERR_LL_NOITEM
   "kein Speicher",		//   ERR_LL_NOMEM
   "kein memorypool",		//   ERR_LL_NOPOOL
   "Fehler bei Pfad",		//   ERR_LL_NOPATH
   "Fehler bei ExAll()",	//   ERR_LL_EXALL
   "",				//   ERR_LL_LETTER -> L_GetErrorMsg()
   "Konnte File nicht erzeugen",	//   ERR_LL_CANTCREATEFILE
   "Fehler beim speichern",	//   ERR_LL_SAVE
};


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

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

  status = STATUS_NOTHING;

  /* neuen Memory-Pool anfordern */

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

  /* Files einlesen */

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

  ReadDir (year);

  status = STATUS_LISTS;

  LL_SetYear (year);

  return (ERR_LL_OK);
}


/*
** alles aufräumen
*/

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


/*
** Setze den aktuellen Jahrgang
*/

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

  for (node = (struct YearNode *) letYears.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_LL_OK);
    }
  else
    return (error = ERR_LL_YEAR);
}


/*
** ermittle das aktuelle Jahr
*/

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

  return (aktList->Year);
}


/*
** ermittle ein bestimmtes Jahr
*/

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

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

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

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

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


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

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

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

  for (i = 0, node = (struct YearNode *) letYears.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 
LL_GetYearCount (void)
{
  return (yearCount);
}


/*
** neuen Brief in die Liste übernehmen 
*/

static int 
private_NewLetter (struct MinLetter *item)
{
  struct LetterNode *newitem;
  int result = ERR_LL_OK;

  if (!(newitem = LibAllocPooled (poolHeader, sizeof (struct LetterNode))))
      return (error = ERR_LL_NOMEM);

  newitem->letter.letterNumber = item->letterNumber;
  newitem->letter.letterYear = item->letterYear;
  strcpy (newitem->letter.letterDate, item->letterDate);
  strcpy (newitem->letter.Kunde, item->Kunde);
  strcpy (newitem->letter.orderDate, item->orderDate);
  strcpy (newitem->letter.printDate, item->printDate);
  strcpy (newitem->letter.Betreff, item->Betreff);

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

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

  return (error = result);
}

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

int 
LL_NewLetter (struct MinLetter *item)
{
  int result = ERR_LL_OK;

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

  return (error = result);
}


/*
** Brief aus Liste löschen
*/

int 
LL_DelLetter (void)
{
  struct LetterNode *newakt;
  char filename[80];
  int result;

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

  /* File auch noch löschen */
  sprintf (filename, "%s%04d/%03d.%s", BASE_DIR,
	   aktList->aktLetter->letter.letterYear,
	   aktList->aktLetter->letter.letterNumber,
	   aktList->aktLetter->letter.Kunde);
  unlink (filename);

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

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

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

  result = WriteDir (aktList->Year);

  return (error = result);
}


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

int 
LL_ChangeLetter (struct MinLetter *item)
{
  int result;

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

  aktList->aktLetter->letter.letterNumber = item->letterNumber;
  aktList->aktLetter->letter.letterYear = item->letterYear;
  strcpy (aktList->aktLetter->letter.letterDate, item->letterDate);
  strcpy (aktList->aktLetter->letter.Kunde, item->Kunde);
  strcpy (aktList->aktLetter->letter.orderDate, item->orderDate);
  strcpy (aktList->aktLetter->letter.printDate, item->printDate);
  strcpy (aktList->aktLetter->letter.Betreff, item->Betreff);

  result = WriteDir (aktList->Year);

  return (error = result);
}


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

int 
LL_SetCurrentLetterNumber (UWORD number)
{
  int i;
  struct LetterNode *node;

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

  for (i = 0, node = (struct LetterNode *) aktList->List.lh_Head;
       node->Node.ln_Succ && (node->letter.letterNumber != number);
       i++, node = (struct LetterNode *) node->Node.ln_Succ);

  if (node->Node.ln_Succ)
    {
      aktList->aktLetter = node;
      aktList->aktNummer = i + 1;
      return (error = ERR_LL_OK);
    }
  else
    return (error = ERR_LL_NOITEM);
}


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

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


/*
** lies die Daten eines Briefes im aktuellen Jahr
*/

int 
LL_GetLetter (UWORD num, struct MinLetter *item)
{
  struct LetterNode *node;
  int i;

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

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

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

  item->letterNumber = node->letter.letterNumber;
  item->letterYear = node->letter.letterYear;
  strcpy (item->letterDate, node->letter.letterDate);
  strcpy (item->Kunde, node->letter.Kunde);
  strcpy (item->orderDate, node->letter.orderDate);
  strcpy (item->printDate, node->letter.printDate);
  strcpy (item->Betreff, node->letter.Betreff);

  return (error = ERR_LL_OK);
}


/*
** lies die Daten des aktuellen Briefes im aktuellen Jahr
*/

int 
LL_GetCurrentLetter (struct MinLetter *item)
{
  if (aktList->itemCount == 0)
    return (error = ERR_LL_LISTEMPTY);

  item->letterNumber = aktList->aktLetter->letter.letterNumber;
  item->letterYear = aktList->aktLetter->letter.letterYear;
  strcpy (item->letterDate, aktList->aktLetter->letter.letterDate);
  strcpy (item->Kunde, aktList->aktLetter->letter.Kunde);
  strcpy (item->orderDate, aktList->aktLetter->letter.orderDate);
  strcpy (item->printDate, aktList->aktLetter->letter.printDate);
  strcpy (item->Betreff, aktList->aktLetter->letter.Betreff);

  return (error = ERR_LL_OK);
}


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

int 
LL_GetCurrentLetterNumber (void)
{
  if (aktList->aktLetter)
    return (aktList->aktLetter->letter.letterNumber);
  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 MinLetter minletter;
  char buffer[MAX_LINE_LEN];
  STRPTR p;
  int result = ERR_LL_OK;

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

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

  LL_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/BriefListe", 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)
	    {
	      /*
	      ** · Briefnummer/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, '/'))
		    {
		      minletter.letterYear = atol (buffer);
		      minletter.letterNumber = atol (p + 1);
		    }
		  else
		    {
		      minletter.letterYear = 0;
		      minletter.letterNumber = 0;
		    }
		}

	      /*
	      ** · Briefdatum BETREFF
	      */

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

	      /*
	      ** · Kunde
	      */

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

	      /*
	      ** · Datum für "Ihr Schreiben vom"
	      */

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

	      /*
	      ** · Druckdatum
	      */

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

	      /*
	      ** · Betreff (bisher Leerzeile)
	      */

	      if (ok && !fgets (minletter.Betreff, 99, file))
		ok = FALSE;
	      if (p = strchr (minletter.Betreff, '\n'))
		*p = 0;


	      if (ok && private_NewLetter (&minletter))
		ok = FALSE;
	    }

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

	  struct ExAllData *ead;
	  struct ExAllControl *eac;
	  struct LetterNode *newitem;
	  struct ExAllData *mem;
	  char patsrc[10], pattern[32];
	  BOOL more;
	  struct MinLetter minletter;

	  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_LL_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 (LE_LoadLetter (filename))
			    result = ERR_LL_LETTER;
			  LE_GetMinLetter (&minletter);

			  if (newitem = LibAllocPooled (poolHeader, sizeof (struct LetterNode)))
			    {
			      newitem->letter.letterNumber = minletter.letterNumber;
			      newitem->letter.letterYear = minletter.letterYear;
			      strcpy (newitem->letter.letterDate, minletter.letterDate);
			      strcpy (newitem->letter.Kunde, minletter.Kunde);
			      strcpy (newitem->letter.orderDate, minletter.orderDate);
			      strcpy (newitem->letter.printDate, minletter.printDate);
			      strcpy (newitem->letter.Betreff, minletter.Betreff);

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

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

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

		    }
		  while (more);

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

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

  return (error = result);
}


/*
** Schreibe die intern verwaltete Brief-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 LetterNode *node;
  int result = ERR_LL_OK;

  LL_SetYear (year);

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

  sprintf (dirname, "%s%04d", BASE_DIR, year);
  sprintf (filename, "%s%04d/BriefListe", 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 LetterNode *) aktList->List.lh_Head;
	       ok && node->Node.ln_Succ;
	       node = (struct LetterNode *) node->Node.ln_Succ)
	    {
	      /*
	      ** · Briefnummer/jahr
	      ** · Briefdatum
	      ** · Kunde
	      ** · Datum für "Ihr Schreiben vom"
	      ** · Druckdatum
	      ** · Betreff (bisher Leerzeile)
	      */

	      if (fprintf (file, "%04d/%d\n%s\n%s\n%s\n%s\n%s\n",
			 node->letter.letterYear, node->letter.letterNumber,
			   node->letter.letterDate, node->letter.Kunde,
			   node->letter.orderDate, node->letter.printDate,
			   node->letter.Betreff) < 0)
		ok = FALSE;
	    }
	  if (!ok)
	    result = ERR_LL_SAVE;

	  fclose (file);
	}
      else
	result = ERR_LL_CANTCREATEFILE;
    }
  else
    result = ERR_LL_NOPATH;

  return (error = result);
}


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

UWORD 
LL_GetNextLetterNumber (void)
{
  if (aktList)
    {
      if (IsListEmpty (&aktList->List))
	return (1);
      else
	return ((UWORD) (((struct LetterNode *)
	        (aktList->List.lh_TailPred))->letter.letterNumber + 1));
    }
  return (0);
}


/*
** lade einen bestimmten Brief
*/

int 
LL_LoadLetter (struct MinLetter *minletter)
{
  char filename[150];
  int result = ERR_LL_OK;

  /* Filename: z.B.   "Briefe1994/003.Scherer" */
  sprintf (filename, "%s%04d/%03d.%s", BASE_DIR, minletter->letterYear,
	   minletter->letterNumber, minletter->Kunde);

  if (LE_LoadLetter (filename))
    result = ERR_LL_LETTER;

  return (error = result);
}


/*
** speichere einen bestimmten Brief
*/

int 
LL_SaveLetter (struct MinLetter *minletter)
{
  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_LL_OK;

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


  /* 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_LL_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_LL_NOMEM;
	  FreeDosObject (DOS_EXALLCONTROL, eac);
	}
      else
	result = ERR_LL_NOMEM;

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

      /* Filename: z.B.   "Briefe1994/003.Scherer" */
      sprintf (filename, "%s%04d/%03d.%s", BASE_DIR, minletter->letterYear,
	       minletter->letterNumber, minletter->Kunde);

      if (LE_SaveLetter (filename))
	result = ERR_LL_LETTER;
    }
  else
    result = ERR_LL_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 LetterNode *l, struct LetterNode *r)
{
  return (l->letter.letterNumber - r->letter.letterNumber);
}


/*
** Fehlerstring erfragen
*/

STRPTR 
LL_GetErrorMsg (void)
{
  if (error == ERR_LL_LETTER)
    return (LE_GetErrorMsg ());
  else
    return (errormsg[error]);
}
