/*
 * when.c:
 *
 * Copyright (c) 2000 James McKenzie <james@fishsoup.dhs.org>,
 * All rights reserved.
 *
 */

static char rcsid[] =
  "$Id: when.c,v 1.13 2001/10/12 13:51:16 root Exp root $";

/*
 * $Log: when.c,v $
 * Revision 1.13  2001/10/12 13:51:16  root
 * #
 *
 * Revision 1.12  2001/01/30 06:16:27  root
 * #
 *
 * Revision 1.11  2000/12/01 04:42:14  root
 * #
 *
 * Revision 1.10  2000/12/01 04:13:48  root
 * #
 *
 * Revision 1.9  2000/11/23 23:45:24  root
 * #
 *
 * Revision 1.8  2000/10/07 18:30:08  root
 * #
 *
 * Revision 1.7  2000/10/06 19:52:21  root
 * #
 *
 * Revision 1.6  2000/09/24 01:48:14  root
 * #
 *
 * Revision 1.5  2000/09/24 01:46:06  root
 * #
 *
 * Revision 1.4  2000/09/24 01:12:49  root
 * #
 *
 * Revision 1.3  2000/09/03 03:21:53  root
 * #
 *
 * Revision 1.1  2000/09/03 02:03:28  root
 * #
 *
 * Revision 1.2  2000/09/02 17:15:27  root
 * #
 *
 * Revision 1.1  2000/09/02 17:14:58  root
 * #
 *
 */

#include "project.h"



int
El_inlist (El_list l, int i)
{
  El e;

  if (!l)
    return 1;
  if (!l->head)
    return 1;

  e = l->head;
  while (e)
    {

      if (e->v == i)
        return 1;
      e = e->next;
    }
  return 0;
}

void
El_add (El_list l, int i)
{
  El e = CREATE_OBJ (El);

  e->v = i;

  Obj_Insert (l, e, ObjInsertTail);
}



void
When_creator (When w)
{
  w->day = CREATE_LIST (El);
  w->weekday = CREATE_LIST (El);
  w->hour = CREATE_LIST (El);
  w->min = CREATE_LIST (El);
  w->sec = CREATE_LIST (El);
  w->usec = CREATE_LIST (El);

}

void
When_destructor (When w)
{
  Obj_Delete (w->day);
  Obj_Delete (w->weekday);
  Obj_Delete (w->hour);
  Obj_Delete (w->min);
  Obj_Delete (w->sec);
  Obj_Delete (w->usec);


  free (w);
}

Daytime timeval_to_daytime (struct timeval tv)
{
  Daytime r;
  time_t t;
  struct tm tm;

  t = (time_t) tv.tv_sec;
  localtime_r (&t, &tm);

  r.usec = tv.tv_usec;
  r.sec = tm.tm_sec;
  r.min = tm.tm_min;
  r.hour = tm.tm_hour;
  r.weekday = tm.tm_wday;
  r.day = tm.tm_mday;
  r.month = tm.tm_mon;
  r.year = tm.tm_year + 1900;

  return r;
}

Daytime now (void)
{
  Daytime r;
  struct timeval tv;
  time_t t;
  struct tm tm;

  gettimeofday (&tv, NULL);
  t = (time_t) tv.tv_sec;
  localtime_r (&t, &tm);

  r.usec = tv.tv_usec;
  r.sec = tm.tm_sec;
  r.min = tm.tm_min;
  r.hour = tm.tm_hour;
  r.weekday = tm.tm_wday;
  r.day = tm.tm_mday;
  r.month = tm.tm_mon;
  r.year = tm.tm_year + 1900;

  return r;
}


void
dt_add (Daytime * dt, int secs)
{
  struct tm tm;
  time_t t;

//printf("%s Add %d",timeval_to_asc(timeval_from_daytime(*dt)),secs);


  time (&t);
  localtime_r (&t, &tm);

  tm.tm_sec = dt->sec;
  tm.tm_min = dt->min;
  tm.tm_hour = dt->hour;
  tm.tm_mday = dt->day;
  tm.tm_mon = dt->month;
  tm.tm_year = dt->year - 1900;

  t = mktime (&tm);
  t += secs;


  localtime_r (&t, &tm);

  dt->sec = tm.tm_sec;
  dt->min = tm.tm_min;
  dt->hour = tm.tm_hour;
  dt->weekday = tm.tm_wday;
  dt->day = tm.tm_mday;
  dt->month = tm.tm_mon;
  dt->year = tm.tm_year + 1900;

//printf("%s\n",timeval_to_asc(timeval_from_daytime(*dt)));

}
struct timeval
timeval_from_daytime (Daytime dt)
{
  struct tm tm;
  struct timeval ret;
  time_t t;

  time (&t);
  localtime_r (&t, &tm);

  tm.tm_sec = dt.sec;
  tm.tm_min = dt.min;
  tm.tm_hour = dt.hour;
  tm.tm_mday = dt.day;
  tm.tm_mon = dt.month;
  tm.tm_year = dt.year - 1900;

  t = mktime (&tm);
  ret.tv_sec = t;
  ret.tv_usec = dt.usec;
  localtime_r (&t, &tm);

//printf("Brain check %d %d\n",dt.hour,tm.tm_hour);

  return ret;
}


struct timeval
nearest_when (When w)
{
  int days;
  Daytime dt = now ();


  while (1)
    {

      if (El_inlist (w->day, dt.day) && El_inlist (w->weekday, dt.weekday))
        {
          if (El_inlist (w->hour, dt.hour))
            {
              if (El_inlist (w->min, dt.min))
                {
                  if (El_inlist (w->sec, dt.sec))
                    {
                      if (El_inlist (w->usec, dt.usec))
                        {
                          return (timeval_from_daytime (dt));
                        }
                      else
                        {
                          El d, e = w->usec->head;
                          int dv = 1000000;

                          d = NULL;
                          while (e)
                            {
                              int q = e->v - dt.usec;

                              if ((q >= 0) && (q < dv))
                                {
                                  d = e;
                                  dv = q;
                                }
                              e = e->next;
                            }

                          if (d)
                            {
                              dt.usec = d->v;
                            }
                          else
                            {
                              dt.usec = w->usec->head->v;
                              dt_add (&dt, DT_SEC);
                            }
                        }
                    }
                  else
                    {
                      dt.usec = 0;
                      dt_add (&dt, DT_SEC);
                    }
                }
              else
                {
                  dt.sec = dt.usec = 0;
                  dt_add (&dt, DT_MIN);
                }
            }
          else
            {
              dt.min = dt.sec = dt.usec = 0;
              dt_add (&dt, DT_HOUR);
            }
        }
      else
        {
          dt.hour = dt.min = dt.sec = dt.usec = 0;
          dt_add (&dt, DT_DAY);
        }
    }

}

void
Fill_when (When w)
{
  w->tv = nearest_when (w);
}

void
Fill_whens (When_list l)
{

  When w = l->head;

  while (w)
    {
      Fill_when (w);
      w = w->next;
    }

}

void
Resort_whens (When_list l)
{
  When_list o = CREATE_LIST (When);
  When w, d;
  struct timeval dt;


  while ((w = l->head))
    {
      d = NULL;
      timerclear (&dt);
      while (w)
        {
          if (timercmp (&(w->tv), &dt, >))
            {
              dt = w->tv;
              d = w;
            }
          w = w->next;
        }

      Obj_Remove (l, d);
      Obj_Insert (o, d, ObjInsertHead);
    }


  l->head = o->head;
  l->tail = o->tail;

  o->head = o->tail = NULL;

  Obj_Delete (o);

}
