/****************************************************************
*																																*
*	 Filename : LoadL2.c																					*
*																																*
*****************************************************************
*																																*
*		Comment : Loadfunktionen von der Plotlibrary. Unterstützt		*
*							folgenden Funktionen.															*
*																																*
*			                    Funktionen														*
*	                        ==========														*
*																																*
*				loaddata()				spez. Datei wird geladen							*
*				getheader()				liest bis zum '#' und erkennt Typ			*
*				contoup()					konvertiert String										*
*				load2d()					2d Daten werden geladen								*
*				loadniv()					Niveau Daten werden geladen						*
*				load3d()					3d Daten werden geladen								*
*				reallocval()			holt Speicher für neue Daten					*
*																																*
*				Rev : V1.0																							*
*																																*
*		History : V1.0 erstellen dieses Files							26/11/89	*
*																																*
*				Doc : Plotlibrary User's Guide													*
*																																*
*			 Bugs : keine bekannten																		*
*																																*
*			Autor : Oesch Silvano																			*
*																																*
*			Datum : 10/12/89																					*
*																																*
****************************************************************/

/****************************************************************
*																																*
*	Plotlibrary Includedateien																		*
*																																*
****************************************************************/

#include "Plot.h"										/* allg. Includes						*/
#include "PlotL2.h"									/* Level 2									*/
#include "LoadL2.h"									/* und eigene								*/

/****************************************************************
*																																*
*	externe Variablen																							*
*																																*
****************************************************************/

extern struct Plot *plot;						/* Plotpointer							*/
extern int plerr;										/* Fehlervariable						*/

/****************************************************************
*																																*
*	Function : loaddata()																					*
*																																*
*****************************************************************
*																																*
*		 Input : file,typ,name																			*
*							char *file			filename der zu ladenden Daten		*
*							int  typ				Darstellungstyp										*
*							char *name      name der neuen Kurve							*
*																																*
*		Output : int returnset																			*
*							!= NULL					ID der neuen Kurve bei 2D oder		*
*															status bei NIVEAU und 3D					*
*							== NULL					Fehler beim laden oder konvert.		*
*																																*
*****************************************************************
*																																*
*	 Comment : Diese Funktion ist die 2 Stufe der load_data				*
*						 Funktion. Es wird die spez. Datei geöffnet und			*
*						 die erste Zeile gelesen. Danach wird eine Kurven-	*
*						 struktur erzeugt. Anhand des Types werden die			*
*						 verschiedenen Ladefunktionen 											*
*						 aufgerufen.																				*
*																																*
****************************************************************/

int loaddata(file,typ)
char *file;
int typ;
{
	int dattyp,												/* Darstellunstyp von Datei	*/
			returnset,										/* allg. Rückgabewert				*/
			returnload;										/* loadrückgabe							*/

	struct Curve *curve = NULL;				/* Kurvenzeiger							*/
	FILE *fp = NULL;									/* Dateizeiger							*/

	fp = fopen(file,"r");							/* öffne Datei zum lesen		*/
	if (fp == NULL)										/* vorhanden								*/
	{																	/* Nein											*/
		seterror(FILEODATA);						/* setzte Fehler						*/
		setreturn(FALSE);
	}
	else															/* Ja												*/
	{
		dattyp = getheader(fp);					/* Hole Datentyp						*/
		if (dattyp == FALSE)						/* Fehler										*/
			setreturn(FALSE);							/* ja												*/
		else														/* kontrolliere typen				*/

/****************************************************************
*																																*
*	Bei dieser Abfrage werden verschiedene Kriterien untersucht.	*
*																																*
*	1. Ist ein Typ beim Funktionsaufruf vorgegeben, wenn ja				*
*		 stimmt dieser Typ mit dem des Datenfiles überein.					*
*	2. Ist schon eine Kurve im Speicher vorhanden, wenn ja				*
*		 stimmen diese Darstellungstypen überein.										*
*																																*
*																																*
*	Diese beiden Kriterien werden mit einer ODER-Funktion					*
*	verknüpft, d.h. für eine erfolgreiches weiterfahren dieser		*
*	dieser Funktion müssen alle Bedingungen erfüllt sein.					*
*																																*
****************************************************************/

			if (((typ != NOTYP) and
				 (typ != dattyp)) or
				 ((plot->last != NULL) and
				 (dattyp != plot->typ)))
			{															/* Nein Fehler							*/
				seterror(NOTYPEQ);
				setreturn(FALSE);						/* setzte Fehler						*/
			}
			else
			{
				plot->typ = dattyp;					/* setzte Darstellungstyp		*/
				if (dattyp == D3)
					curve = getcurve(DEFCOUNT*2);
																		/* hole neue Kurve					*/
				else
					curve = getcurve(DEFCOUNT);
																		/* hole neue Kurve					*/
				if (curve == FALSE)					/* bekommen									*/
					setreturn(FALSE);					/* Nein, Fehler							*/
				else
				{
					switch (dattyp)						/* Ladefunktionen aufrufen	*/
					{
						case D2:
							returnload = load2d(fp,curve);
							break;
						case NIV:
							returnload = loadniv(fp,curve);
							curve = NULL;					/* löschen, weil schon			*/
							break;								/* addiert									*/
						case D3:
							returnload = load3d(fp,curve);
							break;
						default:
							returnload = FALSE;
							break;
					}
					if (returnload == FALSE)	/* Fehler beim Laden				*/
						setreturn(returnload);	/* dann Fehler setzten			*/
					else
					{
						if (plot->typ == NIV)
							setreturn(plot->currid);
						else
						{
							addlist(curve);				/* add neue Kurve zur Liste	*/
							setreturn(curve->id);	/* mit ID zurück						*/
						}
						if (plot->autoval == AUTOON)
																			/* nur wenn gewünscht				*/
							setminmax();						/* Grenzen korrigieren			*/
					}
				}
			}
	}

	if (fp) fclose(fp);								/* zuletzt Datei schliessen	*/
	if (returnset == FALSE)						/* Fehler aufgetretten			*/
		if (curve)											/* Ja, also alles wieder		*/
		{																/* zurückgeben							*/
			if (curve->val)
				free(curve->val);						/* vorhandene Daten löschen	*/
			free(curve);									/* Kurvenspeicher freigeben	*/
		}
	return(returnset);								/* und zurück								*/
}

/****************************************************************
*																																*
*	Function : getheader()																				*
*																																*
*****************************************************************
*																																*
*		 Input : fp																									*
*							FILE *fp				zu durchsuchende Datei						*
*																																*
*		Output : int typ					Darstellungstyp der Daten					*
*							!= FALSE				typ vorhanden											*
*							== FALSE				kein typ oder nicht spezifiziert	*
*																																*
*****************************************************************
*																																*
*	 Comment : Konvertiert den Darstellungstyp am Anfang der 			*
*						 Datei und überspringt den nachfolgenden Kommentar	*
*						 bis zum ersten Datenpaar.													*
*																																*
****************************************************************/

static int getheader(fp)
FILE *fp;
{
	int i,														/* generelle Schleifenvar.	*/
			returnset = FALSE;						/* Rückgabewert							*/
	char buffer[BUFFERSIZE+1];				/* Einlesebuffer						*/

	char *typnamen[] =								/* Darstellungstypen				*/
	{
		"2D",
		"NIVEAU",
		"3D"
	};

	seterror(INVFILESTR);							/* Voreinstellung Fehler		*/
	if (fscanf(fp,"%80s",buffer) != EOF)
																		/* 1. Zeile Dateiende ?			*/
	{																	/* Nein											*/
		seterror(INVFILETYP);						/* Voreinstellung Fehler		*/
		contoup(buffer);								/* konvertiere String				*/
		for (i=D2;i<=D3;i++)						/* durchsuche Typen					*/
			if (strcmp(buffer,typnamen[i-1]) == NULL)
			{															/* gefunden									*/
				setreturn(i);								/* setzte Typ								*/
				break;											/* und verlasse Schleife		*/
			}
	}

	if (returnset != FALSE)						/* positioniere auf Daten		*/
		while ((fscanf(fp,"%80s",buffer) != EOF)
					 and (buffer[0] != '#'));
																		/* lese solange bis EOF 		*/
																		/* Datenanfang # markiert		*/
	return(returnset);								/* und zurück								*/
}

/****************************************************************
*																																*
*	Function : contoup()																					*
*																																*
*****************************************************************
*																																*
*		 Input : buffer																							*
*							char *buffer				String mit Nullzeichen				*
*																	abgeschlossen									*
*																																*
*		Output : void																								*
*																																*
*****************************************************************
*																																*
*	 Comment : Konvertiert einen String in Grossschrift. Der			*
*						 String muss mit einem Nullzeichen enden.						*
*																																*
****************************************************************/

static void contoup(buffer)
char *buffer;
{
	while (*buffer != EOS)						/* solange kein ende kommt	*/
	{
		*buffer = toupper(*buffer);			/* konvertiere zu upper			*/
		buffer++;												/* und nächstes zeichen			*/
	}
}

/****************************************************************
*																																*
*	Function : load2d()																						*
*																																*
*****************************************************************
*																																*
*		 Input : fp,curve																						*
*							FILE *fp							Dateipointer								*
*							struct Curve *curve		Kurvenpointer								*
*																																*
*		Output : int returnset																			*
*							== EOF								eff. Ende der Datei					*
*							== TRUE								Datenabschluss mit '#'			*
*							== FALSE							Fehler beim laden						*
*																																*
*****************************************************************
*																																*
*	 Comment : Von einer Datei werden 2D-Daten geladen. Es werden	*
*						 Zahlen geladen solange kein Fehler auftritt.				*
*						 Wenn der angeforderte Speicher für die aufnahme		*
*						 der Werte nicht mehr ausreicht, wird ein neuer			*
*						 Speicher angefordert. Die neuen Werte werden				*
*						 eingetragen und dann weiter geladen.								*
*						 Das einlesen wird auf drei Arten beendet.					*
*																																*
*						 1. EOF erreicht -> alle Daten sind geladen					*
*						 2. '#' erkannt  -> alle Daten bis zu diesem				*
*																Zeichen sind geladen						*
*						 3. Illegal			 -> Ein unbekanntes Zeichen welches	*
*																nicht konvertiert werden				*
*																konnte wurde gelesen.						*
*						Nur der dritte Fall gibt einen Rückgabewert von			*
*						FALSE.																							*
*																																*
****************************************************************/

static int load2d(fp,curve)
FILE *fp;
struct Curve *curve;
{
	double x,													/* gelesener X-Wert					*/
				 y;													/* gelesener Y-Wert					*/
	DATA *array = curve->val;					/* Datenfeld								*/
	int sret,													/* fscanf returnwert				*/
			returnset,										/* globaler Rückgabewert		*/
			init = NULL,									/* initialisierungswert			*/
			count = NULL;									/* Datenzähler							*/
	char buffer[BUFFERSIZE+1];				/* Stringbuffer							*/

	forever
	{
		sret = fscanf(fp,"%lf %lf",&x,&y);
																		/* lese von Datei x und y		*/

		if (sret == EOF)								/* End of File erreicht			*/
		{																/* Ja												*/
			curve->count = count;					/* speicher Zähler					*/
			setreturn(EOF);								/* EOF als Rückgabewert			*/
			break;												/* forever verlassen				*/
		}
		else if (sret == D2MULT)				/* x und y gelesen					*/
		{																/* Ja												*/
			*array++=(DATA)x;							/* speichere x und erhöhe		*/
			*array++=(DATA)y;							/* speichere y und erhöhe		*/
			count++;											/* ein Datenfeld mehr				*/
			if (init)											/* Daten schon init ?				*/
			{
				if (curve->xmin > x)				/* ok, nur min und max			*/
					curve->xmin = x;					/* setzten für x						*/
				else if (curve->xmax < x)
					curve->xmax=x;

				if (curve->ymin > y)				/* ok, nur min und max			*/
					curve->ymin = y;					/* setzten für y						*/
				else if (curve->ymax < y)
					curve->ymax=y;
			}
			else													/* nein, also init. mit			*/
			{															/* ersten Werten die vor-		*/
				curve->xmin = curve->xmax = x;
				curve->ymin = curve->ymax = y;
																		/* handen.									*/
				init ++;										/* init switch setzten			*/
			}

			if (count >= curve->maxcount)	/* haben noch weitere Daten	*/
			{															/* platz in dem Datenfeld		*/
				array = reallocval(curve);	/* Nein also hole mehr			*/
				if (array == NULL)					/* bekommen ?								*/
				{
					setreturn(FALSE);					/* Nein Fehler							*/
					break;										/* und forever verlassen		*/
				}
			}
		}
		else														/* weder EOF noch Daten			*/
		{
			sret = fscanf(fp,"%80s",buffer);
																		/* lese als String					*/
			if (buffer[0] != '#')					/* ist 1. Zeichen != '#'		*/
			{															/* Ja												*/
				seterror(INVDATAS);					/* Setzte Fehler						*/
				setreturn(FALSE);
			}
			else													/* also ist es '#'					*/
			{
				curve->count = count;				/* speicher count						*/
				setreturn(TRUE);						/* und mit TRUE zurück			*/
			}
			break;												/* forever verlassen				*/
		}
	}
	return(returnset);								/* status zurückgeben				*/
}

/****************************************************************
*																																*
*	Function : loadniv()																					*
*																																*
*****************************************************************
*																																*
*		 Input : fp,curve																						*
*							FILE *fp							Datenfile										*
*							struct Curve *curve		erste Kurvenstruktur				*
*																																*
*		Output : int return																					*
*							!= FALSE							alles ok										*
*							== FALSE							Fehler beim laden						*
*																																*
*****************************************************************
*																																*
*	 Comment : Von einer Datei werden die Daten als Niveaudaten		*
*						 eingelesen. Zuerst wird der Niveauwert geholt und	*
*						 als z-Koordinate gespeichert. Danach werden die		*
*						 via load2d geladen. Diese Funktion gibt uns zu			*
*						 erkennen, wenn das Ende der Datei da ist. Wenn			*
*						 dies nicht der Fall ist, wird eine neue Kurve			*
*						 gelesen.																						*
*						 Bei einem auftrettenden Fehler werden alle Daten		*
*						 gelöscht und der Speicher ans System zurück-				*
*						 gegeben.																						*
*																																*
****************************************************************/

static int loadniv(fp,curve)
FILE *fp;
struct Curve *curve;
{
	DATA z;														/* Niveau Wert							*/
	int sret,													/* scanf returnwert					*/
	returnset;												/* allg. returnwert					*/

	plot->currid = NULL;							/* setzte auf NULL					*/

	do
	{
		sret = fscanf(fp,"%lf",&z);			/* hole Niveau Wert					*/
		if (sret != 1)									/* bekommen ?								*/
		{
			seterror(INVDATAS);						/* Nein also Fehler					*/
			setreturn(FALSE);	
		}
		else														/* Hurra, alles da					*/
		{
			curve->zmin=curve->zmax=(DATA)z;
																		/* setze als Z-Wert					*/
			setreturn(load2d(fp,curve));	/* und lade 2D Kurve				*/
			if (returnset == TRUE)				/* hat es noch mehr Kurven	*/
			{															/* ja, also hole eine neue	*/
				addlist(curve);							/* add Kurve zur Liste			*/
				curve = getcurve(DEFCOUNT);	/* hole neue Kurve					*/
				if (curve == FALSE)					/* bekommen									*/
					setreturn(FALSE);					/* Nein, Fehler							*/
			}
		}
	}
	while(returnset == TRUE);					/* sobald ein Fehler oder		*/
																		/* EOF da ist brechen wir		*/
																		/* ab												*/
	if (returnset == FALSE)						/* ist abbruch ein fehler		*/
	{
		if (curve)											/* Ja, also alles wieder		*/
		{																/* zurückgeben							*/
			if (curve->val)
				free(curve->val);						/* vorhandene Daten löschen	*/
			free(curve);									/* Kurvenspeicher freigeben	*/
		}
		(void)deldata(DELALL,NULL);			/* und die ganze Liste			*/
																		/* freigeben								*/
	}
	else															/* Es war EOF								*/
	{
		if (curve) addlist(curve);			/* letzte Kurve zur Liste		*/
		sortlist();
	}
	return(returnset);
}

/****************************************************************
*																																*
*	Function : load3d()																						*
*																																*
*****************************************************************
*																																*
*		 Input : fp,curve																						*
*							FILE *fp							Dateipointer								*
*							struct Curve *curve		Kurvenpointer								*
*																																*
*		Output : int return																					*
*							== EOF								eff. Ende der Datei					*
*							== TRUE								Datenabschluss mit '#'			*
*							== FALSE							Fehler beim laden						*
*																																*
*****************************************************************
*																																*
*	 Comment : Von einer Datei werden 3D-Daten geladen. Es werden	*
*						 Zahlen geladen solange kein Fehler auftritt.				*
*						 Wenn der angeforderte Speicher für die aufnahme		*
*						 der Werte nicht mehr ausreicht, wird ein neuer			*
*						 Speicher angefordert. Die neuen Werte werden				*
*						 eingetragen und dann weiter geladen.								*
*						 Das einlesen wird auf drei Arten beendet.					*
*																																*
*						 1. EOF erreicht -> alle Daten sind geladen					*
*						 2. '#' erkannt  -> alle Daten bis zu diesem				*
*																Zeichen sind geladen						*
*						 3. Illegal			 -> Ein unbekanntes Zeichen welches	*
*																nicht konvertiert werden				*
*																konnte wurde gelesen.						*
*						Nur der dritte Fall gibt einen Rückgabewert von			*
*						FALSE.																							*
*																																*
*						Diese Funktion unterscheidet sich nur gering von		*
*						der 2D-Funktion. Um jedoch eine Ladeverzögerung			*
*						zu vermeiden, wurde für die 3D-Darstellung eine			*
*						eigene Funktion geschrieben.												*
*																																*
****************************************************************/

static int load3d(fp,curve)
FILE *fp;
struct Curve *curve;
{
	double x,													/* gelesener X-Wert					*/
				 y,													/* gelesener Y-Wert					*/
				 z;													/* gelesener Z-Wert					*/
	DATA *array = curve->val;					/* Datenfeld								*/
	int sret,													/* fscanf returnwert				*/
			returnset,										/* globaler Rückgabewert		*/
			init = NULL,									/* initialisierungswert			*/
			count = NULL;									/* Datenzähler							*/
	char buffer[BUFFERSIZE+1];				/* Stringbuffer							*/

	forever
	{
		sret = fscanf(fp,"%lf %lf %lf",&x,&y,&z);
																		/* lese von Datei x,y und z	*/

		if (sret == EOF)								/* End of File erreicht			*/
		{																/* Ja												*/
			curve->count = count;					/* speicher Zähler					*/
			setreturn(EOF);								/* EOF als Rückgabewert			*/
			break;												/* forever verlassen				*/
		}
		else if (sret == D3MULT)				/* x,y und z gelesen				*/
		{																/* Ja												*/
			*array++=(DATA)x;							/* speichere x und erhöhe		*/
			*array++=(DATA)y;							/* speichere y und erhöhe		*/
			*array++=(DATA)z;							/* speichere z und erhöhe		*/
			count++;											/* ein Datenfeld mehr				*/
			if (init)											/* Daten schon init ?				*/
			{
				if (curve->xmin > x)				/* ok, nur min und max			*/
					curve->xmin = x;					/* setzten für x						*/
				else if (curve->xmax < x)
					curve->xmax=x;

				if (curve->ymin > y)				/* ok, nur min und max			*/
					curve->ymin = y;					/* setzten für y						*/
				else if (curve->ymax < y)
					curve->ymax=y;

				if (curve->zmin > z)				/* ok, nur min und max			*/
					curve->zmin = z;					/* setzten für z						*/
				else if (curve->zmax < z)
					curve->zmax=z;
			}
			else													/* nein, also init. mit			*/
			{															/* ersten Werten die vor-		*/
				curve->xmin = curve->xmax = x;
				curve->ymin = curve->ymax = y;
				curve->zmin = curve->zmax = z;
																		/* handen.									*/
				init ++;										/* init switch setzten			*/
			}

			if (count >= curve->maxcount)	/* haben noch weitere Daten	*/
			{															/* platz in dem Datenfeld		*/
				array = reallocval(curve);	/* Nein also hole mehr			*/
				if (array == NULL)					/* bekommen ?								*/
				{
					setreturn(FALSE);					/* Nein Fehler							*/
					break;										/* und forever verlassen		*/
				}
			}
		}
		else														/* weder EOF noch Daten			*/
		{
			sret = fscanf(fp,"%80s",buffer);
																		/* lese als String					*/
			if (buffer[0] != '#')					/* ist 1. Zeichen != '#'		*/
			{															/* Ja												*/
				seterror(INVDATAS);					/* Setzte Fehler						*/
				setreturn(FALSE);
			}
			else													/* also ist es '#'					*/
			{
				curve->count = count;				/* speicher count						*/
				setreturn(TRUE);						/* und mit TRUE zurück			*/
			}
			break;												/* forever verlassen				*/
		}
	}
	return(returnset);								/* status zurückgeben				*/
}

/****************************************************************
*																																*
*	Function : reallocval()																				*
*																																*
*****************************************************************
*																																*
*		 Input : curve																							*
*							struct Curve *curve		Kurvenzeiger								*
*																																*
*		Output : DATA *returnset				Datenfeldzeiger							*
*							!= NULL								neuer Speicherbereich				*
*																		bekommen. Zeiger auf				*
*																		nächstes freies Element.		*
*							== NULL								Kein neuer Speicherbereich	*
*																		bekommen										*
*																																*
*****************************************************************
*																																*
*	 Comment : Wenn die Kurvendaten nicht in das erste Datenfeld	*
*						 hineinpassen, muss ein grösserer Speicherbereich		*
*						 geholt werden. Dieser neue Speicher erhält um			*
*						 um COUNTSTEP (definiert in Plot.h) mehr Elemente		*
*						 als zuvor. Die Grösse des Feldes sieht also wie		*
*						 folgt aus:																					*
*												1. DEFCOUNT															*
*												2. DEFCOUNT+COUNTSTEP										*
*												3. DEFCOUNT+2*COUNTSTEP									*
*																	"															*
*						 Die Daten werden in diesen neuen Speicherbereich		*
*						 kopiert und die Kurvenstruktur wird korrigiert.		*
*						 Der Rückgabewert ist ein Zeiger auf das nächste		*
*						 freie Element in diesem Datenfeld. Diese Routine		*
*						 kann für 2D und 3D Daten verwendet werden.					*
*																																*
****************************************************************/

static DATA *reallocval(curve)
struct Curve *curve;
{
	int newcount,											/* neue Anzahl Elemente			*/
			newsize;											/* neue Grösse in Bytes			*/
	DATA *val,												/* Zeiger auf Datenfeld			*/
			 *returnset;									/* allg. Rückgabewert				*/

	if (plot->typ == D3)
		newcount = curve->maxcount+COUNTSTEP*2;
	else
		newcount = curve->maxcount+COUNTSTEP;
																		/* newcount berechnen				*/
	newsize = getsize(newcount);			/* hole Grösse							*/
	val = realloc(curve->val,newsize);
																		/* und hole neuen Speicher	*/
	if (val == NULL)									/* bekommen ?								*/
	{																	/* Nein Fehler							*/
		seterror(REALFAIL);
		setreturn(val);									/* zurück mit NULL					*/
	}
	else															/* Ja Kurve korrigieren			*/
	{
		setreturn(&val[curve->maxcount*valsize()]);
																		/* nächstes freie Element		*/
																		/* berechnen								*/
		curve->maxcount = newcount;			/* neuer maxcount setzten		*/
		curve->val = val;								/* neuer Datenfeldzeiger		*/
	}
	return(returnset);
}

