# include "convert.h"
  
int hh_hms (double hh, int *hr, int *mn, double *sc) {

  int flag;

  flag = SIGN(hh);
  hh *= flag;
  hh = 24.0*(hh/24.0 - (int)(hh/24.0));
  *sc = 60.0*(60.0*hh - (int)(60.0*hh));
  *mn = 60.0*(hh - (int)hh);
  *hr = (int) hh;
  *hr *= flag;
  return (TRUE);
}
 
int dd_dms (double dd, int *dg, int *mn, double *sc) {

  int flag;

  flag = SIGN(dd);
  dd = fabs (dd);
  *dg = (int) dd;
  *mn = (int) 60*(dd - *dg);
  *sc = 3600.0*(dd - *dg - *mn/60.0);
  if (*sc > 59.99) {
    *sc = 0;
    *mn += 1.0;
  }
  *dg *= flag;
  return (TRUE);
}
 
int hms_format (char *line, double value) {

  int hr, mn;
  double sc;

  hh_hms (value, &hr, &mn, &sc);
  hr = (int) value;
  if (isnan (value))
    sprintf (line, "xx:xx:xx.xx");
  else {
    if (value < 0) {
      sprintf (line, "-%02d:%02d:%05.2f", abs(hr), mn, sc);
    } else {
      sprintf (line, "%02d:%02d:%05.2f", hr, mn, sc);
    }
  }      
  return (TRUE);
}

int dms_format (char *line, double value) {

  int dg, mn;
  double sc;

  dd_dms (value, &dg, &mn, &sc);
  if (value < 0) {
    sprintf (line, "-%02d:%02d:%05.2f", abs(dg), mn, sc);
  } else {
    sprintf (line, "%02d:%02d:%05.2f", dg, mn, sc);
  }
  return (TRUE);
}

/***** extract RA - RA, DEC - DEC from HST GSC entry *****/
int hstgsc_hms_to_deg (double *h0, double *h1, double *d0, double *d1, char *string) {
  
  int flag_d0, flag_d1, flag_h0, flag_h1;
  double tmp;
  
  *d0 = *h0 = *d1 = *h1 = 0;

  flag_h0 = dparse (h0, 1, string);
  flag_h1 = dparse (h1, 4, string);
  flag_d0 = dparse (d0, 7, string);
  flag_d1 = dparse (d1, 9, string);
  *h0 *= flag_h0;
  *h1 *= flag_h1;
  *d0 *= flag_d0;
  *d1 *= flag_d1;

  dparse (&tmp, 2, string);
  *h0 += tmp/60.0;
  dparse (&tmp, 3, string);
  *h0 += tmp/3600.0;
  
  dparse (&tmp, 5, string);
  *h1 += tmp/60.0;
  dparse (&tmp, 6, string);
  *h1 += tmp/3600.0;
  
  dparse (&tmp, 8, string);
  *d0 += tmp/60.0;

  dparse (&tmp, 10, string);
  *d1 += tmp/60.0;

  *h0 *= 15*flag_h0;
  *h1 *= 15*flag_h1;
  *d0 *= flag_d0;
  *d1 *= flag_d1;

  return (TRUE);
}

/***** convert [-]00:00:00 to 0.0000 ****/
int dms_to_ddd (double *Value, char *string) {
  
  int valid, neg, status;
  double tmp, value;
  char *p1, *p2, *px;

  valid = FALSE; 
  neg = FALSE;
  stripwhite (string);
  p1 = string;
  px = string + strlen(string);

  if (string[0] == '-') { 
    valid = TRUE; 
    neg = TRUE;
    p1 = &string[1];
  }
  if (string[0] == '+') { 
    valid = TRUE; 
    neg = FALSE;
    p1 = &string[1];
  }
  if (isdigit(string[0])) { 
    valid = TRUE;
    p1 = &string[0];
  }
  if (!valid) { return (FALSE); }

  status = 1;
  tmp = strtod (p1, &p2);
  if (p2 == p1) return (FALSE); /* entry not a number: +fred */
  value = tmp;
  if (p2 == px) goto escape;    /* entry only number: +1.0 */ 
  p1 = p2 + 1;

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;    /* entry not a number: +1:fred */
  status = 2;
  value += tmp / 60.0;
  if (p2 == px) goto escape;    /* entry only number: +1:1 */
  p1 = p2 + 1;

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;    /* entry not a number: +1:1:fred */
  value += tmp / 3600.0;

 escape:
  if (neg) {
    value *= -1;
  }
  *Value = value;

  return (status);
}

/**********/
int str_to_radec (double *ra, double *dec, char *str1, char *str2) {

  double Ra, Dec;

  *ra = *dec = 0;
  switch (dms_to_ddd (&Ra, str1)) {
  case 0:
    fprintf (stderr, "syntax error in RA\n");
    return (FALSE);
  case 1:
    break;
  case 2:
    Ra = Ra * 15;
    break;
  }
  switch (dms_to_ddd (&Dec, str2)) {
  case 0:
    fprintf (stderr, "syntax error in DEC\n");
    return (FALSE);
  case 1:
  case 2:
    break;
  }
  *ra = Ra;
  *dec = Dec;
  return (TRUE);
}

int hh_hm (double hh, int *hr, double *mn) {

  int flag;

  flag = SIGN(hh);
  hh = fabs (hh);

  *mn = 60.0*(hh - (int)hh);
  *hr = (int) hh;
  *hr *= flag;
  return (TRUE);
}

char *meade_deg_to_str (double deg) {

  int hr;
  double mn;
  char *line;

  ALLOCATE (line, char, 16);

  hh_hm (deg, &hr, &mn);

  sprintf (line, "%03d:%04.1f", abs(hr), mn);
  return (line);
}

char *meade_ra_to_str (double deg) {

  int hr;
  double mn;
  char *line;

  ALLOCATE (line, char, 16);

  hh_hm (deg/15.0, &hr, &mn);

  sprintf (line, "%02d:%04.1f", abs(hr), mn);
  return (line);
}

char *meade_dec_to_str (double deg) {

  int hr;
  double mn;
  char *line;

  ALLOCATE (line, char, 16);

  hh_hm (deg, &hr, &mn);

  if (deg < 0) {
    sprintf (line, "-%02d:%04.1f", abs(hr), mn);
  } else {
    sprintf (line, "+%02d:%04.1f", hr, mn);
  }      
  return (line);
}

/**********/
int chk_time (char *line) {

  char *p1, *p2;
  double tmp;
  int mode;

  p1 = line;
  tmp = strtod (p1, &p2);
  if (p2 == p1 + strlen (p1) - 1) {
    if (*p2 == 'j') {
      mode = TIME_JD;
    }
    if (*p2 == 'J') {
      mode = TIME_MJD;
    }
    if (*p2 == 'd') {
      mode = TIME_DAYS;
    }
    if (*p2 == 'h') {
      mode = TIME_HOURS;
    }
    if (*p2 == 'm') {
      mode = TIME_MINUTES;
    }
    if (*p2 == 's') {
      mode = TIME_SECONDS;
    }
  } else { 
    mode = TIME_DATE;
  }
  return (mode);
}

/**********/
int str_to_time (char *line, time_t *second) {
  
  char *tmpline;
  struct tm *gmt;
  struct timeval now;
  double jd;
  time_t tsec;

  if (!strcasecmp (line, "NOW")) {
    gettimeofday (&now, (struct timezone *) NULL);
    *second = now.tv_sec;
    return (TRUE);
  }
    
  if (!strncasecmp (line, "TODAY", 5)) {
    gettimeofday (&now, (struct timezone *) NULL);
    if (line[5]) { /* line has extra data (ie, hh:mm:ss) */
      tsec = now.tv_sec;
      ALLOCATE (tmpline, char, 64);
      gmt   = gmtime (&tsec);
      sprintf (tmpline, "%04d/%02d/%02d,%s", 
	       1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, &line[6]);
      *second = date_to_sec (tmpline);
      free (tmpline);
      return (TRUE);
    } else {
      *second = 86400 * ((int)(now.tv_sec / 86400));
      return (TRUE); 
    }
  }
    
  switch (chk_time (line)) {
  case 0:
    return (FALSE);
  case TIME_JD:
    jd = strtod (line, 0);
    *second = jd_to_sec (jd);
    return (TRUE);
  case TIME_MJD:
    jd = strtod (line, 0);
    *second = mjd_to_sec (jd);
    return (TRUE);
  case TIME_DATE:
    *second = date_to_sec (line);
    return (TRUE);
  case TIME_DAYS:
    *second = strtod (line, 0) * 86400.0;
    return (TRUE);
  case TIME_HOURS:
    *second = strtod (line, 0) * 3600.0;
    return (TRUE);
  case TIME_MINUTES:
    *second = strtod (line, 0) * 60.0;
    return (TRUE);
  case TIME_SECONDS:
    *second = strtod (line, 0);
    return (TRUE);
  }
  return (FALSE);
}


/**********/
int str_to_dtime (char *line, double *second) {
  
  switch (chk_time (line)) {
  case 0:
  case TIME_JD:
  case TIME_MJD:
  case TIME_DATE:
    return (FALSE);
  case TIME_DAYS:
    *second = strtod (line, 0) * 86400.0;
    return (TRUE);
  case TIME_HOURS:
    *second = strtod (line, 0) * 3600.0;
    return (TRUE);
  case TIME_MINUTES:
    *second = strtod (line, 0) * 60.0;
    return (TRUE);
  case TIME_SECONDS:
    *second = strtod (line, 0);
    return (TRUE);
  }
  return (FALSE);
}

/**********/
double sec_to_jd (time_t second) {

  double jd;
  
  jd = second/86400.0 + 2440587.5;
  return (jd);
}

/**********/
time_t jd_to_sec (double jd) {

  time_t second;

  second = (jd - 2440587.5)*86400;
  return (second);
}

/**********/
double sec_to_mjd (time_t second) {

  double mjd;
  
  mjd = second/86400.0 + 40587.0;
  return (mjd);
}

/**********/
time_t mjd_to_sec (double mjd) {

  time_t second;

  second = (mjd - 40587.0)*86400;
  return (second);
}

/**********/
char *sec_to_date (time_t second) {
  
  struct tm *gmt;
  char *line;
  
  ALLOCATE (line, char, 64);
  gmt   = gmtime (&second);
  sprintf (line, "%04d/%02d/%02d,%02d:%02d:%02d", 
	   1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, 
	   gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
  return (line);

}

/***** date in format yyyy/mm/dd,hh:mm:ss *****/
time_t date_to_sec (char *date) {
  
  time_t second;
  double tmp, jd;
  struct tm now;
  char *p1, *p2, *px;
  
  p1 = date;
  px = date + strlen(date);
  bzero (&now, sizeof(now));

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;
  now.tm_year = tmp;
  if (now.tm_year > 1000) now.tm_year -= 1900;
  if (now.tm_year <   50) now.tm_year += 100;
  if (p2 == px) goto escape;  
  p1 = p2 + 1;

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;
  now.tm_mon = tmp - 1; /* mon runs from 0 - 11 */
  if (p2 == px) goto escape;  
  p1 = p2 + 1;

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;
  now.tm_mday = tmp;
  if (p2 == px) goto escape;  
  p1 = p2 + 1;

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;
  p1 = p2 + 1;
  now.tm_hour = tmp;
  if (p2 == px) goto escape;  

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;
  now.tm_min = tmp;
  if (p2 == px) goto escape;  
  p1 = p2 + 1;

  tmp = strtod (p1, &p2);
  if (p2 == p1) goto escape;
  now.tm_sec = tmp;
  if (p2 == px) goto escape;  
  p1 = p2 + 1;

 escape:
  jd = now.tm_mday - 32075 + (int)(1461*(1900 + now.tm_year + 4800 + (int)(((now.tm_mon+1)-14)/12))/4)
    + (int)(367*((now.tm_mon+1) - 2 - (int)(((now.tm_mon+1) - 14)/12)*12)/12)
    - (int)(3*(int)((1900 + now.tm_year + 4900 + (int)(((now.tm_mon+1) - 14)/12))/100)/4) - 0.5;
  
  second = (jd - 2440587.5)*86400 + 3600.0*now.tm_hour + now.tm_min*60.0 + now.tm_sec;

  return (second);
}

/* convert UNIX time to a value referenced to the TimeReference in the given unit */
double TimeValue (time_t time, time_t TimeReference, int TimeFormat) {

  double value, dt;

  dt = (time > TimeReference) ? (time - TimeReference) : -1 * (double)(TimeReference - time);
  switch (TimeFormat) {
  case TIME_JD:
    value = time / 86400.0 + 2440587.5;
    break;
  case TIME_MJD:
    value = time / 86400.0 + 40587.0;
    break;
  case TIME_DAYS:
    value = dt / 86400.0;
    break;
  case TIME_HOURS:
    value = dt / 3600.0;
    break;
  case TIME_MINUTES:
    value = dt / 60.0;
    break;
  case TIME_SECONDS:
  default:
    value = dt;
    break;
  }
  return (value);
}
  
/* convert time value referenced to the TimeReference in the given unit to UNIX time */
time_t TimeRef (double value, time_t TimeReference, int TimeFormat) {

  int dt;
  time_t time;

  switch (TimeFormat) {
  case TIME_JD:
    time = (value -  2440587.5) * 86400.0;
    return (time);
    break;
  case TIME_MJD:
    time = (value -  40587.0) * 86400.0;
    return (time);
    break;
  case TIME_DAYS:
    dt = value * 86400.0;
    break;
  case TIME_HOURS:
    dt = value * 3600.0;
    break;
  case TIME_MINUTES:
    dt = value * 60.0;
    break;
  case TIME_SECONDS:
  default:
    dt = value;
    break;
  }

  time = TimeReference + dt;
  return (time);
}

/* times may be in forms as:
   20040200450s (N seconds since 1970.0)
   2440900.232j (julian date)
   99/02/23,03:22:18 (date string)
   (separators may be anything except space, +, -)
   99:02:15:12:23:30
   99:02:15:12h23m30s
   */
