/*
-- This file is  free  software, which  comes  along  with  SmartEiffel. This
-- software  is  distributed  in the hope that it will be useful, but WITHOUT
-- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
-- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You  are  allowed  to  redistribute  it and sell it, alone or as a part of
-- another product.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://SmartEiffel.loria.fr
--
*/
/*
  This file (SmartEiffel/sys/runtime/basic_time.c) is automatically
  included when some external "SmartEiffel" basic_time_* feature is
  used (i.e. in live code).
*/

/* To switch from (or to) C to (from) Eiffel. */
#ifndef TIME_DOUBLE_UNION
#define TIME_DOUBLE_UNION 1
typedef union _time_double_union time_double_union;
union _time_double_union {
  time_t c_mapping;
  EIF_DOUBLE eiffel_mapping;
};
#endif

EIF_DOUBLE _basic_time_time(void) {
  time_double_union tdu;
  tdu.c_mapping = time(NULL);
  return tdu.eiffel_mapping;
}

EIF_DOUBLE basic_time_difftime(EIF_DOUBLE t2, EIF_DOUBLE t1) {
  time_double_union tdu2;
  time_double_union tdu1;
  tdu2.eiffel_mapping = t2;
  tdu1.eiffel_mapping = t1;

  return difftime(tdu2.c_mapping, tdu1.c_mapping);
}

EIF_INTEGER basic_time_getyear(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (((gmtime(&tdu.c_mapping))->tm_year) + 1900);
    }
  else {
    return (((localtime(&(tdu.c_mapping)))->tm_year) + 1900);
  }
}

EIF_INTEGER basic_time_getmonth(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (((gmtime(&(tdu.c_mapping)))->tm_mon) + 1);
  }
  else {
    return (((localtime(&(tdu.c_mapping)))->tm_mon) + 1);
  }
}

EIF_INTEGER basic_time_getday(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (gmtime(&(tdu.c_mapping)))->tm_mday;
    }
  else {
    return (localtime(&(tdu.c_mapping)))->tm_mday;
  }
}

EIF_INTEGER basic_time_gethour(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (gmtime(&(tdu.c_mapping)))->tm_hour;
  }
  else {
    return (localtime(&(tdu.c_mapping)))->tm_hour;
  }
}

EIF_INTEGER basic_time_getminute(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (gmtime(&(tdu.c_mapping)))->tm_min;
  }
  else {
    return (localtime(&(tdu.c_mapping)))->tm_min;
  }
}

EIF_INTEGER basic_time_getsecond(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (gmtime(&(tdu.c_mapping)))->tm_sec;
  }
  else {
    return (localtime(&(tdu.c_mapping)))->tm_sec;
  }
}

EIF_INTEGER basic_time_getwday(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (gmtime(&(tdu.c_mapping)))->tm_wday;
  }
  else {
    return (localtime(&(tdu.c_mapping)))->tm_wday;
  }
}

EIF_INTEGER basic_time_getyday(EIF_DOUBLE t, EIF_INTEGER m) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  if (m == 1) {
    return (gmtime(&(tdu.c_mapping)))->tm_yday;
  }
  else {
    return (localtime(&(tdu.c_mapping)))->tm_yday;
  }
}

EIF_BOOLEAN basic_time_is_summer_time_used(EIF_DOUBLE t) {
  time_double_union tdu;
  tdu.eiffel_mapping = t;
  return (EIF_BOOLEAN)(((localtime(&(tdu.c_mapping)))->tm_isdst) != 0);
}

EIF_DOUBLE basic_time_mktime(EIF_INTEGER year,
			     EIF_INTEGER mon,
			     EIF_INTEGER mday,
			     EIF_INTEGER hour,
			     EIF_INTEGER min,
			     EIF_INTEGER sec) {
  time_double_union tdu;
  static struct tm tm_buf;

  tm_buf.tm_year  = (year - 1900);
  tm_buf.tm_mon   = (mon - 1);
  tm_buf.tm_mday  = mday;
  tm_buf.tm_hour  = hour;
  tm_buf.tm_min   = min;
  tm_buf.tm_sec   = sec;
  tm_buf.tm_isdst = -1;

  tdu.c_mapping = ((time_t)mktime(&tm_buf));
  if (tdu.c_mapping == ((time_t)(-1))) {
    tdu.eiffel_mapping = ((EIF_DOUBLE)(-1));
  }
  return tdu.eiffel_mapping;
}

void basic_time_add_second(EIF_DOUBLE *t, int s) {
  (((time_double_union*)t)->c_mapping) += s;
}
