/****************************************************************************/
/*                                                                          */
/*                              IAGA_merge.c                                */
/*                                                                          */
/****************************************************************************/
/****************************************************************************/
/* This program merges two IAGA-format files into a single IAGA file.       */
/* The ordering of stations in the resulting file is controlled by an       */
/* optional parameter.                                                      */
/*                                                                          */
/* Usage:                                                                   */
/*    IAGA_merge [-o] IAGAFile1 ... IAGAFileN > NewIAGAFile                 */
/*      [-o StationList]    Defines how the stations are ordered in the     */
/*                          final data file. e.g. 'SOR MAS KEV'.            */
/*                          Don't include stations which are not mentioned. */
/*                          If missing then stations from IAGAFile1 are     */
/*                          written first, stations from IAGAFileN last     */
/*                          If data for some station appears in more than   */
/*                          one file then data from the first encountered   */
/*                          file will be written, the rest are neglected.   */
/*      IAGAFile1           Name of first IAGA-format file.                 */
/*      IAGAFileN           Name of last IAGA-format file.                  */
/*      NewIAGAFile         Name of new IAGA-format file.                   */
/*                                                                          */
/* Here the files IAGAFile1 ... IAGAFileN must contain data for exactly the */
/* same times.                                                              */
/****************************************************************************/
/****************************************************************************/
/*                            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.05        08.09.2000                      */
/****************************************************************************/
/****************************************************************************/
/*  Version history:                                                        */
/*                                                                          */
/*  1.05 08.09.2000 Modified the program so that also the case where only   */
/*                  one input file is given is legal. In this case the data */
/*                  is simply copied.                                       */
/*                  incorrect year in date strings if year >= 2000.         */
/*  1.04 09.09.1999 Fixed a Y2K bug in NewTime.h file which resulted in     */
/*                  incorrect year in date strings if year >= 2000.         */
/*  1.03 28.5.1999                                                          */
/*      - Allowed the possibility that data for some station exists in more */
/*        than one file.                                                    */
/*  1.02 26.5.1999                                                          */
/*      - Increased the length of StationStr to 255 in order to eliminate   */
/*        possible overflows if full pathnames are used.                    */
/*  1.01 26.2.1996                                                          */
/*      - Added the possibility to merge more than two files.               */
/*      - Cosmetic change in handling the usage text.                       */
/*                                                                          */
/*  1.0  10.10.1995 First official release                                  */
/****************************************************************************/

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

#define OK   0              /* Return value for successfull completion      */
#define FAIL 1              /* Return value for failed operation            */
#define MaxFileCount 32     /* Maximum number of IAGA files to be merged    */
#define MaxStationCount 1000 /* Maximum total count of stations in IAGA files*/

char *version = "1.05";
char *date = "08.09.2000";

#define HeaderLineCount 6
#define UsageLineCount  9

long IAGABlockSize;             /* Size of IAGA block = 1440, 1441 or 1442  */


char *HeaderText[HeaderLineCount] = {
"**************************************************************************",
"This program merges two or more IAGA format files into a single IAGA file.",
"All files must contain data for the same time interval. If data for some  ",
"station exists in more than one file then data from the first encountered ",
"file will be written.                                                     ",
"**************************************************************************",
};

char *UsageText[UsageLineCount] = {
" [-o] IAGAFile1 ... IAGAFileN > NewIAGAFile",
"      [-o StationList]     Defines how the stations are ordered in the    ",
"                           final data file. e.g. 'SOR MAS KEV'.           ",
"                           Don't include stations which are not mentioned.",
"                           If missing then stations from IAGAFile1 are    ",
"                           written first, stations from IAGAFileN last.   ",
"      IAGAFile1            Name of first IAGA-format file.                ",
"      IAGAFileN            Name of last IAGA-format file.                 ",
"      NewIAGAFile          Name of new IAGA-format file.                  ",
};


/*--------------------------------------------------------------------------*/
/*  Check if the IAGA block contains newlines or carriage returns.          */
/*--------------------------------------------------------------------------*/

long GetIAGABlockSize(FILE *FilePtr)
{
    long Size = 1440;
    char Buffer[1442];              /* Buffer for reading one IAGA block    */

    fread(Buffer,1442,1,FilePtr);   /* Read the first block and little more */
    if (Buffer[1441] < '0') Size = 1442;
    else if (Buffer[1440] < '0') Size = 1441;
    
    rewind(FilePtr);
    return (Size);
}

/*--------------------------------------------------------------------------*/
/*  Count the number of stations in the file FilePtr.                       */
/*--------------------------------------------------------------------------*/

long GetStationCount(FILE *FilePtr)
{
    long Count;
    char Station[4];                /* Name of the first station            */
    char Buffer[1442];              /* Buffer for reading one IAGA block    */
    
    fread(Buffer,IAGABlockSize,1,FilePtr);      /* Read the first block     */
    strncpy(Station,Buffer+12,3);               /* Set the station ID       */
    Station[3] = '\0';

    Count = 0;
    do {
        Count++;
        fread(Buffer,IAGABlockSize,1,FilePtr);
    } while (strncmp(Station,Buffer+12,3));

    rewind(FilePtr);
    return (Count);
}


/*--------------------------------------------------------------------------*/
/*  Read one IAGA block from given file.                                    */
/*--------------------------------------------------------------------------*/

long ReadBlock(FILE *FilePtr,char *Buffer)
{
    long count;
    
    count = fread(Buffer,IAGABlockSize,1,FilePtr);
    if (count == 0) return (0); else return (1);
}

/*--------------------------------------------------------------------------*/
/*  Write one IAGA block into stdout.                                       */
/*--------------------------------------------------------------------------*/

long WriteBlock(char *Buffer)
{
    return(fwrite(Buffer,IAGABlockSize,1,stdout));
}

/*--------------------------------------------------------------------------*/
/*                          The main procedure                              */
/*--------------------------------------------------------------------------*/

int main(int argc, char *argv[])
{
    long    i,j;                        /* Dummy indices                    */
    long    params;
    long    BlockNbr;
    long    status;
    long    FileCount = 0;              /* Number of IAGA files             */
    long    StationCount[MaxFileCount]; /* Number of stations in IAGA files */
    long    TotalStationCount;          /* Total number of stations         */
    long    written;                    /* Flag to indicate multiple        */
                                        /* occurrences of the same station  */
    char    StationStr[255] = "";       /* List of stations                 */
    char    *Block[MaxStationCount];    /* Pointers to IAGA data blocks     */
    char    *FileName[MaxFileCount];    /* Names of the data files          */
    FILE    *IAGAFile[MaxFileCount];    /* File pointers to IAGA files      */


    /*==========================*/
    /* Analyse the command line */
    /*==========================*/

    if (argc == 1) {        /* No arguments, show the usage text */
        PrintUsage(argv[0],0,HeaderLineCount,UsageLineCount);
        return OK;
    }

    for (params = 1; params < argc; params++) {
        if (*argv[params] != '-') {
            FileName[FileCount++] = argv[params];
        } else {
            switch (*(argv[params]+1)) {
                case 'o' : strcpy(StationStr,argv[++params]);   break;
                default  :
                    fprintf(stderr,"\n### %s: \"%s\" is not an option.\n\n",
                            argv[0], argv[params]);
                    PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);
                    return FAIL;
                    break;
            }
        }
    }

    /*====================================*/
    /* Check the values of the parameters */
    /*====================================*/
    
    if (FileCount < 1) {
        PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);
        return FAIL;
    }
    if (FileCount > MaxFileCount) {
        fprintf(stderr,"###  Too many files : %d\n",FileCount);
        fprintf(stderr,"###  Maximum allowed: %d\n",MaxFileCount);
        return FAIL;
    }
    
    /*============================*/
    /* Try to open all the files. */
    /*============================*/
    
    for (i=0;i<FileCount;i++) {
        if ((IAGAFile[i] = fopen(FileName[i], "r")) == NULL) {
            fprintf(stderr,"###  Unable to open file: %s\n",FileName[i]);
            return FAIL;
        }
    }

    /*==========================================*/
    /* Get the number of stations in data files */
    /*==========================================*/
    
    IAGABlockSize = GetIAGABlockSize(IAGAFile[0]);  /* Assume block size is */
                                                    /* same for all files.  */
    TotalStationCount = 0;
    for (i=0;i<FileCount;i++) {
        StationCount[i] = GetStationCount(IAGAFile[i]);
        TotalStationCount += StationCount[i];
    }
    
    if (TotalStationCount > MaxStationCount) {
        fprintf(stderr,"###  Too many stations : %d\n",TotalStationCount);
        fprintf(stderr,"###  Maximum allowed   : %d\n",MaxStationCount);    
        return FAIL;
    }


    /*==========================================*/
    /* Allocate one IAGA block for each station */
    /*==========================================*/
    
    for (i=0;i<TotalStationCount;i++)
        Block[i] = malloc(IAGABlockSize);


    /*=================================================*/
    /* Read data blocks and write them in proper order */
    /*=================================================*/

    while (ReadBlock(IAGAFile[0],Block[0])) {
        BlockNbr = 1;
        for (i=1;i<StationCount[0];i++)     /* First file */
            ReadBlock(IAGAFile[0],Block[BlockNbr++]);
        for (j=1;j<FileCount;j++) {         /* Rest of the files */
            for (i=0;i<StationCount[j];i++)
                ReadBlock(IAGAFile[j],Block[BlockNbr++]);
        }

        /* === Case 1: File1, File2, ... , FileN === */
        if (strlen(StationStr) == 0) {
            for (i=0;i<TotalStationCount;i++) {
                written = 0;
                for (j=0;j<i;j++) {     /* Check if this station has already been written */
                    if (strncmp(Block[i]+12,Block[j]+12,3) == 0) written = 1;
                }
                if (written == 0) { /* Data not yet written */
                    status = WriteBlock(Block[i]);
                    if (status == 0) {
                        fprintf(stderr,"###  Cannot write data to stdout. Disk full ?? \n");
                        return FAIL;
                    }
                }
            }
        }

        /* === Case 2: Include stations from the StationStr === */
        if (strlen(StationStr) > 0) {
            for (i=0;i<strlen(StationStr);i += 4) { /* Go through StationStr */
                for (j=0;j<TotalStationCount;j++) {
                    if (strncmp(StationStr+i,Block[j]+12,3) == 0) {
                        status = WriteBlock(Block[j]);
                        if (status == 0) {
                            fprintf(stderr,"###  Cannot write data to stdout. Disk full ?? \n");
                            return FAIL;
                        }
                        break;      /* Station found, so exit from the loop */
                    }
                }
            }
        }
    }

    for (i=0;i<FileCount;i++) 
        fclose(IAGAFile[i]);
    return OK;
}

