/* 
 * Copyright 1993 Florian Wolpert <flo@pezzi.freiburg.sub.org>
 *
 * Permission to use, copy, modify, distribute, and sell this software and
 * its documentation for any purpose is hereby granted without fee, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation. The author makes no representations about the suitability
 * of this software for any purpose. It is provided "as is" without express
 * or implied warranty.
 *
 */

#define NEXT_Ae (133)
#define NEXT_Oe (150)
#define NEXT_Ue (154)
#define NEXT_ae (217)
#define NEXT_oe (240)
#define NEXT_ue (246)
#define NEXT_ss (251)


#include <string.h>
 
#include "nui.h"

#include "convert.h"
#include "message.h"
#include "parse.h"
#include "strada.h"
#include "utils.h"

#if defined (HANDLE_BROKEN_DATAFILES)
#define IbmToNext IbmAndBrokenToNext
#endif


extern char *strdup (char *s);


static char *messageBuffer = (char *) 0;


#if defined (HANDLE_BROKEN_DATAFILES)

/*
 * "IbmAndBrokenToNext" konvertiert einen C-String mit IBM-Umlauten (und
 * solchen vom Atari ST) nach Next. Die Funktion akzeptiert auch die
 * "verkröppelte 7-Bit-Darstellung der Umlaute. Der Ergebnisstring sollte nach
 * Gebrauch mittels "free" wieder freigegeben werden.
 */

char *IbmAndBrokenToNext (const char *s)
{
    static char ibm[] = 
	{IBM_Ae, IBM_Oe, IBM_Ue, IBM_ae, IBM_oe, IBM_ue, IBM_ss, ATARI_ss,
	 BROKEN_Ae, BROKEN_Oe, BROKEN_Ue, BROKEN_ae, BROKEN_oe, BROKEN_ue,
	 BROKEN_ss};
    static char next[] = 
	{NEXT_Ae, NEXT_Oe, NEXT_Ue, NEXT_ae, NEXT_oe, NEXT_ue, NEXT_ss, 
	 NEXT_ss, NEXT_Ae, NEXT_Oe, NEXT_Ue, NEXT_ae, NEXT_oe, NEXT_ue,
	 NEXT_ss};
    char *result = (char *) malloc (strlen (s) + 1);
    char *r = result;
    char c;
    int i;

    if (result == (char *) 0)
    {
	OutOfMemory ("IbmToNext");
	return (char *) 0;
    }
    while (*s)
    {
	c = *s++;
	for (i = 0; i < sizeof (ibm) / sizeof (ibm[1]); i++)
	    if (c == ibm[i]) {
		c = next[i];
	        break;
	    }
	*r++ = c;
    }
    *r = '\0';
    return result;
}
#endif




/*
 * "IbmToNext" konvertiert einen C-String mit IBM-Umlauten (und solchen vom
 * Atari ST) nach ISO-8859-1. Der Ergebnisstring sollte nach Gebrauch mittels
 * "free" wieder freigegeben werden.
 */

char *IbmToNext (const char *s)
{
    static char ibm[] = 
	{IBM_Ae, IBM_Oe, IBM_Ue, IBM_ae, IBM_oe, IBM_ue, IBM_ss, ATARI_ss};
    static char next[] = 
	{NEXT_Ae, NEXT_Oe, NEXT_Ue, NEXT_ae, NEXT_oe, NEXT_ue, NEXT_ss, 
	 NEXT_ss};
    char *result = (char *) malloc (strlen (s) + 1);
    char *r = result;
    char c;
    int i;

    if (result == (char *) 0)
    {
	OutOfMemory ("IbmToNext");
	return (char *) 0;
    }
    while (*s)
    {
	c = *s++;
	for (i = 0; i < sizeof (ibm) / sizeof (ibm[1]); i++)
	    if (c == ibm[i]) {
		c = next[i];
		break;
	    }
	*r++ = c;
    }
    *r = '\0';
    return result;
}



/*
 * "NextToIso" konvertiert einen C-String mit NeXT-Umlauten nach ISO-8859-1.
 * Der Ergebnisstring sollte nach Gebrauch mittels
 * "free" wieder freigegeben werden.
 * aus mir unerklaerlichen Gruenden funktioniert die NEXT_oe nach ISO_oe
 * Umsetzung nicht richtig (spaeter beim Suchen & Vergleichen). Deshalb
 * Konvertiere ich das kleine NEXT_oe in das grosse ISO_Oe dann gehts :-/
 */

char *NextToIso (const char *s)
{
    static char iso[] = 
	{ISO_Ae, ISO_Oe, ISO_Ue, ISO_ae, ISO_oe, ISO_ue, ISO_ss};
    static char next[] = 
	{NEXT_Ae, NEXT_Oe, NEXT_Ue, NEXT_ae, NEXT_oe, NEXT_ue, NEXT_ss};
    char *result = (char *) malloc (strlen (s) + 1);
    char *r = result;
    char c;
    int i;

    if (result == (char *) 0)
    {
	OutOfMemory ("NextToIso");
	return (char *) 0;
    }
    while (*s)
    {
	c = *s++;
	for (i = 0; i < sizeof (next) / sizeof (next[1]); i++)
	    if (c == next[i]) {
		c = iso[i];
		break;
	    }
	*r++ = c;
    }
    *r = '\0';
    return result;
}


/*
 * "NextToIso" konvertiert einen C-String mit ISO-Umlauten nach NeXT.
 * Der Ergebnisstring sollte nach Gebrauch mittels
 * "free" wieder freigegeben werden.
 */

char *IsoToNext (const char *s)
{
    static char iso[] = 
	{ISO_Ae, ISO_Oe, ISO_Ue, ISO_ae, ISO_oe, ISO_ue, ISO_ss};
    static char next[] = 
	{NEXT_Ae, NEXT_Oe, NEXT_Ue, NEXT_ae, NEXT_oe, NEXT_ue, NEXT_ss};
    char *result = (char *) malloc (strlen (s) + 1);
    char *r = result;
    char c;
    int i;

    if (result == (char *) 0)
    {
	OutOfMemory ("IsoToNext");
	return (char *) 0;
    }
    while (*s)
    {
	c = *s++;
	for (i = 0; i < sizeof (iso) / sizeof (iso[1]); i++)
	    if (c == iso[i]) {
		c = next[i];
		break;
	    }
	*r++ = c;
    }
    *r = '\0';
    return result;
}

/*
 * "NextToIso" konvertiert einen C-String mit ISO-Umlauten nach Ibm.
 * Der Ergebnisstring sollte nach Gebrauch mittels
 * "free" wieder freigegeben werden.
 */

char *IsoToIbm (const char *s)
{
    static char iso[] = 
	{ISO_Ae, ISO_Oe, ISO_Ue, ISO_ae, ISO_oe, ISO_ue, ISO_ss};
    static char ibm[] = 
	{IBM_Ae, IBM_Oe, IBM_Ue, IBM_ae, IBM_oe, IBM_ue, IBM_ss};
    char *result = (char *) malloc (strlen (s) + 1);
    char *r = result;
    char c;
    int i;

    if (result == (char *) 0)
    {
	OutOfMemory ("IsoToIbm");
	return (char *) 0;
    }
    while (*s)
    {
	c = *s++;
	for (i = 0; i < sizeof (iso) / sizeof (iso[1]); i++)
	    if (c == iso[i]) {
		c = ibm[i];
		break;
	    }
	*r++ = c;
    }
    *r = '\0';
    return result;
}



static void NuiMsgFlush (UiComponents *uc)
{
    if (!messageBuffer) return;
    if (*messageBuffer) {
    	char *msg=IsoToNext(messageBuffer);
    	NXRunAlertPanel("Achtung",msg,"OK",NULL,NULL);
	free (msg);
    }
    free (messageBuffer);
    messageBuffer = (char *) 0;
}




static void NuiMsgWrite (UiComponents *uc, char *msg)
{
    char *help;

    if (messageBuffer == (char *) 0)
    {
	messageBuffer = (char *) malloc (1);
	*messageBuffer = '\0';
    }
    help = messageBuffer;
    messageBuffer = (char *) malloc (strlen (messageBuffer) + strlen (msg) + 1);
    strcpy (messageBuffer, help);
    strcat (messageBuffer, msg);
    free (help);
}




static void NuiNoteWrite (UiComponents *uc, char *msg)
{
    NuiController *nc = (NuiController *) uc;

    fprintf (stderr,msg);
    fflush (stderr);
}




static void NuiNoteClear (UiComponents *uc)
{
    NuiController *nc = (NuiController *) uc;

    fprintf (stderr,"\n");
}




#define IsOrtGefunden(pc) \
	(pc->status != PlzOrtNichtGefunden && pc->status != PlzSucheOrt \
	&& pc->status != PlzFehler)

#define IsOrtEindeutig(pc) \
	(IsOrtGefunden (pc) && pc->status != PlzOrtMehrdeutig)

#define IsStrasseGefunden(pc) \
	(IsOrtEindeutig (pc) && \
	(pc->status == PlzStrasseGefunden || \
	pc->status == PlzStrasseEindeutig || \
	pc->status == PlzStrasseMehrfachInOrt || \
	pc->status == PlzStrasseMehrfachInPostanstalt || \
	pc->status == PlzStrasseMehrfachInOrtsteil || \
	pc->status == PlzHausnummerBenoetigt || \
	pc->status == PlzHausnummerNichtGefunden || \
	(pc->status == PlzPlzNeuGefunden && *(pc->strasse))))

#define IsStrasseEindeutig(pc) \
	(IsOrtEindeutig (pc) && \
	(pc->status == PlzStrasseEindeutig || \
	pc->status == PlzHausnummerBenoetigt || \
	pc->status == PlzHausnummerNichtGefunden || \
	(pc->status == PlzPlzNeuGefunden && *(pc->strasse))))

#define IsPostfachGefunden(pc) \
	(IsOrtEindeutig (pc) && \
	(pc->status == PlzPostfachGefunden || \
	pc->status == PlzPostfachMehrfachInOrt || \
	pc->status == PlzPostfachMehrfachInPostanstalt || \
	pc->status == PlzPostfachMehrfachInPlz || \
	(pc->status == PlzPlzNeuGefunden && *(pc->postfach))))

#define IsPostfachEindeutig(pc) \
	(IsOrtEindeutig (pc) && \
	(pc->status == PlzPostfachGefunden || \
	(pc->status == PlzPlzNeuGefunden && *(pc->postfach))))


/*
void InitDisplay (ConversionData *cd, char **strasse, char **hausnummer, char**postfach, char **plz_alt, char **ort, char **postanstalt, char **ortsteil)
{
/*
    GuiComponents *gc = cd->gc;

    LabelSetString (gc->plz_neu, "");
    XtVaSetValues (gc->list,
		   XmNitems, (XmString *) 0,
		   XmNitemCount, 0L,
		   NULL);
}
*/



void ConvertCallback (ConversionData *conversionData)
{
    char string[300];
    char *isoString;
    char *nextMsg;
    PlzConversion *pc = conversionData->pc;
    char *strasse, *hausnummer, *postfach, *plz_alt, *ort, *postanstalt,
	 *ortsteil;

//    SetBusyCursor (widget);
    [conversionData->nc setPlz_neuTo:""];
    [conversionData->nc setListTo:NULL withLen:0];

    isoString=NextToIso([conversionData->nc getStrasse]);
    ParseStrasse (isoString, &strasse, &hausnummer, &postfach);
    free (isoString);

    isoString=NextToIso([conversionData->nc getOrt]);   
    ParseOrt (isoString, &plz_alt, &ort, &postanstalt, &ortsteil);
    free (isoString);

    ConvertPlz (pc, strasse, hausnummer, postfach, plz_alt, ort, postanstalt, 
		ortsteil);
    free (strasse);
    free (hausnummer);
    free (postfach);
    free (plz_alt);
    free (ort);
    free (postanstalt);
    free (ortsteil);

    Message (ConversionStatusString (pc->status));
    MessageFlush ();
    [conversionData->nc setListTo:NULL withLen:0];
    [conversionData->nc enableStrassenverzeichnis:NO];


    if (IsOrtGefunden (pc))
    {
	if (IsOrtEindeutig (pc))
	{
	    if ((pc->orte->entries > 0 && pc->orte->list[0].nplzo_z[0] == '2')
	    || (pc->archivOrte->entries == 1
	    && pc->archivOrte->list[0].nplz_z[0] == '2'))
	    	[conversionData->nc enableStrassenverzeichnis:YES];

	    //XmProcessTraversal (conversionData->gc->strasse,
	    ;//			XmTRAVERSE_CURRENT);
	}
	else
	{
	    /* Mehrere PLZ, mðglicherweise auch mehrere Orte */
	    OrteToList (conversionData->nc, pc->orte, pc->archivOrte);
	    [conversionData->nc setCallback:ListPlaceSelected];
	}

	if (pc->status == PlzPlzNeuGefunden) {
	    [conversionData->nc setPlz_neuTo:pc->plz_neu];
	}

	nextMsg=IsoToNext(OrtString (pc->plz_alt, pc->ort, pc->postanstalt,
			pc->ortsteil));
	[conversionData->nc setOrtTo:nextMsg];
	free(nextMsg);
    }


    if (IsStrasseGefunden (pc))
    {
    	nextMsg = IsoToNext(StrasseString (pc->strasse, pc->hausnummer,
		pc->postfach));
	[conversionData->nc setStrasseTo:nextMsg];
	free (nextMsg);
	if (!IsStrasseEindeutig (pc))
        {
	    StradaSetToList (conversionData->nc, pc->strassen, pc->ort);
	    [conversionData->nc setCallback:ListStreetSelected];
	}
    }


    if (IsPostfachGefunden (pc))
    {
	if (IsPostfachEindeutig (pc))
	{
	    strcpy (string, "Postfach ");
	    strcat (string, postfach);
	    [conversionData->nc setStrasseTo:string];
	}
	else
        {
	    PofadaSetToList (conversionData->nc, pc->postfaecher, 
                             pc->orte->list->ortname_a);
	    [conversionData->nc setCallback:ListPoboxSelected];
        }
    }

//    UnsetBusyCursor (widget);
}

void StrassenverzeichnisCallback (ConversionData *cd)
{
    PlzConversion *pc = cd->pc;

    [cd->nc setPlz_neuTo:""];
    if (pc->orte->entries > 0)
	pc->strassen = Strassenverzeichnis (pc->orte->list[0].alort);
    else if (pc->archivOrte->entries > 0)
	pc->strassen = Strassenverzeichnis (pc->archivOrte->list[0].alort);
    StradaSetToList (cd->nc, pc->strassen, pc->ort);
    [cd->nc setCallback:ListStreetSelected];
}


void ListPoboxSelected (ConversionData *cd)
{
    char *plz;
    char *ort;
    char *zustellamt;
    char *ortsteil;
    char *item;
    char *nextMsg;
    MyString sel = [cd->nc getListSelection];    
    
    item = NextToIso([[sel objectAt:0] string]);
    ParseOrt (item, &plz, &ort, &zustellamt, &ortsteil);

    nextMsg = IsoToNext(item);
    [cd->nc setOrtTo:nextMsg];
    free (nextMsg);

    cd->pc->status = PlzSuchePostfach;
    free (item);
}

/*
 * "ListPlaceSelected" holt den Orts-String aus dem ersten Segment des
 * CompountString und überträgt ihn in das Ortseingabefeld. Falls das zweite
 * Segment als erste Zeichen " -> " enthält, ist dies der aktuelle Ortsname,
 * und der Inhalt des ersten Segments historisch. Er wird als Ortsteil
 * eingesetzt.
 */

void ListPlaceSelected (ConversionData *cd)
{
    char *plz;
    char *ort;
    char *zustellamt;
    char *ortsteil;
    char *item;
    char *nextMsg;
    MyString sel = [cd->nc getListSelection];    

    item = NextToIso([[sel objectAt:0] string]);
    ParseOrt (item, &plz, &ort, &zustellamt, &ortsteil);
    free (item);

    item = [[sel objectAt:1] string];
    if (item && strncmp (item, " -> ", 4) == 0)
    {
	free (ortsteil);
	ortsteil = ort;
	ort = (char *) malloc (strlen (item + 4) + 1);
	strcpy (ort, item + 4);
    }
    
    item = OrtString (plz, ort, zustellamt, ortsteil);
    free (plz);
    free (ort);
    free (zustellamt);
    free (ortsteil);
    nextMsg = IsoToNext(item);
    [cd->nc setOrtTo:nextMsg];
    free (nextMsg);

    cd->pc->status = PlzOrtEindeutig;
}
    
void ListStreetSelected (ConversionData *cd)
{
    Boolean separator=False;
    char *postfach="";
    char *plz;
    char *ort;
    char *zustellamt;
    char *ortsteil;
    char *item;
    int ptr=0;
    char *nextMsg;
    MyString sel = [cd->nc getListSelection];    

    /* Postleitzahl: */
    item = [[sel objectAt:ptr++] string];
    UpdateString (&cd->pc->plz_neu, item);
    [cd->nc setPlz_neuTo:item];
    cd->pc->status = PlzPlzNeuGefunden;
    
    ptr++; // skip blank
    
    /* Straûenname: */
    item = NextToIso([[sel objectAt:ptr++] string]);
    UpdateString (&cd->pc->strasse, item);
    nextMsg = IsoToNext(StrasseString (item, cd->pc->hausnummer, postfach));
    free (item);
    [cd->nc setStrasseTo:nextMsg];
    free (nextMsg);
    
    /* Hausnummernbereich: */
    if ([[sel objectAt:ptr] typ] != SEPARATOR)
    {
    	ptr+=2; // komma und nummer ueberspringen!
    }
    
    /* Orts-String: */
    if ([sel objectAt:ptr] && [[sel objectAt:ptr++] typ] == SEPARATOR)
    {
        item = NextToIso([[sel objectAt:ptr++] string]);
	ParseOrt (item, &plz, &ort, &zustellamt, &ortsteil);
	free (item);
	nextMsg = IsoToNext(OrtString (plz, ort, zustellamt, ortsteil));
        [cd->nc setOrtTo:nextMsg];
	free (nextMsg);
	UpdateString (&cd->pc->plz_alt, plz);
	UpdateString (&cd->pc->ort, ort);
	UpdateString (&cd->pc->postanstalt, zustellamt);
	UpdateString (&cd->pc->ortsteil, ortsteil);
	free (plz);
	free (ort);
	free (zustellamt);
	free (ortsteil);
    }
    else
    {
	UpdateString (&cd->pc->postanstalt, "");
	UpdateString (&cd->pc->ortsteil, "");
	nextMsg = IsoToNext(OrtString (cd->pc->plz_alt, cd->pc->ort, "", ""));
        [cd->nc setOrtTo:nextMsg];
	free (nextMsg);
    }
}


static MyString MyStringCreate(const char *string, MyStringType typ)
{
    MyString list = [[List alloc] init];
    [list addObject:[[MyStringSegment alloc] initWith:string ofType:typ]];
    return list;
}

static MyString MyStringCat(MyString list1, MyString list2)
{
    [list1 appendList:list2];
    [list2 free];
    return list1;
}

static void MyStringFree(MyString list)
{
    [[list freeObjects] free];
}

void PofadaSetToList (NuiController *nc, PofadaSet *pofadaSet, char *ortsname)
{
    Pofada *l;
    Pofada *newPobox;
    int i, j;
    MyString *stringList = (MyString *) calloc ((int) pofadaSet->entries, 
						sizeof (MyString *));
    char msg[300];
    char *nextMsg;
    char *ibmMsg;
    int entriesLeft = pofadaSet->entries;
    char postanstalt[5];

    newPobox = pofadaSet->list;
    postanstalt[0] = '\0';
    for (l = pofadaSet->list, i = j = 0; i < pofadaSet->entries; i++, l++)
    {
	msg[0] = '\0';
	if (strncmp (l->npanst, postanstalt, sizeof (l->npanst)) != 0)
	{
	    strncpy (postanstalt, l->npanst, sizeof (l->npanst));
	    strncat (msg, l->plz_w_o, sizeof (l->plz_w_o));
	    strncat (msg, l->plzalt, sizeof (l->plzalt));
    	    strcat  (msg, " ");
	    ibmMsg = IsoToIbm(ortsname);
	    strncat (msg, ibmMsg, sizeof (((Umsda *) 0)->ortname_a));
	    free (ibmMsg);
    	    StripBlanks (msg);
    	    strcat  (msg, " ");
    	    strncat (msg, l->npanst, sizeof (l->npanst));
	}
	else
	{
	    entriesLeft--;
	    continue;
	}

	nextMsg = IbmToNext (msg);
	stringList[j++] = MyStringCreate(nextMsg,NORMAL);
	free (nextMsg);
    }

    [nc setListTo:stringList withLen:entriesLeft];

    for (i = 0; i < entriesLeft; i++)
	MyStringFree (stringList[i]);
    free (stringList);
}



static void AppendHn (char *s, char *tag, int length)
{
    char *c = tag;

    while (*c == ' ' && c - tag < length)
	c++;
    if (c - tag < length)
    {
	strncat (s, c, length - (c - tag));
	StripBlanks (s);
    }
}



void StradaSetToList (NuiController *nc, StradaSet *stradaSet, char *ortsname)
{
    Strada *l;
    Strada *newStreet;
    int i, j;
    MyString s1;
    MyString *stringList = (MyString *) calloc ((int) stradaSet->entries, 
						sizeof (MyString *));

    char msg[300];
    char *nextMsg;
    char *ibmMsg;
    char ortsteil[sizeof (((Strada *) 0)->ortsteil)];
    char sname[sizeof (((Strada *) 0)->sname)];
    char strlfdnr[sizeof (((Strada *) 0)->strlfdnr)];
    int entriesLeft = stradaSet->entries;

    newStreet = stradaSet->list;
    ortsteil[0] = sname[0] = strlfdnr[0] = '\0';
    for (l = stradaSet->list, i = j = 0; i < stradaSet->entries; i++, l++)
    {
    	/* neue Postleitzahlen */
	msg[0] = '\0';
	strncat (msg, l->plz_z, sizeof (l->plz_z));
	s1 = MyStringCreate(msg,NORMAL);
	s1 = MyStringCat(s1, MyStringCreate(" ",NORMAL));
	
	/* Straûenname: */
	msg[0] = '\0';
	strncat (msg, l->sname, sizeof (l->sname));
	StripBlanks (msg);
	nextMsg = IbmToNext (msg);
	s1 = MyStringCat(s1, MyStringCreate(nextMsg,NORMAL));
	free (nextMsg);

	/* Hausnummernbereich (falls vorhanden): */
	if (strntoi (l->nplz_z, sizeof (l->nplz_z)) > 1)
	{
	    s1 = MyStringCat(s1, MyStringCreate(", ",NORMAL));
	    msg[0] = '\0';
	    AppendHn (msg, l->hnr1von, sizeof (l->hnr1von));
	    AppendHn (msg, l->hnr2von, sizeof (l->hnr2von));
	    strcat (msg, "-");
	    AppendHn (msg, l->hnr1bis, sizeof (l->hnr1bis));
	    AppendHn (msg, l->hnr2bis, sizeof (l->hnr2bis));
	    nextMsg = IbmToNext (msg);
	    s1 = MyStringCat(s1, MyStringCreate(nextMsg,NORMAL));
	    free (nextMsg);
	}
	else
	{
	    if (strncmp (l->sname, sname, sizeof (l->sname)) != 0
	    || strncmp (l->strlfdnr, strlfdnr, sizeof (l->strlfdnr)) != 0)
	    {
		strncpy (sname, l->sname, sizeof (l->sname));
		strncpy (strlfdnr, l->strlfdnr, sizeof (l->strlfdnr));
	    }
	    else
	    {
		entriesLeft--;
		MyStringFree(s1);
		continue;
	    }
	}

	/* Orts-String (bei mehreren gleichnamigen Straûen): */
	if (strntoi (l->anzgleist, sizeof (l->anzgleist)) > 1)
	{
	    if (strncmp (l->ortsteil, ortsteil, sizeof (l->ortsteil)) != 0)
	    {
	        s1 = MyStringCat(s1, MyStringCreate("",SEPARATOR));
		strncpy (ortsteil, l->ortsteil, sizeof (l->ortsteil));
		strcpy (msg, "      ");
		strncat (msg, l->plz_w_o, sizeof (l->plz_w_o));
	    	StripBlanks (msg);
		strncat (msg, l->plzalt, sizeof (l->plzalt));
	    	strcat  (msg, " ");
		ibmMsg = IsoToIbm(ortsname);
	    	strncat (msg, ibmMsg, sizeof (((Umsda *) 0)->ortname_a));
		free (ibmMsg);
	    	StripBlanks (msg);
	    	strcat  (msg, " ");
	    	strncat (msg, l->npanst, sizeof (l->npanst));
	    	StripBlanks (msg);
	    	strcat  (msg, " (");
		strncat (msg, l->ortsteil, sizeof (l->ortsteil));
	    	StripBlanks (msg);
            	strcat  (msg, ")");
	    	StripBlanks (msg);
		nextMsg = IbmToNext (msg);
	        s1 = MyStringCat(s1, MyStringCreate(nextMsg,NORMAL));
		free (nextMsg);
	    }
	    else
	    {
		entriesLeft--;
		MyStringFree(s1);
		continue;
	    }
	}

	stringList[j++] = s1;
    }

    [nc setListTo:stringList withLen:entriesLeft];

    for (i = 0; i < entriesLeft; i++)
	MyStringFree (stringList[i]);
    free (stringList);
}




void OrteToList (NuiController *nc, UmsdaSet *orte, OrtardaSet *archivOrte)
{
    Umsda *lu;
    Ortarda *lo;
    int i;
    MyString *stringList = (MyString *) calloc ((int)orte->entries
                                         +(int)archivOrte->entries, 
		                         sizeof (MyString *));
    MyString s1;
    char msg[300];
    char *nextMsg;
    char *c;

    for (lu = orte->list, i = 0; i < orte->entries; i++)
    {
	/* PLZ alt, Ortsname, Postanstalt: */
	msg[0] = '\0';
	strncat (msg, lu->plz_w_o, sizeof (lu->plz_w_o));
	strncat (msg, lu->plzalt, sizeof (lu->plzalt));
        strcat  (msg, " ");
        strncat (msg, lu->ortname_a, sizeof (lu->ortname_a));
	StripBlanks (msg);
        strcat  (msg, " ");
        strncat (msg, lu->npanst_a, sizeof (lu->npanst_a));
	StripBlanks (msg);
	nextMsg = IbmToNext (msg);
	s1 = MyStringCreate(nextMsg, NORMAL);
	free (nextMsg);

	/* Ortszusatz: */
	*msg = '\0';
	c = lu->ortzusa;
	if (*c != ',' && *c != '-')
	    strcat (msg, " ");
	while (*c == ' ' && c - lu->ortzusa < sizeof (lu->ortzusa))
	    c++;
	if (c - lu->ortzusa < sizeof (lu->ortzusa))
	{
	    strncat (msg, c, sizeof (lu->ortzusa) - (c - lu->ortzusa));
	}
	StripBlanks (msg);

	nextMsg = IbmToNext (msg);
	stringList[i] = MyStringCat(s1,MyStringCreate(nextMsg, ITALIC));
	free (nextMsg);
	lu++;
    }

    for (lo = archivOrte->list; i < orte->entries + archivOrte->entries; i++)
    {
	/* PLZ alt, Ortsname, Postanstalt: */
	msg[0] = '\0';
	strncat (msg, lo->plz_w_o, sizeof (lo->plz_w_o));
	strncat (msg, lo->plzalt, sizeof (lo->plzalt));
        strcat  (msg, " ");
        strncat (msg, lo->ortname_a, sizeof (lo->ortname_a));
	StripBlanks (msg);
        strcat  (msg, " ");
        strncat (msg, lo->npanst_a, sizeof (lo->npanst_a));
	StripBlanks (msg);
	nextMsg = IbmToNext (msg);
	s1 = MyStringCreate(nextMsg, NORMAL);
	free (nextMsg);

	/* aktueller Ortsname: */
	strcpy (msg, " -> ");
	strncat (msg, lo->ortname_n, sizeof (lo->ortname_n));
	StripBlanks (msg);

	nextMsg = IbmToNext (msg);
	stringList[i] = MyStringCat(s1,MyStringCreate(nextMsg, ITALIC));
	free (nextMsg);
	lo++;
    }

    [nc setListTo:stringList withLen:orte->entries+archivOrte->entries];
    for (i = 0; i < orte->entries+archivOrte->entries; i++)
	MyStringFree (stringList[i]);
    free (stringList);
}



/*
XtCallbackProc QuitCallback (Widget widget, XtPointer clientData,
			     XtPointer callData)
{
    XtDestroyApplicationContext (XtWidgetToApplicationContext (widget));
    exit (0);
}

.... close data-files !!
*/

Boolean RecordRead (char *record)
{
    Note (".");
    return True;
}

Boolean PofadaRecordRead (char *record)
{
    Note("P");
    return True; //RecordRead (record);
}

Boolean StradaRecordRead (char *record)
{
    Note("S");
    return True; //RecordRead (record);
}

Boolean UmsdaRecordRead (char *record)
{
    Note("U");
    return True; //RecordRead (record);
}

Boolean OrtardaRecordRead (char *record)
{
    Note("O");
    return True; //RecordRead (record);
}



ConversionData *NeXTInterface (id nc)
{
    static ConversionData cd;
    static PlzConversion pc;

    cd.pc = &pc;
    cd.nc = nc;
    cd.batch = (Batch *) 0;
    cd.pc->plz_alt = (char *) 0;
    cd.pc->ort = (char *) 0;
    cd.pc->postanstalt = (char *) 0;
    cd.pc->ortsteil = (char *) 0;
    cd.pc->strasse = (char *) 0;
    cd.pc->hausnummer = (char *) 0;
    cd.pc->postfach = (char *) 0;
    cd.pc->plz_neu = (char *) 0;
    cd.pc->verkehrsgebiet = 'W';
    cd.pc->orte = (UmsdaSet *) 0;
    cd.pc->strassen = (StradaSet *) 0;
    cd.pc->postfaecher = (PofadaSet *) 0;

    userInterfaceMethods.uiComponents = (UiComponents *) nc;
    userInterfaceMethods.NoteClear = NuiNoteClear;
    userInterfaceMethods.NoteWrite = NuiNoteWrite;
    userInterfaceMethods.MsgWrite = NuiMsgWrite;
    userInterfaceMethods.MsgFlush = NuiMsgFlush;
    userInterfaceMethods.PofadaRecordRead = PofadaRecordRead;
    userInterfaceMethods.StradaRecordRead = StradaRecordRead;
    userInterfaceMethods.UmsdaRecordRead = UmsdaRecordRead;
    userInterfaceMethods.OrtardaRecordRead = OrtardaRecordRead;
    

    return &cd;
}
