/**********************************************************************
* PROGRAM DESCRIPTION : Convert OLD URSI format to NEW URSI format
*                       "NEW" = ursi international exchange format
*                       "OLD" = WDC/A archive format
* INPUT : PC disk file with names of OLD URSI files to combine into 1
*                                    NEW URSI file (OLD URSI names in order)
*         Each file named contains 80 byte records terminated with CR/LF.
* OUTPUT: PC disk file named SSSYY.NEW  where SSS is station code and
*                                              YY is year
* USAGE : old2new file-of-filenames
* FUNCTION : converts old URSI data files to a single file of new URSI data
* AUTHOR : Chris Wells
* DATE   : December 07, 1988
* MODIFIED : November 2, 1989 - port to PC; input from file of filenames
* PROGRAM LOGIC :
* COMMENTS : 1 old URSI file = 1 month, all parameters
*            1 new URSI file = 1 year, all parameters
*                    1 block = 1 month, 1 parameter
* UPDATES : 3/29/89  use 5-character station code read from file
*           4/24/89  EBCDIC; copy all input tape files, changing output
*                    files upon finding a new year or new station code
*           5/12/89  log file for screen output; file numbers on output
*           4/11/91  enhance log file output for debugging bad input;
*                    open log file in append mode; add verbose flag;
*           9/24/91  correct leap year determination in Ndays;
*                    re-initialize entire month of data to blanks to
*                    correct problem encountered when some input files
*                    have missing days (instead of blank-filled)
*          10/16/91  (TAW) read header info from OU_HEADE.OK file
*          10/17/91  (TAW) no blanks in parameter type     
*           7/15/92  (TAW) leap year correction
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#define NEW_RECORD_SIZE  120
#define OLD_RECORD_SIZE   80
#define OKFILE "OU_HEADE.OK"

struct PARAMETER {
       char value[5];
       };

struct OLD_URSI_Header {
       char stationcode[5],
            year[2],
            month[2],
            stationname[16],
            country[15],
            timezone[5];
       float latitude, longitude;
       } Header;

struct OLD_URSI_Parameter_Month {
       char year[2],
            month[2];
       int daysinmonth;
       char parametertype[2];
       struct PARAMETER monthdata[31][24],
                        summary[7][24];
       } MonthData;

int FilesWritten;
static char InputPath[32],
            OutputPath[32];
FILE *flog,
     *oldtape,
     *newtape;
int Verbose;
char UtilStr[81];

int Read_OLD_URSI_Record( FILE **oldtape, char record[OLD_RECORD_SIZE] );
void HeaderRecord(char stacode[],char year[],char month[],
                  struct OLD_URSI_Header *header);
void Error_Exit( char errstring[] );
int Write_NEW_URSI_Block( FILE **newtape, struct OLD_URSI_Header header,
                          struct OLD_URSI_Parameter_Month month );
void Process_OLD_URSI_Record( char Record[OLD_RECORD_SIZE],
                               struct OLD_URSI_Parameter_Month *Month );
void Initialize_OLD_Month( struct OLD_URSI_Parameter_Month *Month );

void main( int argc, char *argv[] )
{
    static char OldRecord[OLD_RECORD_SIZE],
                lastchar[2],
                lastyr[2],
                lastSC[5],
                message[60];
    static char logname[32],
                drive[32],dir[32],fname[32],ext[32];
    int FileIn;
    FILE *fp;
    char stacode[4];
    char year[3],month[3];

    /***  get the command line parameters  ***/
    if ( argc < 2 ) {
        printf(" USAGE: olds2new file-of-filenames [VERBOSE]\n");
        exit(1);
        }

    Verbose = ( argc >= 3 ) ? 1 : 0;
    if ( Verbose )
       printf("VERBOSE mode set\n");

    _splitpath( argv[1],drive,dir,fname,ext );
    sprintf( logname,"%s.LOG",fname );
    if ( (flog = fopen( logname,"a" ) ) == NULL )
        Error_Exit( "can't open LOG file" );

    FileIn = 0;

    /*******************************************************/
    /* loop over all input files in file on command line   */
    /*******************************************************/
    fp = fopen( argv[1],"r" );
    while ( fgets(InputPath,32,fp) ) {

        /*** open an OLD URSI input file ***/
        InputPath[strlen(InputPath)-1] = 0;   /* remove LF terminator */
        if ( (oldtape = fopen(InputPath,"r") ) == NULL ) {
            sprintf( message,"OPENING INPUT FILE %s",InputPath );
            Error_Exit( message );
            }
       

        /*** if first input file, open output file ***/
        if ( ! FileIn ) {
            /***  read OLD URSI header record to form output file name ***/
            if ( ! Read_OLD_URSI_Record( &oldtape,OldRecord ) ) {
              sprintf( message,"FIRST FILE IS EMPTY : %s",InputPath );
              Error_Exit( message );
            }

            sprintf( OutputPath,"%5.5s.NEW",&OldRecord[2] );
            if ( (newtape = fopen(OutputPath,"w") ) == NULL )
                 Error_Exit( "OPENING OUTPUT FILE" );
            rewind( oldtape );
            /***  set flags to nothing  ***/
            strncpy( lastyr,"-1",2 );
            strncpy( lastSC,"-1-1-",5 );
            }

        Initialize_OLD_Month( &MonthData );

        /***  read in the OLD URSI header record  ***/
        if ( ! Read_OLD_URSI_Record( &oldtape,OldRecord ) ) {
            sprintf( message,"EMPTY OLD URSI INPUT FILE %s",InputPath );
            Error_Exit( message );
            }

        /*** decode 3-letter station code, year, month from first record ***/
        strncpy( stacode,OldRecord+2,3 );
        stacode[3]='\0';
        strncpy( year,OldRecord+5,2 );
        year[2]='\0';
        strncpy( month,OldRecord+7,2 );
        month[2]='\0';

        HeaderRecord( stacode,year,month,&Header );

        /***  if year changed or station code changed, BALK  ***/
        if ( (strncmp(Header.year,lastyr,2) && strncmp(lastyr,"-1",2) ) ||
             (strncmp(Header.stationcode,lastSC,5) && strncmp(lastSC,"-1-1-",5) ) ) {
            printf("%s %2.2s\n","Year = ",Header.year);
            printf("%s %5.5s\n","Station code =",Header.stationcode);
            sprintf( message,"CHANGE OF YEAR OR STATION CODE in file %s",InputPath );
            Error_Exit( message );
            }

        strncpy( lastyr,Header.year,2 );
        strncpy( lastSC,Header.stationcode,5 );

        printf("%03d: %56.56s\n",FileIn,OldRecord );

        fprintf( flog,"%03d: %56.56s\n",FileIn++,OldRecord );
        if ( Verbose )
          fflush( flog );

        strncpy( lastchar,"-1",2 );
        /*** read in all OLD URSI data from input file  ***/
        while ( Read_OLD_URSI_Record(&oldtape,OldRecord) ) {
            /***  skip over the OLD URSI record separator  ***/
            if ( strncmp(&OldRecord[0],"1 ",2) == 0 )
                continue;
            /***  skip over the OLD URSI end-of-file flag  ***/
            if ( strncmp(&OldRecord[0],"  ",2) == 0 )
                continue;
            /***  check if a new characteristic was read  ***/
            if ( strncmp(lastchar,&OldRecord[11],2) ) {
                if ( strncmp(lastchar,"-1",2) )
                    Write_NEW_URSI_Block( &newtape,Header,MonthData );
                strncpy( lastchar,&OldRecord[11],2 );
                /*....................................................*
                * 9/24/91: re-initialize entire month of data to 
                *          compensate for some input files not having
                *          blank-filled records for some days (instead
                *          those days just aren't there)
                *.....................................................*/
                Initialize_OLD_Month( &MonthData );
                }
            Process_OLD_URSI_Record( OldRecord,&MonthData );
            }
        /*** end of OLD URSI input file ***/

        Write_NEW_URSI_Block( &newtape,Header,MonthData );
        fclose(oldtape);
        }

      printf(      "=============================================================\n");
      fprintf(flog,"=============================================================\n" );
      printf( "... NEW URSI OUTPUT FILE IS %s\n",OutputPath );
      fprintf( flog,"... NEW URSI OUTPUT FILE IS %s\n",OutputPath );
      fclose( flog );
      fclose( newtape );

      exit( 0 );
}


/**********************************************************************
* read a logical record from the OLD URSI tape                        *
* arguments :                                                         *
*    record : the logical record read                                 *
**********************************************************************/
int Read_OLD_URSI_Record( FILE **oldtape, char record[OLD_RECORD_SIZE] )
{
    static char Buffer[OLD_RECORD_SIZE+2];    /* +2 for CR/LF */

    if ( ! fgets( Buffer,OLD_RECORD_SIZE+2,*oldtape ) )
        return( 0 );
    if ( strlen(Buffer) == 1 )       /*** allow for blank last line ***/
        return( 0 );
    strncpy( record,Buffer,OLD_RECORD_SIZE );


    /*** (TAW 10/17/91) no blanks in parameter type ***/
    if( ! strncmp(&record[11],"  ",2) )
      strncpy( &record[11],"00",2 );
    if( ! strncmp(&record[11]," ",1) )
      strncpy( &record[11],"0",1 );

    return( 1 );
}


/********************************************************************
*  10/16/91 (TAW)
*  Get header info. from the OU_HEADE.OK file
********************************************************************/
void HeaderRecord(char stacode[],char year[],char month[],
                  struct OLD_URSI_Header *header)
{
    int found;
    char temp[5];
    float val;
    static char Buffer[93];    
    int yr,mn;
    int begyrt,begmnt;
    int endyrt,endmnt;
    FILE *OU_File;

    strncpy( temp,year,2 );
    temp[2] = '\0';
    yr = atoi( temp );
    strncpy( temp,month,2 );
    temp[2] = '\0';
    mn = atoi( temp );

    if( (OU_File = fopen( OKFILE,"r" )) == NULL ) {
      sprintf(UtilStr,"%s %s","UNABLE to open",OKFILE);
      Error_Exit(UtilStr);
      return;
    }

    while( fgets( Buffer,94,OU_File ) ) {
      found = 0;
      if( ! strncmp( Buffer+2,stacode,3 ) ) {
        found = 1;
        if( strncmp( Buffer+80,"  ",2 ) != 0 ) {
          found = 0;
          strncpy( temp,Buffer+80,2 );
          temp[2] = '\0';
          begyrt = atoi( temp );  
          strncpy( temp,Buffer+82,2 );
          temp[2] = '\0';
          begmnt = atoi( temp );  
        }
        else {
          begyrt = -1;
          begmnt = 1;
        }
        if( strncmp( Buffer+84,"  ",2 ) != 0 ) {
          found = 0;
          strncpy( temp,Buffer+84,2 );
          temp[2] = '\0';
          endyrt = atoi( temp );  
          strncpy( temp,Buffer+86,2 );
          temp[2] = '\0';
          endmnt = atoi( temp );  
        }
        else {
          endyrt = 9999;
          endmnt = 12;
        }

        if( ! found ) {
         if( (yr > begyrt) && (yr < endyrt) ) {
            found = 1;
          }
          else if( (yr == endyrt) && (mn <= endmnt) ) {
            found = 1;
          }
          else if( (yr == begyrt) && (mn >= begmnt) ) {
            found = 1;
          }
        }
        if( found )  {
          strncpy( header->stationcode,Buffer+75,5 );
          strncpy( header->year,year,2 );
          strncpy( header->month,month,2 );
          strncpy( header->stationname,Buffer+13,15 );
          strncpy( header->country,Buffer+29,15 );
          strncpy( header->timezone,Buffer+69,5 );
          strncpy( temp,Buffer+47,3 );
          temp[3] = (char) 0;
          val = ((float) atoi( temp )) / 10.0;
          if ( ! strncmp( Buffer+50,"S",1 ) )
              val = (float)-1.0 * val;
          header->latitude = val;
          strncpy( temp,Buffer+51,4 );
          temp[4] = (char) 0;
          val = ((float) atoi( temp )) / 10.0;
          if ( ! strncmp( Buffer+55,"W",1 ) )
              val = val * -1.0;
          header->longitude = val;
          break;
        }
      }
    }

    if( !found ) {
      sprintf(UtilStr,"%s %s","UNABLE to find data in",OKFILE);
      Error_Exit(UtilStr);
    }
      

    fclose(OU_File);

    return;
}



/*********************************************************************
* abort the program after giving an error message                    *
*********************************************************************/
void Error_Exit( char errstring[] )
{
    printf("  ERROR : %s\n",errstring);
    fprintf( flog," ERROR : %s\n",errstring );
    fclose( flog );
    exit(1);
}



/*********************************************************************
* compute the number of days in this month                           *
* arguments :                                                        *
*   month : month string like "03"                                   *
*   year  : year string like "87"                                    *
*********************************************************************/
int Ndays( char month[],char year[2] )
{
    int yr,mon;
    char temp[3];

    strncpy( temp,year,2 );
    temp[3] = 0;
    yr = atoi( temp ) + 1900;
    strncpy( temp,month,2 );
    temp[3] = 0;
    mon = atoi( temp );
    if ( (mon==9)||(mon==4)||(mon==6)||(mon==11) )
       return( 30 );
    if ( mon==2 ) {
        /* 7/15/92: correct leap year determination */
        if ( ( (yr%4)==0 ) && ( (yr%100)!=0 ) || ( (yr%400)==0 ) )
            return( 29 );
        else
            return( 28 );
        }
    return( 31 );
}


/***********************************************************************
* write a block of new ursi data to tape                               *
* arguments :                                                          *
*   newtape : file handle of new tape                                  *
*   header  : old ursi processed header                                *
*   month   : old ursi data month                                      *
***********************************************************************/
int Write_NEW_URSI_Block( FILE **newtape, struct OLD_URSI_Header header,
                          struct OLD_URSI_Parameter_Month month )
{
    static char NewBlock[NEW_RECORD_SIZE+1], temp[5];
    int pos,val,i,hr;
    float rval;

    strncpy( &NewBlock[0],header.stationname,15 );
    NewBlock[15] = ' ';
    NewBlock[16] = NewBlock[17] = NewBlock[18] = NewBlock[19] = ' ';
    strncpy( &NewBlock[20],header.stationcode,5 );
    strncpy( temp,header.timezone,4 );
    temp[4] = '\0';
    val = atoi( temp ) / 10;
    sprintf( temp,"%03d%c",val,header.timezone[4] );
    strncpy( &NewBlock[25],temp,4 );
    rval = (float)90.0 - header.latitude;
    val = (int) (rval * (float)10.0);
    sprintf( &NewBlock[29],"%04d",val );
    if ( header.longitude < 0 )
        sprintf( &NewBlock[33],"%04d",(int)((360.0+header.longitude)*10) );
    else
        sprintf( &NewBlock[33],"%04d",(int)(header.longitude*10) );
    NewBlock[37] = '1';
    NewBlock[38] = '9';
    NewBlock[39] = header.year[0];
    NewBlock[40] = header.year[1];
    strncpy( &NewBlock[41],header.month,2 );
    strncpy( &NewBlock[43],month.parametertype,2 );
    for ( i = 45; i < 120; i++ )
        NewBlock[i] = ' ';
    NewBlock[120] = 0;


    fprintf( *newtape,"%s\n",NewBlock );

    for ( i = 0; i < month.daysinmonth; i++ ) {
        for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
            strncpy( &NewBlock[pos],month.monthdata[i][hr].value,5 );
        NewBlock[120] = 0;
        fprintf( *newtape,"%s\n",NewBlock );
        }

    for ( i = month.daysinmonth; i < 31; i++ ) {
        for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
            strncpy( &NewBlock[pos],"     ",5 );
        NewBlock[120] = 0;
        fprintf( *newtape,"%s\n",NewBlock );
        }

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[0][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[1][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[2][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[3][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[5][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[4][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],month.summary[6][hr].value,5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    for ( pos = 0, hr = 0; hr < 24; hr++, pos += 5 )
        strncpy( &NewBlock[pos],"     ",5 );
    NewBlock[120] = 0;
    fprintf( *newtape,"%s\n",NewBlock );

    return( 1 );
}

/***********************************************************************
* process an OLD URSI logical record                                   *
* arguments :                                                          *
*   Record  : the record to process                                    *
*   Month   : the cumulative OLD URSI month of data                    *
***********************************************************************/
void Process_OLD_URSI_Record( char Record[OLD_RECORD_SIZE],
                         struct OLD_URSI_Parameter_Month *Month )
{
    char temp[6];
    int i, indx, day, hourst, startpos;

    strncpy( Month->year,&Record[5],2 );
    strncpy( Month->month,&Record[7],2 );
    Month->daysinmonth = Ndays( Month->month,Month->year );
    strncpy( Month->parametertype,&Record[11],2 );

    if ( Record[1] == '1' )
      hourst = 0;
    else
      hourst = 12;
    startpos = 13;
        /***  hourly measurement record  ***/
    if ( Record[0] == '1' ) {
        strncpy( temp,&Record[9],2 );
        temp[2] = 0;
        day = atoi( temp );
        if ( Verbose ) {
          fprintf( flog,"DATE:%2.2s%2.2s%02d %2.2s\n",Month->year,
                   Month->month,day,Record+11 );
          fflush( flog );
          }
        for ( i = hourst; i < hourst+12; i++, startpos += 5 )
            strncpy( Month->monthdata[day-1][i].value,&Record[startpos],5 );
        }
        /***  monthly summary record  ***/
    else {
        indx = -1;
        if ( ! strncmp(&Record[9],"40",2) ) indx = 0;
        if ( ! strncmp(&Record[9],"50",2) ) indx = 1;
        if ( ! strncmp(&Record[9],"60",2) ) indx = 2;
        if ( ! strncmp(&Record[9],"70",2) ) indx = 3;
        if ( ! strncmp(&Record[9],"80",2) ) indx = 4;
        if ( ! strncmp(&Record[9],"77",2) ) indx = 5;
        if ( ! strncmp(&Record[9],"87",2) ) indx = 6;
        if ( Verbose ) {
          fprintf( flog,"SUMMARY:%2.2s\n",Record+9 );
          fflush( flog );
          }
        for ( i = hourst; i < hourst+12; i++, startpos += 5 )
            strncpy( Month->summary[indx][i].value,&Record[startpos],5 );
        }
    return;
}



/***********************************************************************
* initialize the OLD URSI month of data to all blanks for safety       *
* arguments :                                                          *
*   Month : OLD URSI parameter month                                   *
***********************************************************************/
void Initialize_OLD_Month( struct OLD_URSI_Parameter_Month *Month )
{
    int hour, day, summ;

    strncpy( Month->year,"  ",2 );
    strncpy( Month->month,"  ",2 );
    Month->daysinmonth = 0;
    strncpy( Month->parametertype,"  ",2 );
    for ( hour = 0; hour < 24; hour++ ) {
        for ( day = 0; day < 31; day++ )
            strncpy( Month->monthdata[day][hour].value,"     ",5 );
        for ( summ = 0; summ < 7; summ++ )
            strncpy( Month->summary[summ][hour].value,"     ",5 );
        }

    return;
}

/*
int strupr( string )
char string[];
{
    int i;

    for ( i = 0; i < strlen(string); i++ )
        string[i] = toupper(string[i] );
    return;
}
*/