/****************************************************************************/
/*                                                                          */
/*                              Find_missing.c                              */
/*                                                                          */
/****************************************************************************/
/****************************************************************************/
/* This program reads IAGA, GADF, Dump or WDC format data files containing  */
/* magnetometer data, searches for missing data values and writes the       */
/* missing periods into standard output                                     */
/*                                                                          */
/* Usage:                                                                   */
/*    Find_missing [-f] [-v] File1 ... FileN                                */
/*      [-v ]               Verbose. Write information about file content.  */
/*      [-f Dataformat]     Format of the data file. Possible values for    */
/*                          Dataformat are IAGA (default),GADF,Dump or WDC. */
/*         File*            Names of data files.                            */
/*                                                                          */
/****************************************************************************/
/****************************************************************************/
/*                            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.02        02.07.1999                      */
/****************************************************************************/
/****************************************************************************/
/*  Version history:                                                        */
/*                                                                          */
/*  1.02 02.07.1999 Fixed a Y2K bug in NewTime.h file which resulted in     */
/*                  incorrect year in date strings if year >= 2000.         */
/*  1.01 21.10.1998 Accommodated to the changes in Dump.h (0.1 nT to        */
/*                  0.01 nT resolution).                                    */
/*  1.0  20.01.1997 First official release                                  */
/****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Usage.h"
#include "MagnData.h"
#include "IAGA.h"
#include "GADF.h"
#include "WDC.h"
#include "Dump.h"

char *version = "1.02";
char *date = "02.07.1999";

#define HeaderLineCount 4
#define UsageLineCount  6

char *HeaderText[HeaderLineCount] = {
"**************************************************************************",
"This program finds missing data records in magnetometer data files and    ",
"writes times of data gaps into standard output.                           ",
"**************************************************************************",
};

char *UsageText[UsageLineCount] = {
" [-v] [-f] File1 ... FileN                                                 ",
"       [-v ]               Verbose. Write information about data content.  ",
"                           If missing then only gaps are written.          ",
"       [-f Dataformat]     Format of the data file. Possible values for    ",
"                           Dataformat are IAGA (default),GADF,Dump or WDC. ",
"      File*                Names of data files.",
};


/*--------------------------------------------------------------------------*/
/*  Define a data structure for storing information about each data gap.    */
/*--------------------------------------------------------------------------*/

#define MaxGapCount 1000

struct Data_Gap {
    char        Comp[4];        /* Components missing for this interval     */
    Time_sec    StartTime;      /* First missing data point                 */
    Time_sec    EndTime;        /* Last missing data point                  */
};

typedef struct Data_Gap Data_Gap_struct;

long    GapCount;
Data_Gap_struct GapTable[MaxGapCount];



/*--------------------------------------------------------------------------*/
/*  Add the gap for given component and given times into the GapTable.      */
/*  First check if this gap already exists for some other component. If so  */
/*  then update the particular element in the GapTable otherwise add a new  */
/*  element to the GapTable.                                                */
/*--------------------------------------------------------------------------*/

void AddGapToTable(char Component,Time_sec GapStart, Time_sec GapEnd)
{
    long i = 0;
    
    /*** First check if this gap already exists in some other component ***/
    while (i < GapCount) {
        if ((GapTable[i].StartTime == GapStart) && 
            (GapTable[i].EndTime == GapEnd)) {  /* Yes, we have it already */
                GapTable[i].Comp[Component-'X'] = Component;
            return;
        }
        i++;
    }
    
    /*** We haven't recorded this gap, so add it to the GapTable ***/
    GapTable[GapCount].StartTime = GapStart;
    GapTable[GapCount].EndTime   = GapEnd;
    GapTable[GapCount].Comp[Component-'X'] = Component;
    GapCount++;
}

/*--------------------------------------------------------------------------*/
/*  Exchange the i'th and j'th element of the GapTable.                     */
/*--------------------------------------------------------------------------*/

void Exchange(long i, long j)
{
    char dummyStr[4];
    Time_sec t1,t2;
    
    strcpy(dummyStr,GapTable[i].Comp);
    t1 = GapTable[i].StartTime;
    t2 = GapTable[i].EndTime;
    
    strcpy(GapTable[i].Comp,GapTable[j].Comp);
    GapTable[i].StartTime = GapTable[j].StartTime;
    GapTable[i].EndTime = GapTable[j].EndTime;
    
    strcpy(GapTable[j].Comp,dummyStr);
    GapTable[j].StartTime = t1;
    GapTable[j].EndTime   = t2;
}


/*--------------------------------------------------------------------------*/
/*  Put the elements of GapTable into temporal order according to StartTime.*/
/*  Here we use a very simple algorithm for sorting the table.              */
/*--------------------------------------------------------------------------*/

void TimeOrderGapTable()
{
    long i,j;
    
    for (i=0;i<GapCount-1;i++) 
        for (j=i+1;j<GapCount;j++)
            if (GapTable[i].StartTime > GapTable[j].StartTime)
                Exchange(i,j);
}


/*--------------------------------------------------------------------------*/
/*  Write the elements of GapTable into standard output.                    */
/*--------------------------------------------------------------------------*/

void WriteGapTable(StationPtr Station)
{
    long i;
    char StartStr[20];
    char EndStr[20];
    Time_sec GapLength;
    long GapDays,GapHours,GapMins,GapSecs;
    
    for (i=0;i<GapCount;i++) {
        SecsToStr(GapTable[i].StartTime,StartStr);
        SecsToStr(GapTable[i].EndTime,EndStr);
        GapLength = GapTable[i].EndTime - GapTable[i].StartTime;
        GapDays  = GapLength/86400;
        GapHours = (GapLength % 86400)/3600;
        GapMins  = (GapLength % 3600)/60;
        GapSecs  = GapLength % 60;
        printf("  %s %s   %.6s %s - %.6s %s   ",Station->StationID,
                GapTable[i].Comp,StartStr,StartStr+6,EndStr,EndStr+6);
        if (GapDays > 0) printf("%02dd ",GapDays);
        else printf("    ");
        if (GapHours > 0) printf("%02dh ",GapHours);
        else printf("    ");
        if (GapMins > 0) printf("%02dm ",GapMins);
        else printf("    ");
        printf("%02ds\n",GapSecs);
    }
}


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

int main(int argc, char *argv[])
{
    long    params,i;
    long    status = 0;
    long    FileCount = 0;
    long    FileNbr;
    char    FileName[100];
    Network_struct NETWORK;             /* Structure containing the data    */
                                        /* for all stations.                */
    StationPtr  Station;                /* Pointer to the current station   */
    char FormatStr[10]      = "IAGA";   /* Format of magnetometer data file */
    char StartTimeStr[20];
    char EndTimeStr[20];
    Time_sec GapStart;
    Time_sec GapEnd;
    Time_sec T;
    char Comp;
    long Verbose = 0;


    /*==========================*/
    /* 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] != '-') {
            argv[FileCount++] = argv[params];
        } else {
            switch (*(argv[params]+1)) {
                case 'f' : strcpy(FormatStr,argv[++params]); break;
                case 'v' : Verbose = 1;                      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 that all necessary parameters are defined */
    /*=================================================*/
    
    if (FileCount == 0)
    {
        PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount);
        return FAIL;
    }

    /*=================================================*/
    /* Go through all files listed in the command line */
    /*=================================================*/

    for (FileNbr = 0; FileNbr < FileCount; FileNbr++) {
        strcpy(FileName,argv[FileNbr]);

        /*======================================*/
        /* Read data from data file into memory */
        /*======================================*/

        if (!strcmp(FormatStr,"IAGA")) {
            status = ReadIAGA(FileName,&NETWORK,NULL,NULL,NULL);
        } else
        if (!strcmp(FormatStr,"GADF")) {
            status = ReadGADF(FileName,&NETWORK,NULL,NULL,NULL);
        } else
        if (!strcmp(FormatStr,"Dump")) {
            status = ReadDump(FileName,&NETWORK,NULL,NULL,NULL);
        } else
        if (!strcmp(FormatStr,"WDC")) {
            status = ReadWDC(FileName,&NETWORK,NULL,NULL,NULL);
        } else {
            fprintf(stderr,"Illegal format type: %s\n",FormatStr);
            return FAIL;
        }
    
        if (status != 0) {
            if (status == FileError)
                fprintf(stderr,"### Error in opening data file ");
            if (status == OutOfMemory)
                fprintf(stderr,"### Out of memory while reading data file");
            if (status == FileFormatError)
                fprintf(stderr,"### Wrong file format in input file ");
            fprintf(stderr,"%s\n",FileName);
        }


        if (!strcmp(FormatStr,"Dump"))  /* This is not necessary but */
            ChangeUnitsDOWN(&NETWORK);  /* do it anyway              */


        /*======================================*/
        /* Go through all stations in NETWORK   */
        /*======================================*/

        Station = NETWORK.StationList;
        while(Station != NULL) {

            /*** Write station ID and data start and end times ***/
            
            if (Verbose) {
                SecsToStr(Station->StartTime,StartTimeStr);
                SecsToStr(Station->EndTime,EndTimeStr);
                printf("%s   %.6s %s - %.6s %s\n",Station->StationID,
                        StartTimeStr,StartTimeStr+6,EndTimeStr,EndTimeStr+6);
            }
            
            /*** Find gaps in each component and store them into GapTable ***/

            GapCount = 0;
            for (i = 0;i < MaxGapCount; i++) strcpy(GapTable[i].Comp,"   ");

            for (Comp='X';Comp <= 'Z';Comp++) {
                T = Station->StartTime;
                while (T < Station->EndTime) {
                    if (FindGap(Station,Comp,T,&GapStart,&GapEnd)) {
                        AddGapToTable(Comp,GapStart,GapEnd);
                        if (GapCount == MaxGapCount) {
                            fprintf(stderr,"### Too many gaps !!!!\n");
                            return 1;
                        }
                    }
                    T = GapEnd;
                }
            }
            
            /*** Write GapTable into standard output ***/
            TimeOrderGapTable();
            WriteGapTable(Station);

            Station = Station->Next;
        }                               /* End of Station Loop */

        FreeNetwork(&NETWORK);
    }                                   /* End of File loop */

    return OK;
}

