# include <ohana.h>
# include <skycalc_internal.h>

/***** 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);
}

# define FORMAT_DAYS    1
# define FORMAT_HOURS   2
# define FORMAT_MINUTES 3
# define FORMAT_SECONDS 4
# define FORMAT_JD      5
# define FORMAT_DATE    6

/**********/
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 == 'd') {
      mode = FORMAT_DAYS;
    }
    if (*p2 == 'h') {
      mode = FORMAT_HOURS;
    }
    if (*p2 == 'm') {
      mode = FORMAT_MINUTES;
    }
    if (*p2 == 's') {
      mode = FORMAT_SECONDS;
    }
    if (*p2 == 'j') {
      mode = FORMAT_JD;
    }
  } else { 
    mode = FORMAT_DATE;
  }
  return (mode);
}

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

  if (!strcasecmp (line, "NOW")) {
    gettimeofday (&now, (struct timezone *) NULL);
    *second = now.tv_sec;
    return (TRUE);
  }
    
  if (!strcasecmp (line, "TODAY")) {
    gettimeofday (&now, (struct timezone *) NULL);
    *second = 86400 * ((int)(now.tv_sec / 86400));
    return (TRUE);
  }
    
  switch (chk_time (line)) {
  case 0:
    return (FALSE);
  case FORMAT_DAYS:
    *second = strtod (line, 0) * 86400.0;
    return (TRUE);
  case FORMAT_HOURS:
    *second = strtod (line, 0) * 3600.0;
    return (TRUE);
  case FORMAT_MINUTES:
    *second = strtod (line, 0) * 60.0;
    return (TRUE);
  case FORMAT_SECONDS:
    *second = strtod (line, 0);
    return (TRUE);
  case FORMAT_JD:
    jd = strtod (line, 0);
    *second = jd_to_sec (jd);
    return (TRUE);
  case FORMAT_DATE:
    *second = date_to_sec (line);
    return (TRUE);
  }
  return (FALSE);
}

/**********/
int str_to_dtime (char *line, double *second) {
  
  switch (chk_time (line)) {
  case 0:
  case FORMAT_JD:
  case FORMAT_DATE:
    return (FALSE);
  case FORMAT_DAYS:
    *second = strtod (line, 0) * 86400.0;
    return (TRUE);
  case FORMAT_HOURS:
    *second = strtod (line, 0) * 3600.0;
    return (TRUE);
  case FORMAT_MINUTES:
    *second = strtod (line, 0) * 60.0;
    return (TRUE);
  case FORMAT_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);
}

/**********/
char *sec_to_date (time_t second) {
  
  struct tm *gmt;
  char *line;
  
  ALLOCATE (line, char, 64);
  gmt   = gmtime (&second);
  sprintf (line, "%4d/%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);
}


/* 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
   */


/* fseek with timeout - 0.5 sec */
int Fseek (FILE *f, long offset, int whence) {

  int status, k;

  status = fseek (f, offset, whence);
  if (status == -1) {
    int k;
    /* fprintf (stderr, "problem seeking position: %d\n", errno); */
    for (k = 0; (k < 10) && ((status = fseek (f, 0, SEEK_SET)) == -1); k++) usleep (50000);
    if (status == -1) {
      /* fprintf (stderr, "ERROR: serious problem seeking position: %d\n", errno); */
      /* clear lock at this point? */
      return (0);
    }
  }
  return (1);
}
