/*
*
*     ##################################################################
*     ##################################################################
*     ######                                                      ######
*     ######                      88D2ARPS                        ######
*     ######                                                      ######
*     ######                     Developed by                     ######
*     ######    Center for Analysis and Prediction of Storms      ######
*     ######                University of Oklahoma                ######
*     ######                                                      ######
*     ##################################################################
*     ##################################################################
*
*     fakeio.c
*
*#######################################################################
*
*     PURPOSE:
*
*     Emulates the behavior of the NSSL WSR-88D realtime and 
*     Archive II tape reading software.  Arrays filled with fake
*     data are passed to the calling program as if they were
*     being read from the realtime buffer or tape stream.
*
*     To use: Replace links to NSSL 88D libraries with 
*             object code from this file.
*
*     Some shortcomings of version 1.0:
*        A few calls are not supported.
*        Set_radar_name doesn't read the radar table and change location.
*        Storm mode only is emulated.
*        Runs faster than realtime (sleeps can be inserted in read_radial).
*
*     Things for the future:
*        Address shortcomings, above.
*        More sophisticated fake data, such as read from a file,
*        analytic field or even a cloud model.
*
*#######################################################################
*
*     AUTHOR: Keith Brewster
*     March, 1995   version 1.0
*     kbrewster@ou.edu
*
*     MODIFICATION HISTORY:
*
*#######################################################################
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <math.h>
#include <time.h>

struct tm rtime, *radtime;
struct count_struct {
     int iazi;
     int iangle;
     int itilt;
     int iscan;
} radcount;

struct loc_struct {
     char rsite[80];
     char radid[4];
     int latitude;
     int longitude;
     int altitude;
} radinfo;

/* ****  End of structure definitions **** */

/*     set_radar_name    */

/*     Assigns radar name in location structure
       but does not look up the lat,lon,elev like the
       real radar reader.                               */

void set_radar_name(site)
char site[80];
{
      extern struct loc_struct radinfo;
      strcpy(radinfo.rsite,site);
}

/*     get_field_number  */

/*    Assigns field number based on input string.
      Must agree with action of get_data_field.  */

int get_field_num(fchar)
char fchar[3];
{
      if(strcmp(fchar,"DBZ") == 0)
        return(0);
      else if(strcmp(fchar,"VEL") == 0)
        return(1);
      else if(strcmp(fchar,"SPW") == 0)
        return(2);
      else if(strcmp(fchar,"SNR") == 0)
        return(3);
      else
        return(-1);
}

/*     radar_init  */

/*    Initializes the radar counters.
      prints a warning message that fake data is being used.  */

void radar_init(drive)
char drive[80];
{
      extern struct count_struct radcount;
      extern struct tm rtime, *radtime;

      printf("\n\n *************FAKE DATA***********************\n\n");
      printf("  Initializing a2io_fake for file testing only.\n");
      printf("\n\n *************FAKE DATA***********************\n\n");

      radtime =&rtime;

      radcount.iazi=0;
      radcount.iangle=100;
      radcount.itilt=1;
      radcount.iscan=1;
}

/*     read_radial    */

/*     Emulates the act of reading a radial.
       Gets the time from the system and increments
       counters that pretend that the radar is spinning
       and going through a normal sequence of elev angles.

       Unlike the true read_radial, data are not buffered
       for use by get_data_field, rather get_data_field makes
       things up as it goes along                       */

/*     These are the tilts for the WSR-88D storm mode   */
/*     The precise behavior of the 0.5 degree scans     */
/*     is not replicated                                */

#define MAXTILT 16
static int kelev[MAXTILT] =
         {50,50,50,150,240,340,430,530,620,750,
          870,1000,1200,1400,1670,1950};

int read_radial()
{
      extern struct tm rtime, *radtime;
      extern struct count_struct radcount;
      extern int kelev[];
      int istat;
      long curtime[2], *tp;
      long timez[2], *tzp;

      tp = curtime;
      tzp = timez;

      radcount.iazi=radcount.iazi+100;
      if ( radcount.iazi > 35999 ) {
        radcount.iazi=radcount.iazi-36000;
        radcount.itilt++;
        if ( radcount.itilt > MAXTILT) {
          radcount.itilt=1;
          radcount.iscan++;
        }
      }
      radcount.iangle=kelev[radcount.itilt - 1];
      istat=gettimeofday(tp,tzp);
      radtime=gmtime(tp);
      return(0);
}
int get_first_gate(ifield)
int ifield;
{
    if( ifield == 0 )
      return(1000);
    else if ( ifield == 1)
      return(1000);
    else if ( ifield == 2)
      return(1000);
    else if ( ifield == 3)
      return(1000);
    else
      return(-999);
}
int get_gate_spacing(ifield)
int ifield;
{
    if( ifield == 0 )
      return(1000);
    else if ( ifield == 1)
      return(250);
    else if ( ifield == 2)
      return(250);
    else if ( ifield == 3)
      return(1000);
    else
      return(-999);
}

/*     get_data_field     */

/*     returns fake data

       Some day this could read from a storm model or other
       more realistic fake data generator.

       Reflectivity data are assigned an increasing function of range
       Velocity data are assigned a value like a constant horiz wind
       Spectrum Width data are constant = 0.5 ms-1
       SNR data are constant = 40.                                */

int get_data_field(ifield,field,nsize)
int ifield;
float field[];
int nsize;
{
    extern struct count_struct radcount;
    float twopi,dtr;
    float sinaz,cosaz,dxdr,dydr,dsdr;
    float mpgate,mgate0,x0,y0,xscale,yscale,x,y,u,v;
    int i;
    float *ptr;

    ptr=field;
 
    if( ifield == 0 )
      for (i = 0; i < nsize; i++){
        *ptr = (0.1 * (float) i);
        ptr++;
      }
    else if( ifield == 1 )
      for (i = 0; i < nsize; i++){
/*      *ptr =-abs (20.0 * sin (dtr * 0.01 * (float) radcount.iazi) );*/
/*      *ptr = 20.0 * sin (dtr * 0.01 * (float) radcount.iazi);*/
        dtr=0.017453292;
        twopi = 6.283185307;
        mpgate=250.;
        mgate0=1000.;
        x0 = 15000.;
        y0 = 15000.;
        xscale = twopi / 50000.;
        yscale = twopi / 50000.;
        cosaz = cos (dtr * 0.01 * (float) radcount.iazi);
        sinaz = sin (dtr * 0.01 * (float) radcount.iazi);
        dxdr = mpgate * cosaz ;
        dydr = mpgate * sinaz ;
        dsdr = cos (dtr * 0.01 * (float) radcount.iangle);
        for (i = 0; i < nsize; i++){
          x = x0 + dxdr * (mgate0 + (float) i);
          y = y0 + dydr * (mgate0 + (float) i);
          u = 10.0 * sin (yscale * y);
          v =-10.0 * sin (xscale * x);
          *ptr = 10.0 * dsdr * (u * sinaz + v * cosaz);
          ptr++;
        }
      }
    else if( ifield == 2 )
      for (i = 0; i < nsize; i++){
        *ptr = 0.5;
        ptr++;
      }
    else if( ifield == 3 )
      for (i = 0; i < nsize; i++){
        *ptr = 40.;
        ptr++;
      }
    else
      return(-1);

    return(0);
}

/*     get_year    */

/*     returns year 
       time is controlled by read_radial */

int get_year()
{
      extern struct tm *radtime;
      return(radtime->tm_year);
}

/*     get_month   */

/*     returns number of month (1-12)
       time is controlled by read_radial */

int get_month()
{
      extern struct tm *radtime;
      int imon;
      imon=radtime->tm_mon + 1;
      return(imon);
}

/*     get_day   */

/*     returns day
       time is controlled by read_radial */

int get_day()
{
      extern struct tm *radtime;
      return(radtime->tm_mday);
}

/*     get_hour   */

/*     returns hour
       time is controlled by read_radial */

int get_hour()
{
      extern struct tm *radtime;
      return(radtime->tm_hour);
}

/*     get_min   */

/*     returns minute 
       time is controlled by read_radial */

int get_min()
{
      extern struct tm *radtime;
      return(radtime->tm_min);
}

/*     get_sec   */

/*     returns seconds 
       time is controlled by read_radial */

int get_sec()
{
      extern struct tm *radtime;
      return(radtime->tm_sec);
}

/*     get_azi   */

/*     returns radar azimuth angle
       angle is controlled by read_radial  */

int get_azi()
{
      extern struct count_struct radcount;
      return(radcount.iazi);
}

/*     get_fixed_angle   */

/*     returns radar elevation angle
       angle is controlled by read_radial  */

int get_fixed_angle()
{
      extern struct count_struct radcount;
      return(radcount.iangle);
}

/*     get_scan   */

/*     returns radar scan number
       number is controlled by read_radial  */

int get_scan()
{
      extern struct count_struct radcount;
      return(radcount.iscan);
}

/*     get_tilt   */

/*     returns radar tilt number
       number is controlled by read_radial  */

int get_tilt()
{
      extern struct count_struct radcount;
      return(radcount.itilt);
}

/*     get_status   */

/*     status returned is fixed at 1,
       status is always good in radar nirvana */

int get_status(index)
int index;
{
      return(1);
}

/*     get_rt_mode   */

/*     rt_mode returned is fixed at 1, real-time /

int get_rt_mode()
{
      return(1);
}

/*     get_nyquist   */

/*     nyquist velocity returned is fixed at 35.0 ms-1  */

 
int get_nyquist()
{
      return(3500);
}

/*     get_vcp   */

/*     vcp returned is fixed at 41  */

int get_vcp()
{
      return(41);
}

/*     get_latitude   */

/*     latitude returned is fixed at 35.23N  */

int get_latitude()
{
/*    return(3523000); */
/*    return(3674000); */
      return(3523000);
}

/*     get_longitude  */

/*     longitude returned is fixed at 97.46W  */

int get_longitude()
{
/*    return(9746000); */
/*    return(9812750); */
      return(9746000);   
}

/*     get_altitude  */

/*     altitude returned is fixed at 381 m */

int get_altitude()
{
      return(381);
}

/*  get_number_of_gates
 *  
 *  Need to be checked for correctness -- Y. Wang.
 *  Just added for compiling 88d2arps_fake.
 *
*/

int get_number_of_gates(int n) {
  return 0;
}