#include "soleph.h"  /* Header file for BBSO ephemeris programs */

/* 
########################################################
# UPDATE_STRUCT                                        #
#          - program to update BBSO telescope control  #
#            structure:Coord_s                         #
#                                                      #
#          - uppdates telescope position struct with   #
#            corrections for solar rotation and/or     #
#            telescope flexure.                        #
#                                                      #
#          - returns 0 if outside the solar disk       #
#            or in case of error 1 otherwise           #
#                                                      #
#      by: Anders Johannesson                          #
#                                                      #
#  Modifications:  06-Aug-97  AJO  Created             #
#                  17-Aug-97  AJO  Flexure Data Added  # 
#                  10-Oct-97  AJO  Updated ephem code  #
#                  20-Oct-97  AJO  Error update        #
#                  24-Oct-97  AJO  Flexure change      #
#                  01-Nov-97  AJO  Absolute Flexure    #
#                  06-Nov-97  AJO  Error Codes         #
#                                                      #
#       Part of the PDP replacement project 1997       #
########################################################
*/

short update(Cstruct *InStruct, double H_ref, double flexure_LUT[2][145])
{

   /* DECLARATIONS */
   double S, B0, P, L0, B, L, x, y, xnew, ynew,xoff,yoff;
   double TimeDiff, H_now;
   short  error_code;
   TimeType Etime;
   EphType Ephem;

   /* WHICH WERE THE LAST COORDINATES? */
   B=InStruct->rlat;
   L=InStruct->rlong;

   /* CHECK IF WE ARE OUTSIDE OF THE SUN */
   if ((B > -9999.9) && (L > -9999.9))
      error_code = OK;
   else
      error_code = BADXY;

   /* UPDATE FOR SOLAR ROTATION */
   if ((InStruct->rupdate == 1) && (error_code == OK))
   {

      /* GET CURRENT TIME AND TIME DIFFERENCE SINCE LAST UPDATE */
      new_time(*InStruct, &Etime, &TimeDiff, ROTATION);

      /* CALCULATE EPHEMERID */
      soleph(Etime,&Ephem);

      /* GET S, B0, P and L0 */
      S=Ephem.rad;
      B0=Ephem.b;
      P=Ephem.p;
      L0=0.0; /* use central meridian as reference */

      /* WHICH WERE THE LAST COORDINATES? */
      B=InStruct->rlat;
      L=InStruct->rlong;

      /* UPDATE WITH SYNODIC DIFFERENTIAL ROTATION AT THIS LATITUDE */
      /* Values from Balthasar and Wohl (1980) - 0.9865 deg/day */
      L=L+((TimeDiff/86400.0)*(13.5-2.8*pow(sin(B*DPI/180.0),2)));

      /* FIND NEW PROJECTION ON DISK */
      error_code=helio_to_cart(S,B0,P,L0,B,L,&xnew,&ynew);

      /* TRANSFER THE VALUES TO THE STRUCTURE */
      if ((error_code == OK) || (error_code == BADXY))
      {
         to_struct(InStruct, Etime, xnew, ynew, B, L,-1,-1,ROTATION);
      }
	 
   }

   /* UPDATE FOR TELESCOPE FLEXURE */
   if (InStruct->fupdate == 1)
   {

      /* GET CURRENT TIME AND TIME DIFFERENCE SINCE LAST UPDATE */
      new_time(*InStruct, &Etime, &TimeDiff, FLEXURE);

      /* CALCULATE EPHEMERID */
      soleph(Etime,&Ephem);

      /* TELESCOPE FLEXURE */
      if (Ephem.H > 12)
         H_now=Ephem.H-24.0;
      else
         H_now=Ephem.H;
      flexure_since(H_ref,H_now,flexure_LUT,&xoff,&yoff);

      /* TRANSFER THE VALUES TO THE STRUCTURE */
      to_struct(InStruct,Etime, -1, -1, -1, -1,xoff,yoff,FLEXURE);

   }

   if ((error_code == BADLAT) | (error_code == BADLONG))
      error_code = FARSUN;

   return(error_code);

}


/*
########################################################
# NEW_TIME                                             #
#          - Get current time and time difference from #
#            last update.                              #
#                                                      #
#          - program used by UPDATE_STRUCT.            #
#                                                      #
#    Modifications:  07-Aug-97  AJO  created           # 
#                                                      #
#       Part of the PDP replacement project 1997       #
########################################################
*/

void new_time(Cstruct InStruct, TimeType *Etime, double *TimeDiff, short rfupdate)
{

   /* DECLARATIONS */
   time_t Current_Time, Last_UT, Current_UT;
   struct tm *Last_Time_UT, *Current_Time_UT, temp;

   /* GET TIME */
   time(&Current_Time);
   Current_Time_UT=gmtime(&Current_Time);

   /* UPDATE ETIME WITH CURRENT TIME (UT) */
   Etime->iy=Current_Time_UT->tm_year+1900;
   Etime->im=Current_Time_UT->tm_mon+1;
   Etime->id=Current_Time_UT->tm_mday;
   Etime->ih=Current_Time_UT->tm_hour;
   Etime->imi=Current_Time_UT->tm_min;
   Etime->is=Current_Time_UT->tm_sec;

   /* USE TEMP TO AVOID PROBLEM WITH TEMPORARY BUFFER IN mktime() */
   temp.tm_year=Current_Time_UT->tm_year;
   temp.tm_mon=Current_Time_UT->tm_mon;
   temp.tm_mday=Current_Time_UT->tm_mday;
   temp.tm_hour=Current_Time_UT->tm_hour;
   temp.tm_min=Current_Time_UT->tm_min;
   temp.tm_sec=Current_Time_UT->tm_sec;
   temp.tm_isdst=Current_Time_UT->tm_isdst;

   Current_UT=mktime(&temp);

   /* WHAT IS THE TIME DIFFERENCE SINCE LAST UPDATE? */
   if (rfupdate == ROTATION) /* rotation */
   {
      Last_Time_UT = (struct tm *) calloc(1,sizeof(struct tm));
      Last_Time_UT->tm_year=InStruct.r_year-1900;
      Last_Time_UT->tm_mon=InStruct.r_month-1;
      Last_Time_UT->tm_mday=InStruct.r_day;
      Last_Time_UT->tm_hour=InStruct.r_hour;
      Last_Time_UT->tm_min=InStruct.r_minute;
      Last_Time_UT->tm_sec=InStruct.r_second;
      Last_Time_UT->tm_isdst=0;

      Last_UT=mktime(Last_Time_UT);
      *TimeDiff=difftime(Current_UT,Last_UT);

      free(Last_Time_UT);
   }

   /* WHAT IS THE TIME DIFFERENCE SINCE LAST UPDATE? */
   if (rfupdate == FLEXURE) /* telescope flexure */
   {
      /* NO DIFFERENCE - LUT IS USED FOR ABSOLUTE FLEXURE */
      *TimeDiff=0.0;
   }

}


/*
########################################################
# TO_STRUCT                                            #
#          - Send new coordinates and time to the      #
#            structure.                                #
#                                                      #
#          - program used by UPDATE_STRUCT.            #
#                                                      #
#    Modifications:  07-Aug-97  AJO  created           #
#                    24-Oct-97  AJO  Absolute Flexure  # 
#                                                      #
#       Part of the PDP replacement project 1997       #
########################################################
*/
void to_struct(Cstruct *InStruct, TimeType Etime, double x, double y,
	double B, double L, double xoff, double yoff, short mode)
{

   /* UPDATE TIME */
   if (mode == ROTATION) /* rotation */
   {
      InStruct->xpos=x;
      InStruct->ypos=y;
      InStruct->rlong=L;
      InStruct->rlat=B;
      InStruct->r_hour=Etime.ih;
      InStruct->r_minute=Etime.imi;
      InStruct->r_second=Etime.is;
      InStruct->r_year=Etime.iy;
      InStruct->r_month=Etime.im;
      InStruct->r_day=Etime.id;
   }
   if (mode == FLEXURE) /* flexure */
   {
      InStruct->f_offx=xoff;
      InStruct->f_offy=yoff;
   }

}
