/****************************************************************************/
/*																			*/
/*									Dump.h									*/
/*																			*/
/****************************************************************************/
/****************************************************************************/
/* This is a C language header file that defines a routine for reading		*/
/* 'dump' format data files into memory. The dump format is a data format	*/
/* used at Nurmijarvi Observatory to store raw magnetometer data.			*/
/*																			*/
/*	-------------------  Read data from a dump-format file	--------------	*/
/*																			*/
/* long ReadDump(char *FileName,NetworkPtr Network,char *StartTimeStr,		*/
/*				 char *EndTimeStr,char *StationList)						*/
/*		FileName		Name of the dump-file containing the data.			*/
/*						If FileName is nil or zero length then standard		*/
/*						input is used.										*/
/*		Network			Structure into which the data is read.				*/
/*						Network_struct is defined in file MagnData.h.		*/
/*		StartTimeStr	String defining the first time to be read from  	*/
/*						the data file (String delimited with '\0').			*/
/*						String format : YYMMDDHH. If HH is missing then		*/
/*						00 is assumed. If StartTimeStr is nil or zero		*/
/*						length then start of file is assumed.				*/
/*		EndTimeStr		String defining the time not to be read anymore.	*/
/*						Format as before YYMMDDHH. If nil or zero length	*/
/*						then data is read until end of file.				*/
/*		StationList		List of stations included in the data. The stations	*/
/*						must be specified with three letter codes			*/
/*						(e.g. SOR) and must be separeted with a space in	*/
/*						the list (e.g. 'SOR MAS KEV'). If nil or zero		*/
/*						length then all stations in the file are included.	*/
/*																			*/
/*		The function result indicates how successfull the file reading was:	*/
/*				0: OK			: File read successfully					*/
/*				1: FileError	: Failed to read the given file				*/
/*				2: OutOfMemory	: Memory allocation failed during reading	*/
/*				3: FormatError	: File to be read is not Dump file			*/
/*																			*/
/*	-------------------  Write data into a dump-format file	--------------  */
/*																			*/
/* long WriteDump(char *FileName,NetworkPtr Network,char *StartTimeStr,		*/
/*				  char *EndTimeStr,char *StationList)						*/
/* 		FileName		Name of the Dump file. IF NULL or zero length then	*/
/*						stdout is used.										*/
/*		Network			Pointer to the Network structure whose data is to	*/
/*						be written into a file.								*/
/* 		StartTimeStr	Start date string YYMMDDHHMM. If NULL then same as	*/
/*						the time of the first record of the first station	*/
/*						in the Network data structure.						*/
/* 		EndTimeStr		End date string YYMMDDHHMM. This record is NOT		*/
/*						included anymore. If NULL then data till the end of	*/
/*						first station in Network structure will be written.	*/
/*		StationList		String containing the 3-letter ID's of the station.	*/
/*						Only one station is allowed.						*/
/*																			*/
/*	The function result indicates how successfull the file writing was:		*/
/*				0: OK			: Data written successfully					*/
/*				1: FileError	: Failed to create the given file			*/
/*																			*/
/*	NOTE: Contrary to almost all other data format header files data in		*/
/*		  Dump.h is read into Network-structure using 0.01 nT field			*/
/*		  resolution. All the others (e.g. IAGA.h) use 0.1 nT resolution.	*/
/*		  This must be taken into account e.g. when writing format			*/
/*		  conversion filters.												*/
/****************************************************************************/
/****************************************************************************/
/*							  Lasse Hakkinen								*/
/*					  Finnish Meteorological Institute						*/
/*						  Department of Geophysics							*/
/*								P.O.Box 503									*/
/*						FIN-00101, Helsinki, Finland						*/
/*						e-mail: Lasse.Hakkinen@fmi.fi						*/
/*						phone : (+358)-9-19294634							*/
/*						fax   : (+358)-9-19294603							*/
/*																			*/
/*						version 1.24		 8.5.2006						*/
/****************************************************************************/
/****************************************************************************/
/*	Version history:														*/
/*																			*/
/*	1.24 08.05.2006 Fixed a bug where reading failed when there is a data 	*/
/*					gap and more than 24 hours of data.						*/
/*	1.23 09.11.2005 Changed MaxParamLineCount to 10000.						*/
/*	1.22 04.10.2004 Added station code 'I' for Mekrijarvi station.			*/
/*	1.21 08.03.2004 Modified ReadDump so that it does not stop if d-line	*/
/*					contains illegal characters or its length is not OK.    */
/*                  In these situations the erronuous line is neglected.	*/
/*	1.20 07.11.2003 Added CheckLine-routine for checking illegal characters */
/*					in the data file. Also added line length checking.		*/
/*	1.19 15.10.2001 Fixed a bug which caused a crash when reading unix		*/
/*					format data file in a Mac.								*/
/*	1.18 18.09.2001 Changed station code 'T' from O_E to TAR (= Tartu)		*/
/*	1.17 15.10.1999 Modified NextDumpLine so that it neglects the last data */
/*					line if it does not end with CR or LF. This prevents    */
/*					some mysterious behaviour.								*/
/*	1.16 13.10.1999 Remodified ReadDump so that it no longer breaks program	*/
/*					execution if data lines are not in chronological order.	*/
/*	1.15 02.02.1999 made GetDumpTime-routine non-static.					*/
/*	1.14 20.11.1998 Fixed a bug which multiplied field values by 10 if data	*/
/*					was written in Dump format with 0.1 nT resolution.		*/
/*	1.13 11.11.1998 Changed MaxParamLineCount to 200.						*/
/*  1.12 05.11.1998 Added station codes R,V,L,Q,W .							*/
/*	1.11 28.10.1998 Modified read and write routines so that the extra		*/
/*					s-component is read into the A-field in Station_struct.	*/
/*	1.1  21.10.1998 When reading data into memory a field resolution of		*/
/*					0.01 nT is used (previously 0.1 nT). WriteDump routine	*/
/*					added.													*/
/*	1.03 29.09.1998 Modified ReadDump so that it no longer breaks program	*/
/*					execution if data lines are not in chronological order.	*/
/*	1.02 15.09.1998 Modified ReadDump so that it no longer breaks program	*/
/*					execution if two data lines have same time.				*/
/*	1.01 17.07.1998 Modified GetFloat so that field values '*********' are	*/
/*					interpreted as missing data values.						*/
/*	1.0  10.11.1996	First official release									*/
/****************************************************************************/

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

/*--------------------------------------------------------------------------*/
/* Define the correspondence between one letter dump station char and the	*/
/* conventional three letter Station ID (e.g. N = NUR, P = PEL).			*/
/* New station names may be added by changing StationCodeCount and adding a	*/
/* new line into the StationName array (the line may be added anywhere in	*/
/* StationName, not necessarily to end).									*/
/*--------------------------------------------------------------------------*/

#define StationCodeCount 20

static char *StationName[StationCodeCount] = {
"F NUR",
"N NUR",
"P PEL",
"K KIL",
"O OUJ",
"U OUJ",
"H HAN",
"I MEK",
"M MUO",
"E KEV",
"S SOR",
"A MAS",
"R NUR",
"L OUL",
"Q KVI",
"W NOR",
"V IVA",
"G MAN",
"B SOD",
"T TAR"
};

static long		LineNbr;			/* Current line number					*/
static char		Resolution;			/* Number of decimals used in writing	*/
									/* field values in dump file. Must be	*/
									/* either 1 or 2						*/

/*--------------------------------------------------------------------------*/
/* Define the variables used for storing information about parameter lines	*/
/* (= non-d lines = b-,x-,y-,z-,t- ... lines).								*/
/*--------------------------------------------------------------------------*/

#define MaxParamLineCount 10000
static char	ParamLine[MaxParamLineCount][80];/* All non-d lines are stored	*/
											 /* into this array				*/
static Time_sec ParamLineTime[MaxParamLineCount];/* Times of param lines	*/
static long ParamLineCount = 0;		/* Number of parameter lines			*/


static char ComponentStr[6];		/* Components defined in d-lines. This 	*/
									/* must be same in all d-lines.			*/
static char StationChar;			/* One letter station character			*/



/*--------------------------------------------------------------------------*/
/* Define the offsets of various fields from the beginning of line in a		*/
/* dump format data file.													*/
/*--------------------------------------------------------------------------*/

#define Dump_LineID			 0
#define Dump_InstrID		 1
#define Dump_Components		 2
#define Dump_AverageTime	 8
#define Dump_Year			12
#define Dump_Month			17
#define Dump_Day			20
#define Dump_Hour			23
#define Dump_Minute			26
#define Dump_Second			29
#define Dump_X				31
#define Dump_Y				40
#define Dump_Z				49
#define Dump_T				58
#define Dump_A				67
#define Dump_TimingChar		15


#define MissingDump 9999999


/*--------------------------------------------------------------------------*/
/* Function prototypes														*/
/*--------------------------------------------------------------------------*/

static long GetFileSize(char *FileName);
static long GetPositiveInt(char *p);
static long GetFloat(char *p);
Time_sec GetDumpTime(char *Line);
static void SetDumpStationID(char StatChar,char *StationID);
static void SetStationParamsDump(StationPtr Station,char StatChar,char *StatList);
static char *NextDumpLine(char *Line);
static long CheckLine(char *Line);
static long GetLineLength(char *Line);
static void AddMissingData(StationPtr Station,Time_sec Time,Time_sec OldTime);
static void GetDumpData(StationPtr Station, char *Line, Time_sec Time);
static void GetParamLine(char *Line,Time_sec Time);
long ReadDump(char *FileName,NetworkPtr Network,char *StartTimeStr,
			  char *EndTimeStr,char *StationList);

static void Print1(FILE *DumpFile,long value);
static void Print2(FILE *DumpFile,long value);
static void WriteXYZ(FILE *DumpFile, StationPtr Station, Time_sec Time);
static void WriteParamLine(FILE *DumpFile,char *Line);
static void Write_d_line(FILE *DumpFile,StationPtr Station, Time_sec Time);
long WriteDump(char *FileName,NetworkPtr Network);


/*==========================================================================*/
/*					Routines for reading Dump-format files					*/
/*==========================================================================*/

/*--------------------------------------------------------------------------*/
/*	Find size of a data file												*/
/*--------------------------------------------------------------------------*/

static long GetFileSize(char *FileName)
{
	long	dummy = 0;
	FILE	*DataFile;

	if ((DataFile = fopen(FileName, "r")) != NULL) {
		dummy = fseek(DataFile,0L,SEEK_END);
		dummy = ftell(DataFile);
		fclose(DataFile);
	}
	return dummy;
}


/*--------------------------------------------------------------------------*/
/* Get positive integer value from the Buffer. We could also use sscanf		*/
/* but this is considerably faster because no checkings are made.			*/
/*--------------------------------------------------------------------------*/

static long GetPositiveInt(char *p)
{
	long value;

	while (*p == ' ') p++;		/* scan leading spaces */

	value = (*p++ -'0');		/* Go through the digits */
	while ((*p >= '0') && (*p <= '9'))
		value = 10*value+(*p++ - '0');

	return (value);
}


/*--------------------------------------------------------------------------*/
/* Get a floating point number from the Buffer. The number may contain		*/
/* either 1 or 2 decimals. The value is multiplied by 100. This convention	*/
/* implies the use of 0.01 nT accuracy in field values and 0.01 C accuracy	*/
/* in temperature values.													*/
/* We could also use sscanf, but this is considerably faster because no		*/
/* checkings are made.														*/
/*--------------------------------------------------------------------------*/

static long GetFloat(char *p)
{
	long value;
	long negative;

	while (*p == ' ') p++;			/* scan leading spaces		*/

	if (*p == '*') return (MissingValue);	/* ignore garbage	*/

	negative = (*p == '-');			/* check the sign			*/
	if (negative) p++;

	value = (*p++ - '0');			/* get the integer part		*/
	while (*p != '.')
		value = 10*value+(*p++ - '0');

	p++;							/* get the first decimal	*/
	value = 10*value+(*p++ -'0');

	if ((*p >= '0') && (*p <= '9'))	/* get the last decimal 	*/
		value = 10*value+(*p++ -'0');
	else
		value *= 10;

	if (value == MissingDump)		/* Missing value may be		*/
		return (MissingValue);		/* 99999.99 in dump file	*/

	if (negative) return(-value);	/* return the result		*/
	return (value);
}


/*--------------------------------------------------------------------------*/
/*	Get the time of current data line in seconds. 'Line' points to the		*/
/*  first character in the current line.									*/
/*--------------------------------------------------------------------------*/

Time_sec GetDumpTime(char *Line)
{
	Time_struct MyTime;

	MyTime.tm_year = GetPositiveInt(Line+Dump_Year)-1900;
	MyTime.tm_mon  = GetPositiveInt(Line+Dump_Month)-1;
	MyTime.tm_mday = GetPositiveInt(Line+Dump_Day);
	MyTime.tm_hour = GetPositiveInt(Line+Dump_Hour);
	MyTime.tm_min  = GetPositiveInt(Line+Dump_Minute);
	MyTime.tm_sec  = GetPositiveInt(Line+Dump_Second);
	return (TmToSecs(&MyTime));
}



/*--------------------------------------------------------------------------*/
/*	Convert the one character Station code in the dump file into three		*/
/*	letter Station ID string.												*/
/*--------------------------------------------------------------------------*/

static void SetDumpStationID(char StatChar,char *StationID)
{
	long i = 0;

	while ((i<StationCodeCount) && (StatChar != *StationName[i])) i++;

	if (i < StationCodeCount) strcpy(StationID,StationName[i]+2);
	else StationID[0] = 0;	/* Station char is not defined in StationName	*/
							/* array. Set the StationID to zero length		*/
}

/*--------------------------------------------------------------------------*/
/*	Fill some fields in the Station_struct by copying them from the			*/
/*	StationInfo structure defined in the StatInfo.h file.					*/
/*--------------------------------------------------------------------------*/

static void SetStationParamsDump(StationPtr Station,char StatChar,char *StatList)
{
	StationInfoPtr StationInfo;

	/* Set the station ID */
	if ((StatList == NULL) || (strlen(StatList) == 0)) { /* Station ID from	*/
		SetDumpStationID(StatChar,Station->StationID);	 /* dump file		*/
	}
	else {
		strncpy(Station->StationID,StatList,3);			 /* Station ID from	*/
		Station->StationID[3] = '\0';					 /* command line	*/
	}

	StationInfo = FindStationInfo(Station->StationID);

	/* Set the location of the station */
	Station->Latitude  = StationInfo->Latitude;
	Station->Longitude = StationInfo->Longitude;

	/* Set the component markers */
	strcpy(Station->Components,"XYZ");
}


/*--------------------------------------------------------------------------*/
/* Find the start of next line in the Buffer. The line may be terminated by	*/
/* a newline (NL) or carriage return (CR) or NL+CR.							*/
/*--------------------------------------------------------------------------*/

static char *NextDumpLine(char *Line)
{
	register char *ChrPtr = Line;

	while (*ChrPtr++ > 31);
	if (*ChrPtr == 0) return (NULL);		/* End of file					*/
	if (*ChrPtr < 32) {						/* Linefeed or carriage return	*/
		ChrPtr++;
		if (*ChrPtr == 0) return (NULL);
	}

	LineNbr++;
	return(ChrPtr);
}


/*--------------------------------------------------------------------------*/
/* Check that there are no illegal characters in the line (e.g. letters		*/
/* after the 7th character). Also check that the spaces are in correct		*/
/* positions.																*/
/*--------------------------------------------------------------------------*/

static long CheckLine(char *Line)
{
	register char *p = Line;

	if (*p == 0) return (0);		/* End of file					*/

	if (Line[ 7] != ' ') return (1);
	if (Line[11] != ' ') return (1);
	if (Line[16] != ' ') return (1);
	if (Line[19] != ' ') return (1);
	if (Line[22] != ' ') return (1);
	if (Line[25] != ' ') return (1);
	if (Line[28] != ' ') return (1);

	p = Line+8;
	while (*p > 31) {
		if (*p > '9') return (1);
		if ((*p < '0') && (*p != ' ') && (*p != '-') && (*p != '.')) return (1);
		p++;
	}

	return (0);
}


/*--------------------------------------------------------------------------*/
/* Get the length of the line.												*/
/*--------------------------------------------------------------------------*/

static long GetLineLength(char *Line)
{
	register char *p = Line;
	register length = 0;

	while (*p++ > 31) length++;
	return (length);
}


/*--------------------------------------------------------------------------*/
/* Set missing data values from OldTime+TimeStep to Time-TimeStep			*/
/*--------------------------------------------------------------------------*/

static void SetMissingData(StationPtr Station,Time_sec Time,Time_sec OldTime)
{
	long i,Count;
	OneDay_struct *p;
	long *XPtr,*YPtr,*ZPtr,*TPtr,*APtr;

	/* Find the last OneDayBlock */
	for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay);

	/* Set the pointers within the OneDayBlock */
	XPtr = (p->X)+(p->XCount);
	YPtr = (p->Y)+(p->YCount);
	ZPtr = (p->Z)+(p->ZCount);
	TPtr = (p->T)+(p->TCount);
	APtr = (p->A)+(p->TCount);

	/* Set missing values */
	Count = (Time-OldTime)/Station->TimeStep - 1;
	for (i=0;i<Count;i++) {
		*XPtr++ = MissingValue;
		*YPtr++ = MissingValue;
		*ZPtr++ = MissingValue;
		*TPtr++ = MissingValue;
		*APtr++ = MissingValue;
	}

	/* Update counters */
	p->XCount += Count;
	p->YCount += Count;
	p->ZCount += Count;
	p->TCount += Count;
}


/*--------------------------------------------------------------------------*/
/* Copy data from a single data line into the proper OneDayBlock.			*/
/*--------------------------------------------------------------------------*/

static void GetDumpData(StationPtr Station, char *Line, Time_sec Time)
{
	OneDay_struct *p;
	long *XPtr,*YPtr,*ZPtr,*TPtr,*APtr;

	/* Find the last OneDayBlock */
	for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay);

	/* Set the pointers within the OneDayBlock */
	XPtr = (p->X)+(p->XCount);
	YPtr = (p->Y)+(p->YCount);
	ZPtr = (p->Z)+(p->ZCount);
	TPtr = (p->T)+(p->TCount);
	APtr = (p->A)+(p->TCount);

	/* Copy the data */
	*XPtr = GetFloat(Line+Dump_X);
	*YPtr = GetFloat(Line+Dump_Y);
	*ZPtr = GetFloat(Line+Dump_Z);
	if (Line[5] == 'T')
		*TPtr = GetFloat(Line+Dump_T);
	else
		*TPtr = MissingValue;

	if (Line[6] == 's')
		*APtr = GetFloat(Line+Dump_A);
	else
		*APtr = MissingValue;

	/* Update counters */
	p->XCount++;
	p->YCount++;
	p->ZCount++;
	p->TCount++;

	/* Set the last time */
	Station->EndTime = Time+Station->TimeStep;
}

/*--------------------------------------------------------------------------*/
/* Copy a parameter line into ParamLine-array.								*/
/*--------------------------------------------------------------------------*/

static void GetParamLine(char *Line,Time_sec Time)
{
	char *p,*q;

	p = ParamLine[ParamLineCount];
	q = Line;

	while (*q > 31) *p++ = *q++;
	*p = *q;

	ParamLineTime[ParamLineCount] = Time;
	ParamLineCount++;
}


/*--------------------------------------------------------------------------*/
/*	Here is the routine for reading Dump-format data file into memory.		*/
/*	The data is read into a Network structure (see MagnData.h for details).	*/
/*	See the comments at the beginning of this file for more details about	*/
/*	the parameters for this routine.										*/
/*																			*/
/*	The rounite works by reading the data file one line at a time and adds	*/
/*	that data in the particular stations data block. If the data block		*/
/*	becomes full a new one day block is allocated. At the end of the		*/
/*	routine all one day blocks are combined into a single data block.		*/
/*--------------------------------------------------------------------------*/

long ReadDump(char *FileName,NetworkPtr Network,char *StartTimeStr,
			  char *EndTimeStr,char *StationList)
{
	FILE	*Dumpfile;				/* The data file to be processed		*/
	char	*Line;					/* Points to start of current data line */
	Time_sec Time;					/* Time of the current data line	   	*/
	Time_sec OldTime;				/* Time of previous data line			*/
	Time_sec TempTime;				/* Time of Current data line			*/
	Time_sec StartTime;				/* Time of first record to be read		*/
	Time_sec EndTime;				/* Time of record not read anymore		*/
	Time_sec TimeStep;				/* Interval between successive points	*/
	StationPtr Station;				/* Pointer to the current station		*/
	long	FirstLine = 1;			/* Flag for first valid data line		*/
	long	LineLength;				/* Length of d-lines					*/
	char	TimingChar;				/* How mean values are computed ?		*/
									/* S = start, M = middle, E = end		*/
	long DumpFileSize;				/* Size of the dump file in bytes		*/
	char *DumpBuffer;				/* Read the whole dump file into this	*/
									/* buffer.								*/

	char CurrTime[20];
	long i;


	InitNetwork(Network);			/* Initialize the fields of Network		*/

	/* --- Set the start and end times --- */
	if ((StartTimeStr == NULL) || (*StartTimeStr == '\0'))
		StartTime = MIN_TIME;
	else StartTime = StrToSecs(StartTimeStr,0);

	if ((EndTimeStr == NULL) || (*EndTimeStr == '\0')) EndTime = MAX_TIME;
	else EndTime = StrToSecs(EndTimeStr,0);


	/* --- Try to read the file into memory --- */
	if ((FileName == NULL) || (*FileName == '\0')) {
		fprintf(stderr,"### FileName not specified\n");
		return(FileError);
	}

	DumpFileSize = GetFileSize(FileName);
	if (DumpFileSize == 0) {
		fprintf(stderr,"### Could not open file %s\n",FileName);
		return FileError;
	}

	DumpBuffer = malloc(DumpFileSize+1);
	if (DumpBuffer == NULL) {
		fprintf(stderr,"### Out of memory !\n");
		return(OutOfMemory);
	}
	DumpBuffer[DumpFileSize] = 0;	/* Set our end of file mark	*/

	Dumpfile = fopen(FileName,"r");
	if (fread(DumpBuffer,DumpFileSize,1,Dumpfile) == 0) {
		fprintf(stderr,"### Could not read file %s\n",FileName);
		return FileError;
	}
	fclose(Dumpfile);


	/* --- Handle the first line. It should start with letter 'i' ---*/
	Line = DumpBuffer;
	if (*Line != 'i') {
		fprintf(stderr,"### The first line is not an i-line\n");
		fprintf(stderr,"File \"%s\" ; Line 1\n",FileName);
		free(DumpBuffer);
		return(FileFormatError);
	}

	/* --- Set up some parameters  ---*/
	TimeStep = GetPositiveInt(Line+Dump_AverageTime);
	if ((TimeStep < 1) || (TimeStep > 999)) {
		fprintf(stderr,"### Illegal value for time resolution %d\n",TimeStep);
		fprintf(stderr,"File \"%s\" ; Line 1\n",FileName);
		free(DumpBuffer);
		return(FileFormatError);
	}
	TimingChar = Line[Dump_TimingChar];
	Station = AddNewStation(Network,TimeStep,TimeStep);
	StationChar = Line[1];
	if (Station != NULL)
		SetStationParamsDump(Station,StationChar,StationList);
	else {	/* Unable to allocate memory for station data	*/
		free(DumpBuffer);
		return(OutOfMemory);
	}
	ParamLineCount = 0;

	/* --- Check that the station code is defined --- */
	if (strlen(Station->StationID) == 0) {
		fprintf(stderr,"### The station code %c is undefined\n",StationChar);
		fprintf(stderr,"File \"%s\" ; Line 1\n",FileName);
		free(DumpBuffer);
		return(FileError);
	}

	/* --- Find the first 'd'-line and check the field resolution --- */

	Line = DumpBuffer;
	LineNbr = 1;
	while ((Line != NULL) && (*Line != 'd')) Line = NextDumpLine(Line);
	if (Line == NULL) {
		fprintf(stderr,"### No d-lines found in the input file\n");
		free(DumpBuffer);
		return(FileFormatError);
	}
	if (*(Line+37) == '.')
		Resolution = 2;
	else
		Resolution = 1;

	/* --- Check the components --- */

	strncpy(ComponentStr,Line+Dump_Components,6);
	if (strncmp(ComponentStr,"XYZ",3)) {
		fprintf(stderr,"### Components are not XYZ: %.3s\n",Line+2);
		fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
		free(DumpBuffer);
		return(FileFormatError);
	}

	/* --- Set the components in the station structure --- */

	strncpy(Station->Components,ComponentStr,6);
	for (i=0;i<6;i++) {
		if (ComponentStr[i] == 's') Station->Components[i] = 'A';
		if (ComponentStr[i] == ' ') Station->Components[i] = '\0';
	}


	Line = DumpBuffer;
	LineNbr = 1;
	Time = MIN_TIME;
	GetParamLine(Line,Time);		/* The first line: i-line */


	/* --- Read data into one day blocks ---*/

	while ((Line = NextDumpLine(Line)) != NULL)
	{
		/* Weak check of dump format */
		if ((*Line < 'a') || (*Line > 'z'))	{
			fprintf(stderr,"### First character in line %d is illegal:\n",LineNbr);
			fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
			free(DumpBuffer);
			return(FileFormatError);
		}

		/* check the line for illegal characters, except i- and c -lines, */
		if ((*Line != 'i') && (*Line != 'c')) {
			if (CheckLine(Line)) {
				fprintf(stderr,"### Illegal character(s) in line %d. Line ignored.\n",LineNbr);
				fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
				continue;
				/* free(DumpBuffer); */
				/* return(FileFormatError); */
			}
		}

		/* Store non-d lines into ParamLine-Array	*/
		if (*Line != 'd') {
			if ((*Line != 'i') && (*Line != 'c'))
				Time = GetDumpTime(Line);
			GetParamLine(Line,Time);

			if (ParamLineCount == MaxParamLineCount) {
				fprintf(stderr,"### Sorry, too many parameter lines in dumpfile %s\n",FileName);
				fprintf(stderr,"### Cannot continue\n");
				free(DumpBuffer);
				return(FileFormatError);
			}
			continue;
		}

		/* Check that the station code hasn't changed */
		if (StationChar != Line[1]) {
			fprintf(stderr,"### Different station character ? %c\n",Line+1);
			fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
			free(DumpBuffer);
			return(FileFormatError);
		}

		/* Check that the component characters haven't changed */
		if (strncmp(ComponentStr,Line+Dump_Components,6)) {
			fprintf(stderr,"### Different components ? %.6s\n",Line+2);
			fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
			free(DumpBuffer);
			return(FileFormatError);
		}

		/* Check if we already have all required data */
		if ((Time = GetDumpTime(Line)) >= EndTime) break;

		/* Handle a d-line */
		if (Time >= StartTime) {
			if (FirstLine) {		/* First valid data line */
				Station->StartTime = Time;
				OldTime = Time;
				LineLength = GetLineLength(Line);
				FirstLine = 0;
			}
			else {	/* Check times and add missing data if necessary	*/
				if (LineLength != GetLineLength(Line)) {
					fprintf(stderr,"### Line length not constant ?!. Line ignored.\n");
					fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
					continue;
					/* free(DumpBuffer); */
					/* return(FileError); */
				}
				else
				if ((Time - Station->StartTime) % TimeStep != 0) {
					fprintf(stderr,"### Illegal time %.20s\n",Line+12);
					fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
					free(DumpBuffer);
					return(FileError);
				}
				else
				if (Time < OldTime) {
					fprintf(stderr,"### Warning: Data lines not in chronological order\n");
					fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
					/* free(DumpBuffer); */
					/* return(FileError); */
					continue;
				}
				else
				if (Time == OldTime) {		/* same data line twice */
					fprintf(stderr,"### Warning: Same time in two lines !\n");
					fprintf(stderr,"File \"%s\" ; Line %d\n",FileName,LineNbr);
					continue;				/* do nothing */
				}
				else
				if (Time-OldTime != TimeStep) {	/* Add missing data points */
					for (TempTime=OldTime+TimeStep; TempTime < Time; TempTime += TimeStep) {
						SetMissingData(Station,TempTime+TimeStep,TempTime-TimeStep);
						if (OneDayFull(Station,'Z')) {
							if (AddOneDay(Station))
								return(OutOfMemory); 	   /* Failed to allocate memory */
						}
					}
				}
			}

			if (OneDayFull(Station,'Z')) {
				if (AddOneDay(Station))
					return(OutOfMemory); 	   /* Failed to allocate memory */
			}
			GetDumpData(Station,Line,Time);		/* Finally get data values	*/
			OldTime = Time;
		}
	}

	free(DumpBuffer);


	/* --- Combine one day blocks into one large block	 ---*/
	/* --- and correct the start and end times according ---*/
	/* --- to the TimingChar value.						 ---*/

	Station = Network->StationList;
	while (Station != NULL) {
		if (CombineData(Station) == OutOfMemory) return(OutOfMemory);
		switch (TimingChar) {
			case 'S' : break;
			case 'M' : break;
					/* Station->StartTime -= TimeStep/2;
					   Station->EndTime   -= TimeStep/2;
					   break; */
			case 'E' : Station->StartTime -= TimeStep;
					   Station->EndTime   -= TimeStep;
					   break;
		}
		Station = Station->Next;
	}


	return OK;
}



/*==========================================================================*/
/*				Routines for writing Dump-format files						*/
/*==========================================================================*/

/*--------------------------------------------------------------------------*/
/* Write a field value (1 or 2 decimals) to given dump file.				*/
/*--------------------------------------------------------------------------*/

static void Print1(FILE *DumpFile,long value)
{
	double X;

	X = value/100.0;
	if (value != MissingValue)
		fprintf(DumpFile,"%9.1f",X);
	else
		fprintf(DumpFile,"  99999.9");
}

static void Print2(FILE *DumpFile, long value)
{
	double X;

	X =  value/100.0;
	if (value != MissingValue)
		fprintf(DumpFile,"%9.2f",X);
	else
		fprintf(DumpFile," 99999.99");
}


/*--------------------------------------------------------------------------*/
/* Write X, Y and Z values to the current dump line. Also T is written if	*/
/* it exists in the original file.											*/
/*--------------------------------------------------------------------------*/

static void WriteXYZ(FILE *DumpFile, StationPtr Station, Time_sec Time)
{
	long X,Y,Z,T,A;
	long count;

	count = (Time - Station->StartTime)/(Station->TimeStep);
	X = *(Station->X + count);
	Y = *(Station->Y + count);
	Z = *(Station->Z + count);

	if (Resolution == 1) {
		Print1(DumpFile,X);
		Print1(DumpFile,Y);
		Print1(DumpFile,Z);
	}
	else {
		Print2(DumpFile,X);
		Print2(DumpFile,Y);
		Print2(DumpFile,Z);
	}

	if (ComponentStr[3] != ' ') {
		T = *(Station->T + count);
		if (Resolution == 1)
			Print1(DumpFile,T);
		else
			Print2(DumpFile,T);
	}

	if (ComponentStr[4] != ' ') {
		A = *(Station->A + count);
		if (A == MissingValue) A = 0;
		if (Resolution == 1)
			Print1(DumpFile,A);
		else
			Print2(DumpFile,A);
	}

	fprintf(DumpFile,"\n");
}


/*--------------------------------------------------------------------------*/
/*	Write a parameter line into dump file.									*/
/*--------------------------------------------------------------------------*/

static void WriteParamLine(FILE *DumpFile,char *Line)
{
	char *p = Line;
	long count = 0;

	while (*p++ > 31) count++;
	fwrite(Line,count,1,DumpFile);
	fprintf(DumpFile,"\n");
}

/*--------------------------------------------------------------------------*/
/*	Write a d-line into dump file.											*/
/*--------------------------------------------------------------------------*/

static void Write_d_line(FILE *DumpFile,StationPtr Station, Time_sec Time)
{
	char TimeStr[14];

	/* d-character, Station character,Components and time step */
	fprintf(DumpFile,"d%c%.6s%3d ",StationChar,ComponentStr,Station->TimeStep);

	/* Time */
	SecsToStr(Time,TimeStr);
	if (Time < YEAR2000)
		fprintf(DumpFile,"19");
	else
		fprintf(DumpFile,"20");

	fprintf(DumpFile,"%.2s %.2s %.2s %.2s %.2s %.2s",TimeStr,TimeStr+2,
				TimeStr+4,TimeStr+6,TimeStr+8,TimeStr+10);

	/* Field components */
	WriteXYZ(DumpFile,Station,Time);
}

/*--------------------------------------------------------------------------*/
/*	Here is the routine for writing data into a Dump-format file. This 		*/
/*	routine can only be used if the data to be written was previousle read	*/
/*	in from a dump-format file.												*/
/*--------------------------------------------------------------------------*/

long WriteDump(char *FileName,NetworkPtr Network)
{
	FILE	*DumpFile;				/* The data file to be processed		*/
	Time_sec Time;					/* Time of the current data block   	*/
	Time_sec StartTime;				/* Time of first record to be read		*/
	Time_sec EndTime;				/* Time of record not read anymore		*/
	StationPtr Station;				/* Pointer to the current station		*/
	long CurrParamLine = 0;			/* Number of current Parameter line		*/

	/* --- Check that there is some data in the Network --- */
	if (Network->StationList == NULL) return FAIL;

	/* --- Set the start and end times --- */
	Station   = Network->StationList;
	StartTime = Station->StartTime;
	EndTime   = Station->EndTime;

	/* --- Try to create the file --- */
	if ((FileName == NULL) || (*FileName == '\0')) DumpFile = stdout;
	else if ((DumpFile = fopen(FileName, "w")) == NULL) return FileError;

	/* --- Write the dump file --- */
	Time = StartTime;
	while (Time < EndTime) {

		/* Write the Parameter lines */
		while ((CurrParamLine < ParamLineCount) && (ParamLineTime[CurrParamLine] <= Time))
			WriteParamLine(DumpFile,ParamLine[CurrParamLine++]);

		/* Write a d-line */
		Write_d_line(DumpFile,Station,Time);

		Time += Station->TimeStep;
	}

	fclose(DumpFile);

	return OK;
}

