// temp.c
/********************************************************************************
* Código escrito para intentar encontrar por qué en ciertas localidades existe
* hora de salida de sol pero no la hora de la puesta. Es decir, existe "solin"
* en la tabla astro pero no "solout" en la misma tabla.
*
* Marcos Molina Cano - 22/08/2016
*********************************************************************************/

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libnova/julian_day.h>
#include <libnova/solar.h>
#include <libnova/lunar.h>

// Declaración de funciones que están al acabar el código principal.
int sun_rise_set( time_t *rise, time_t *transit, time_t *set, time_t tref, double lat, double lon);

// Función copiada y modificada de la propia web de la librería libnova.
static void print_date (char *title, struct ln_zonedate *date)
{
  fprintf(stdout, "\n%s\n",title);
//  fprintf(stdout, " Year    : %d\n", date->years);
//  fprintf(stdout, " Month   : %d\n", date->months);
//  fprintf(stdout, " Day     : %d\n", date->days);
//  fprintf(stdout, " Hours   : %d\n", date->hours);
//  fprintf(stdout, " Minutes : %d\n", date->minutes);
//  fprintf(stdout, " Seconds : %f\n", date->seconds);
  fprintf(stdout, "%d-%.2d-%.2d %.2d:%.2d:%.2d\n", date->years, date->months, date->days, date->hours, date->minutes, (int)date->seconds);
}

int main(int argc, char const *argv[]){
  int i, dias;
  double lat = 34.2734;
  double lon = -83.8982;
  time_t start, tref, rise, transit, set;
  struct tm sta, starttm, rise_tm, transit_tm, set_tm, rise_tm_local, transit_tm_local, set_tm_local;
  int ano, mes, dia;
  char fecha[] = "20160902"; // Fecha de la cual se calcula la puesta, cénit y ocaso del sol.
  char rise_char[50], set_char[50], transit_char[50], auxfecha[50];
  char rise_char_local[50], set_char_local[50], transit_char_local[50];
  char zoneinfo[] = ":America/New_York";

  // cambiamos a zona UTC.
  setenv("TZ", ":UTC", 1);
  tzset();

  // Paso la fecha a hora unix.
  memset(&sta, 0, sizeof (struct tm));
  strptime(fecha, "%Y%m%d", &sta);
  start = mktime(&sta);
  gmtime_r(&start, &starttm);
  strftime(auxfecha, 50, "\"%Y:%m:%d %H:%M:%S\"", &starttm);
  printf("%s\n\n", auxfecha);
//  printf("La fecha es: %s\n", fecha);
//  printf("%li\n", start);

  dias = 2;
  for (i = -dias; i <= dias ; i++) {
    sun_rise_set( &rise, &transit, &set, start + i*86400, lat, lon);
//    printf("rise    = %li \n", rise);
//    printf("transit = %li \n", transit);
//    printf("set     = %li \n", set);

    // Cambiamos a la zona horaria del lugar a estudiar.
    setenv("TZ", ":America/New_York", 1);
    tzset();

    // Transformo los valores de rise, transit y set que están en formato time_t a formato struct tm.
    gmtime_r(&rise, &rise_tm);
    gmtime_r(&transit, &transit_tm);
    gmtime_r(&set, &set_tm);
    localtime_r(&rise, &rise_tm_local);
    localtime_r(&transit, &transit_tm_local);
    localtime_r(&set, &set_tm_local);

    // Devuelvo a zona horaria UTC.
    setenv("TZ", ":UTC", 1);
    tzset();

    strftime (rise_char, sizeof(rise_char), "%Y-%m-%d %H:%M:%S", &rise_tm );
    strftime (transit_char, sizeof(transit_char), "%Y-%m-%d %H:%M:%S", &transit_tm );
    strftime (set_char, sizeof(set_char), "%Y-%m-%d %H:%M:%S", &set_tm );
    strftime (rise_char_local, sizeof(rise_char_local), "%Y-%m-%d %H:%M:%S", &rise_tm_local );
    strftime (transit_char_local, sizeof(transit_char_local), "%Y-%m-%d %H:%M:%S", &transit_tm_local );
    strftime (set_char_local, sizeof(rise_char_local), "%Y-%m-%d %H:%M:%S", &set_tm_local );
    printf("Salida del sol = %s UTC = %s EDT\n", rise_char, rise_char_local);
    printf("Cénit del sol  = %s UTC = %s EDT\n", transit_char, transit_char_local);
    printf("Puesta del sol = %s UTC = %s EDT\n\n", set_char, set_char_local);
  }

  // Devolvemos a la zona horaria apropiada de la máquina.
  setenv("TZ", ":Europe/Madrid", 1);
  tzset();

  /* Prueba para comprobar si introduciendo la hora local podemos obtener el segundo sunset del día. */
  struct ln_zonedate fecha_local, fecha_local_rise, fecha_local_transit, fecha_local_set;
  struct ln_lnlat_posn punto;
  double JD, disk, disk2, phase, phase2;
  struct ln_rst_time rst;

  // Cambiamos a la zona horaria del lugar a estudiar.
  setenv("TZ", ":America/New_York", 1);
  tzset();

  // Declaración de la hora local y su desfase.
  fecha_local.years   = 2016;
  fecha_local.months  = 9;
  fecha_local.days    = 2;
  fecha_local.hours   = 12;
  fecha_local.minutes = 0;
  fecha_local.seconds = 0.0;
  fecha_local.gmtoff  = -14400;

  // Definición del punto cuya salida y puesta de Sol queremos obtener.
  punto.lat = lat;
  punto.lng = lon;

  // Convertimos la hora local en Julian Day.
  JD = ln_get_julian_local_date( &fecha_local );

  // Obtenemos la salida, cénit y puesta del sol en formato de día juliano.
  ln_get_solar_rst(JD, &punto, &rst);

  // Pasamos los días julianos de los fenómenos obtenidos a fecha local y escribimos en pantalla.
  ln_get_local_date(rst.rise, &fecha_local_rise);
  ln_get_local_date(rst.transit, &fecha_local_transit);
  ln_get_local_date(rst.set, &fecha_local_set);
  print_date("Rise", &fecha_local_rise);
  print_date("Transit", &fecha_local_transit);
  print_date("Set", &fecha_local_set);

  /* Estudio de la fase lunar y su porcentaje de iluminación. */
  for (i = 1; i < 31; i++) {

    /* Declaración de la hora local y su desfase. */
    fecha_local.years = 2016;
    fecha_local.months = 9;
    fecha_local.days = i;
    fecha_local.hours = 0;
    fecha_local.minutes = 0;
    fecha_local.seconds = 0.0;
    fecha_local.gmtoff = -14400;

    /* Convertimos la hora local en Julian Day. */
    JD = ln_get_julian_local_date( &fecha_local );

    /* Calculamos la fracción del disco lunar iluminado */
    disk = ln_get_lunar_disk(JD);
    disk2 = ln_get_lunar_disk(JD + 0.01);

    /* Calcula la fase de la luna */
    phase = ln_get_lunar_phase(JD);
    phase2 = ln_get_lunar_phase(JD);
    if (disk2 > disk)
      phase2 = 360.0 - phase;

    /* Mostramos los resultados por pantalla */
    printf("Julian Day (JD) = %f | disk = %f | disk2 = %f | phase = %10f | phase2 = %10f\n", JD, disk, disk2, phase, phase2);
  }

  // Devolvemos a la zona horaria apropiada de la máquina.
  setenv("TZ", ":Europe/Madrid", 1);
  tzset();
};



/* Función usada por Guillermo */
/*!
  \fn int sun_rise_set(time_t *rise, time_t *transit, time_t *set, time_t tref, double lat, double lon)
  \brief calcula la hora del orto, mediodía y ocaso desde una hora y posición de referencia
  \param rise puntero a instante unix donde se escribe la hora del orto
  \param transit puntero a instante unix donde se escribe la hora del mediodia
  \param set puntero a instante unix donde se escribe la hora del ocaso
  \param tref instate de tiempo Unix de referencia
  \param lat latitud del punto, en grados
  \param lon longitud del punto, en grados

  Si no se pone o no sale el sol se devuelve \ref METEO_FAILURE en otro caso \ref METEO_SUCCESS
*/
int sun_rise_set ( time_t *rise, time_t *transit, time_t *set, time_t tref, double lat, double lon )
{
    double JD;
    time_t t;
    struct ln_lnlat_posn observer;
    struct ln_rst_time rst;

    observer.lat = lat;
    observer.lng = lon;
    t = tref;

    /* Pasa la fecha a formato libnova y obtiene JD*/
    JD = ln_get_julian_from_timet ( &t );

    /* calcula el orto mediodia y ocaso */
    if ( ln_get_solar_rst ( JD, &observer, &rst ) == 1 )
        return -1; // el sol no se pone o no sale
    else
    {
        ln_get_timet_from_julian ( rst.rise, rise );
        ln_get_timet_from_julian ( rst.transit, transit );
        ln_get_timet_from_julian ( rst.set, set );
    }
    return 0;
}
