/****************************************************************************/
/*																			*/
/*									IAGA.h									*/
/*																			*/
/****************************************************************************/
/****************************************************************************/
/* This is a C language header file that defines the following routines		*/
/* for reading IAGA format data files into memory and writing data from		*/
/* memory into IAGA-format data files. The description of IAGA format is	*/
/* given in file 'IAGA.doc'.												*/
/*																			*/
/*	-------------------  Read data from a IAGA-format file	--------------	*/
/*																			*/
/* long ReadIAGA(char *FileName,NetworkPtr Network,char *StartTimeStr,		*/
/*				 char *EndTimeStr,char *StationList)						*/
/*		FileName		Name of the IAGA-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 IAGA file			*/
/*																			*/
/*	-------------------  Write data into a IAGA-format file	--------------  */
/*																			*/
/* long WriteIAGA(char *FileName,NetworkPtr Network,char *StartTimeStr,		*/
/*				  char *EndTimeStr,char *StationList)						*/
/* 		FileName		Name of the IAGA 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 stations	*/
/*						to be included. If NULL or 0-length then all		*/
/*						stations will be written. The stations must be		*/
/*						separated by a	space in the list (e.g. 'SOR KEV').	*/
/*																			*/
/*	The function result indicates how successfull the file writing was:		*/
/*				0: OK			: Data written successfully					*/
/*				1: FileError	: Failed to create the given file			*/
/*																			*/
/****************************************************************************/
/****************************************************************************/
/*                            Lasse Hakkinen                                */
/*                    Finnish Meteorological Institute                      */
/*                        Geophysical Research Division                     */
/*                              P.O.Box 503                                 */
/*                      FIN-00101, Helsinki, Finland                        */
/*                      e-mail: Lasse.Hakkinen@fmi.fi                       */
/*                      phone : (+358)-9-19294634                           */
/*                      fax   : (+358)-9-19294603                           */
/*																			*/
/*						version 1.09		22.01.2001						*/
/****************************************************************************/
/****************************************************************************/
/*	Version history:														*/
/*																			*/
/*	1.10 12.05.2005	Fixed a bug in Reading an IAGA file in the case that    */
/*					there were missing data blocks in the IAGA file.		*/
/*	1.09 22.01.2001	Modified the computation of hourly averages so that if  */
/*					one or more data points are missing then the whole hour */
/*					average is marked as missing.							*/
/*	1.08 04.05.2000	Fixed a bug in WriteIAGA which caused the field values  */
/*					to be written with more that 6 characters if the field  */
/*					value was larger than 999999.							*/
/*	1.07 08.03.2000	Added function Get5chars. This fixed a bug where the	*/
/*					latitude of the station was incorrectly read if the		*/
/*					longitude was more than 100 degrees (= all 5 chars)		*/
/*	1.06 20.10.1998	Slight change how missing data points are handled		*/
/*					internally. Defined the IAGAMissingValue constant		*/
/*					(!= MissingValue defined in MagnData.h.					*/
/*	1.05 16.10.1998 Fixed a bug where some data was not read in if			*/
/*					StartTime was not exactly the same as IAGA block start	*/
/*					time.													*/
/*	1.04 09.11.1996 Fixed a bug which caused WriteIAGA to crash if the		*/
/*					StartTime or EndTime were not aligned along suitable	*/
/*					minute boundaries.										*/
/*	1.03 11.09.1996 Fixed a bug where Temperature values where incorrectly	*/
/*					written if Temp > 999 or Temp < -999 (physically		*/
/*					unrealistic).											*/
/*  1.02 27.07.1996 Fixed a bug where WriteIAGA crashed is there is no data	*/
/*					in the Network-structure								*/
/*	1.01 19.02.1996 Added WriteIAGABlock routine							*/
/*	1.0  13.11.1995	First official release									*/
/****************************************************************************/

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

/*--------------------------------------------------------------------------*/
/* Define the offsets of various fields from the start of the IAGA block	*/
/* See the definition of IAGA record for the explanation of various fields.	*/
/*--------------------------------------------------------------------------*/

#define IAGA_RecLength		 0
#define IAGA_RecLenMin		 4
#define IAGA_Datatype		 7
#define IAGA_StationNbr		 9
#define IAGA_StationID		12
#define IAGA_Latitude		15
#define IAGA_Longitude		20
#define IAGA_Free1			25
#define IAGA_DateCentury	48
#define IAGA_DateYear		50
#define IAGA_DateMonth		52
#define IAGA_DateDay		54
#define IAGA_DateHour		56
#define IAGA_DateMinute		58
#define IAGA_SampleStep		60
#define IAGA_HowProduced	62
#define IAGA_FilterBreak	63
#define IAGA_FilterSlope	67
#define IAGA_BaselineInfo	69
#define IAGA_BaselineChange	70
#define IAGA_Components		72
#define IAGA_DayCharacter	73
#define IAGA_Free2			74
#define IAGA_Temperature	74
#define IAGA_Data		   159
#define IAGA_DataAverage  1419

#define IAGAMissingValue  999999

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

Time_sec GetIAGATime(char *Buffer);
static long GetIAGAStep(char *Buffer);
int ReadIAGABlock(FILE *IAGAfile,char *Buff);
static long Get5chars(char *p);
static void SetStationParamsIAGA(StationPtr Station,char *Buff);
long GetIAGAFieldValue(char *p);
static long GetIAGATempValue(char *Buff);
static void GetIAGAData(StationPtr Station, char *Buff);
long ReadIAGA(char *FileName,NetworkPtr Network,char *StartTimeStr,
			  char *EndTimeStr,char *StationList);

void WriteIAGABlock(FILE *DataFile,char *Buffer);
static void WriteIAGAdata(FILE *DataFile,StationPtr Station,Time_sec Time);
static void WriteIAGAaverages(FILE *DataFile,
							  StationPtr Station,Time_sec Time);
long WriteIAGA(char *FileName,NetworkPtr Network,char *StartTimeStr,
			  char *EndTimeStr,char *StationList);



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


/*--------------------------------------------------------------------------*/
/*	Get the start time in seconds of a 1440-character data block. In the	*/
/*  IAGA file the date is in format YYMMDDHHMM.								*/
/*--------------------------------------------------------------------------*/

Time_sec GetIAGATime(char *Buffer)
{
	return (StrToSecs(Buffer+IAGA_DateYear,10));
}


/*--------------------------------------------------------------------------*/
/* Get the 2 character sample step value from the buffer.					*/
/*--------------------------------------------------------------------------*/

static long GetIAGAStep(char *Buffer)
{
	char *q = Buffer+IAGA_SampleStep;
	
	return (10*(*q-48)+(*(q+1)-48));
}


/*--------------------------------------------------------------------------*/
/* Read one block from the IAGA-format file into the Buffer. This routine	*/
/* works also for 1441-character blocks (i.e. terminated with linefeeds).	*/
/* The routine will return 1 if the block was succesfully read, otherwise	*/
/* 0 is returned.															*/
/*--------------------------------------------------------------------------*/

int ReadIAGABlock(FILE *IAGAfile,char *Buff)
{
	int c;
	
	/* Handle the first character */
	if ((c = getc(IAGAfile)) == EOF) return(0);
	if (c < 32) {	/* Linefeed or carriage return */
		if ((c = getc(IAGAfile)) == EOF) return(0);
	}
	
	*Buff = c;		/* Put the first char into Buffer */
	
	/* read the rest of the block */
	return(fread(Buff+1,1439,1,IAGAfile));
}

/*--------------------------------------------------------------------------*/
/* Get the 5 character long from a Buffer.									*/
/*--------------------------------------------------------------------------*/

static long Get5chars(char *p)
{
	int k;
	long value = 0;
	long negative = 0;
	
	if (*p == '-')
		negative = 1;
	else
		if (*p != ' ') value = *p-'0'; 
	p++;

	/* Get the rest 4 characters */
	for (k=0;k<4;k++) {
		if (*p != ' ') value = 10*value+(*p-'0');
		p++;
	}
	if (negative) value = -value;

	return (value);
}


/*--------------------------------------------------------------------------*/
/*	Fill some fields in the Station_struct by copying them from the IAGA	*/
/*	buffer. AddNewStation procedure in the MagnData.h file will set other	*/
/*	station parameters.														*/
/*--------------------------------------------------------------------------*/

static void SetStationParamsIAGA(StationPtr Station,char *Buff)
{
	/* Set the station ID */
	strncpy(Station->StationID,Buff+IAGA_StationID,3);
	Station->StationID[3] = '\0';
	
	/* Set the location of the station */
	Station->Latitude  = Get5chars(Buff+IAGA_Latitude);
	Station->Longitude = Get5chars(Buff+IAGA_Longitude);

	/* Set the StartTime and TimeStep, GetIAGAData-routine will set EndTime */
	Station->StartTime = GetIAGATime(Buff);
	Station->TimeStep  = GetIAGAStep(Buff);
	Station->EndTime   = Station->StartTime;

	/* Set the component markers */
	if (*(Buff+IAGA_Components) == '1') strcpy(Station->Components,"XYZ");
	if (*(Buff+IAGA_Components) == '2') strcpy(Station->Components,"HDZ");
}


/*--------------------------------------------------------------------------*/
/* Get the 1+6 character number from the Buffer. We could also use sscanf,	*/
/* but this is considerably faster because no checkings are made.			*/
/*--------------------------------------------------------------------------*/

long GetIAGAFieldValue(char *p)
{
	int k;
	long value = 0;
	long negative;
	
	negative = (*p++ == '-');
		
	/* Get the 6-characters */
	for (k=0;k<6;k++) {
		if (*p != ' ') value = 10*value+(*p-'0');
		p++;
	}
	if (negative) value = -value;
	if (value == IAGAMissingValue)
		return (MissingValue);
	else
		return (value);
}


/*--------------------------------------------------------------------------*/
/* Get the 1+3 character temperature value from the buffer.	The temperature	*/
/* value is stored in the free-area starting from byte 74 in the buffer.	*/
/* Unit of temperature is 0.1 degrees centigrade.							*/
/*--------------------------------------------------------------------------*/

static long GetIAGATempValue(char *Buff)
{
	char *q = Buff+IAGA_Temperature+1;	/* first digit after sign */
	long k  = 0;
	long i;
	
	if (*(Buff+IAGA_Temperature+3) == ' ')	/* If last digit is missing		*/
		return (MissingValue);				/* then whole value is missing	*/
	
	for (i=0;i<3;i++) k = 10*k+(*q++)-'0';
	if (k == 999) return (MissingValue);
	if (*(Buff+74) == '-') return (-k); else return (k);
}


/*--------------------------------------------------------------------------*/
/* Copy the data from the 1440 character block into the proper OneDayBlock.	*/
/*--------------------------------------------------------------------------*/

static void GetIAGAData(StationPtr Station, char *Buff)
{
	OneDay_struct *p;
	long *XPtr,*YPtr,*ZPtr,*TPtr;
	long i;
	char *q;
	
	/* Find the last OneDayBlock */
	for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay);
	
	/* Set the temperature value */
	TPtr  = (p->T)+(p->TCount);
	*TPtr = GetIAGATempValue(Buff);
	p->TCount++;

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

	/* Copy the data */
	q = Buff+IAGA_Data;
	for (i=0;i<60;i++) {
		*XPtr++ = GetIAGAFieldValue(q); q += 7;
		*YPtr++ = GetIAGAFieldValue(q); q += 7;
		*ZPtr++ = GetIAGAFieldValue(q); q += 7;
	}
	p->XCount += 60;
	p->YCount += 60;
	p->ZCount += 60;
	
	/* Set the last time */
	Station->EndTime = GetIAGATime(Buff)+60*Station->TimeStep;
}

/*--------------------------------------------------------------------------*/
/* Add missing data block 													*/
/*--------------------------------------------------------------------------*/

static void AddMissingBlock(StationPtr Station)
{
	OneDay_struct *p;
	
	/* Find the last OneDayBlock */
	for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay);
	
	/* We only have to update counters since the data areas are already */
	/* initialized with missing data									*/
	p->XCount += 60;
	p->YCount += 60;
	p->ZCount += 60;
	p->TCount +=  1;
}


/*--------------------------------------------------------------------------*/
/*	Here is the routine for reading IAGA-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 block (1440 bytes) at a	*/
/*	time and adds that data in the particular stations data block. First	*/
/*	for each new station that is encountered space for one day is allocated.*/
/*	If the day 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 ReadIAGA(char *FileName,NetworkPtr Network,char *StartTimeStr,
			  char *EndTimeStr,char *StationList)
{
	FILE	*IAGAfile;				/* The data file to be processed		*/
	char	Buffer[1440];			/* Buffer for one IAGA data block		*/
	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		*/
	Time_sec CurrTime;				/* Time of previous data block			*/
	Time_sec TimeStep;				/* Sampling rate in seconds				*/
	StationPtr Station;				/* Pointer to the current station		*/


	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 open the file --- */
	if ((FileName == NULL) || (*FileName == '\0')) IAGAfile = stdin;
	else if ((IAGAfile = fopen(FileName, "r")) == NULL) return FileError;

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

	while (ReadIAGABlock(IAGAfile,Buffer))
	{
		if (strncmp(Buffer,"144",3) != 0)	/* Check that this is IAGA file */
			return(FileFormatError);

		if ((Time = GetIAGATime(Buffer)) >= EndTime) break;
		
		TimeStep = GetIAGAStep(Buffer);
		
		if (((Time+60*TimeStep) > StartTime)
			&& StationInList(Buffer+IAGA_StationID,StationList))
		{
			Station = FindStation(Network,Buffer+IAGA_StationID);

			if (Station == NULL) {		/* First occurrence of this station */
				Station = AddNewStation(Network,TimeStep,60*TimeStep);
				if (Station != NULL)
					SetStationParamsIAGA(Station,Buffer);
				else		/* Unable to allocate memory for station data	*/
					return(OutOfMemory);
			}

			/* --- Add possible missing data blocks ---                */
			/* CurrTime is the expected time of the current data block.*/
			/* If it is less than the time read from the block then    */
			/* add missing data blocks                                 */

			CurrTime = Station->EndTime;
			while (CurrTime < Time) {
				AddMissingBlock(Station);
				if (OneDayFull(Station,'Z')) {
					if (AddOneDay(Station))
						return(OutOfMemory);
				}
				CurrTime += 60*TimeStep;
			}
		
			if (OneDayFull(Station,'Z')) {
				if (AddOneDay(Station))
					return(OutOfMemory); 	   /* Failed to allocate memory */
			}
			GetIAGAData(Station,Buffer);
		}
	}
	fclose(IAGAfile);

	/* --- Combine one day blocks into one large block ---*/
	Station = Network->StationList;
	while (Station != NULL) {
		if (CombineData(Station) == OutOfMemory) return(OutOfMemory);
		Station = Station->Next;
	}

	return OK;
}


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


/*--------------------------------------------------------------------------*/
/*	Write one 1440 character block into standard output						*/
/*--------------------------------------------------------------------------*/

void WriteIAGABlock(FILE *DataFile,char *Buffer)
{
	fwrite(Buffer,1440,1,DataFile);
}


/*--------------------------------------------------------------------------*/
/*	Compute an average over speficied time period for specified station,	*/
/*	component and time.	If one or more data points are missing then the		*/
/*  average is marked as missing.											*/
/*--------------------------------------------------------------------------*/

long ComputeHourAverage(StationPtr Station,char Comp,Time_sec Time,long Length)
{
	double Sum = 0;	/* we must use double as long might overflow */
	long Good = 0;
	long i,Count,Value;

	if (Length == 0)
		Count = 1;	/* Average is same as a single data value */
	else
		Count = Length/Station->TimeStep;

	for (i=0;i<Count;i++) {
		Value = GetDataValue(Station,Time,Comp);
		if (Value == MissingValue) return (MissingValue);
		Sum += (double) Value;
		Good++;
		Time += Station->TimeStep;
	}
	return RoundFloat(Sum/Good);
}


/*--------------------------------------------------------------------------*/
/*	Write one 1440 character block for given station and for given time		*/
/*	into specified datafile. All 1440 characters except the hour averages	*/
/*	are written (WriteAverages routine does that).							*/
/*--------------------------------------------------------------------------*/

static void WriteIAGAdata(FILE *DataFile,StationPtr Station,Time_sec Time)
{
	long j,Temperature;
	long X,Y,Z;
	StationInfoPtr p;
	char DummyStr[14];
	
	
	/*** Find pointer to proper StationInfoStruct in StationInfoTable	***/
	/*** defined in header file 'StatInfo.h'							***/

	p = FindStationInfo(Station->StationID);

	/*** Fill out some fields with station info  ***/
	fprintf(DataFile,"1440%03d%s%s%s",Station->TimeStep,
		p->DataType,p->StationNum,Station->StationID);
	fprintf(DataFile,"% 05d%5d",Station->Latitude,Station->Longitude);
	fprintf(DataFile,"                       ");	/* 23 spaces */
	if (Time < YEAR2000) fprintf(DataFile,"19"); else fprintf(DataFile,"20");
	SecsToStr(Time,DummyStr);
	fprintf(DataFile,"%.10s%02d",DummyStr,Station->TimeStep);
	fprintf(DataFile,"%s%s%s",p->ProdType,p->FilterBreak,p->FilterSlope);
	fprintf(DataFile,"%s%s",p->BaseInfo,p->BaseChange);
	if (Station->Components[0] == 'X') fprintf(DataFile,"1");
	else if (Station->Components[0] == 'H') fprintf(DataFile,"2");
	fprintf(DataFile,"%s",p->DayCharacter);
	
	/*** Write temperature value  ***/
	Temperature = GetDataValue(Station,Time,'T');
	if ((Temperature != MissingValue) &&
		(Temperature < 999) && (Temperature > -999)) {
		fprintf(DataFile,"% 04d",Temperature);
		}
	else fprintf(DataFile,"    ");

	/*** Some empty space for comments etc.  ***/
	for (j=0;j<3;j++)	/* 81 = 3*27 spaces	*/
		fprintf(DataFile,"                           ");
	
	/*** Write magnetometer data ***/
	for (j=0;j<60;j++) {
		X = GetDataValue(Station,Time,'X');
		Y = GetDataValue(Station,Time,'Y');
		Z = GetDataValue(Station,Time,'Z');
		if ((X == MissingValue) || (abs(X) > IAGAMissingValue)) X = IAGAMissingValue;
		if ((Y == MissingValue) || (abs(Y) > IAGAMissingValue)) Y = IAGAMissingValue;
		if ((Z == MissingValue) || (abs(Z) > IAGAMissingValue)) Z = IAGAMissingValue;
		fprintf(DataFile,"% 07d% 07d% 07d",X,Y,Z);
		Time += Station->TimeStep;
	}
}


/*--------------------------------------------------------------------------*/
/*	Write hour averages														*/
/*--------------------------------------------------------------------------*/

static void WriteIAGAaverages(FILE *DataFile,StationPtr Stat,Time_sec Time)
{
	Time_sec	LastTime;		/* Time of last record in the block+Step */
	Time_struct TmTime;
	long AveX,AveY,AveZ;

	LastTime = Time+60*Stat->TimeStep;
	SecsToTm(LastTime,&TmTime);
	if (TmTime.tm_min == 0)	{	/* The last block of hour ? */
		AveX = ComputeHourAverage(Stat,'X',LastTime-3600,3600);
		AveY = ComputeHourAverage(Stat,'Y',LastTime-3600,3600);
		AveZ = ComputeHourAverage(Stat,'Z',LastTime-3600,3600);
		if ((AveX == MissingValue) || (abs(AveX) > IAGAMissingValue)) AveX = IAGAMissingValue;
		if ((AveY == MissingValue) || (abs(AveY) > IAGAMissingValue)) AveY = IAGAMissingValue;
		if ((AveZ == MissingValue) || (abs(AveZ) > IAGAMissingValue)) AveZ = IAGAMissingValue;
		fprintf(DataFile,"% 07d",AveX);
		fprintf(DataFile,"% 07d",AveY);
		fprintf(DataFile,"% 07d",AveZ);
	}
	else fprintf(DataFile," 000000 000000 000000");
}


/*--------------------------------------------------------------------------*/
/*	Here is the routine for writing data into an IAGA-format file. See the	*/
/*	comments at the beginning of this file for more details about the 		*/
/*	parameters for this routine.											*/
/*--------------------------------------------------------------------------*/

long WriteIAGA(char *FileName,NetworkPtr Network,char *StartTimeStr,
			  char *EndTimeStr,char *StationList)
{
	FILE	*IAGAfile;				/* 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		*/
	Time_sec IAGABlockLength;		/* Length of one IAGA block in seconds	*/
	StationPtr Station;				/* Pointer to the current station		*/
	
	/* --- Check there is some data in the Network --- */
	if (Network->StationList == NULL) return FAIL;
	
	/* --- Set the start and end times --- */
	if ((StartTimeStr == NULL) || (*StartTimeStr == '\0'))
		StartTime = Network->StationList[0].StartTime;
	else StartTime = StrToSecs(StartTimeStr,0);

	if ((EndTimeStr == NULL) || (*EndTimeStr == '\0'))
		EndTime = Network->StationList[0].EndTime;
	else EndTime = StrToSecs(EndTimeStr,0);

	/* --- Try to create the file --- */
	if ((FileName == NULL) || (*FileName == '\0')) IAGAfile = stdout;
	else if ((IAGAfile = fopen(FileName, "w")) == NULL) return FileError;
	
	/* Set StartTime and EndTime so that IAGA blocks will */
	/* start or end at suitable minute boundaries		  */
	
	IAGABlockLength = 60*(Network->StationList[0].TimeStep);
	StartTime -= StartTime % IAGABlockLength;
	if ((EndTime % IAGABlockLength) != 0)
		EndTime += IAGABlockLength-(EndTime % IAGABlockLength);

	/* --- Write the data ---*/
	Time = StartTime;
	while (Time < EndTime) {
		Station = Network->StationList;
		while (Station != NULL) {
			if (StationInList(Station->StationID,StationList)) {
				WriteIAGAdata(IAGAfile,Station,Time);
				WriteIAGAaverages(IAGAfile,Station,Time);
			}
			Station = Station->Next;
		}
		Time += IAGABlockLength;
	}
	fclose(IAGAfile);

	return OK;
}

