/*
** Copyright (C) 2000 by Kevin L. Mitchell <klmitch@mit.edu>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**
** @(#)$Id: timer_add.c,v 1.1 2000/12/10 05:17:15 klmitch Exp $
*/
#include "timer.h"
#include "timer_int.h"
#include "rcstag.h"

RCSTAG("@(#)$Id: timer_add.c,v 1.1 2000/12/10 05:17:15 klmitch Exp $");

_s_ul
timer_add(timer *atimer, timer_val *time, _s_us type)
{
  _s_ul retval;

  type &= TIMER_TYPE_MASK; /* not allowed to set other flags */

  if (!timer_verify(atimer) || !time || !type)
    return TIMER_ERR_BADARGS; /* check for invalid arguments */

  if (atimer->t_flag & TIMER_ACTIVE) /* timer is active... */
    return TIMER_ERR_ACTIVE;

  if ((type & TIMER_INTERVAL) && (type & TIMER_ABSOLUTE))
    return TIMER_ERR_EXCLUSION; /* must be one or the other */

  if ((type & TIMER_ABSOLUTE) && (type & TIMER_REPEAT))
    return TIMER_ERR_REPEAT; /* can't repeat absolute timers */

  atimer->t_flag = type; /* store type... */
  atimer->t_time = *time; /* structure copy */

  if (type & TIMER_ABSOLUTE) /* store time */
    atimer->t_call = *time; /* call us at exactly the specified time */
  else if ((retval = _timer_set_call(atimer, 0))) /* it's relative... */
    return retval;

  return _timer_add(atimer); /* ok, add timer to list */
}

_s_ul
_timer_add(timer *atimer)
{
  timer **ptr_p;

  for (ptr_p = &timers; ; ptr_p = &(*ptr_p)->t_next)
    /* if we've reached the end of the list, or if we're before or at
     * the same time as the timer we're examining, insert here.
     */
    if (!*ptr_p || atimer->t_call.t_sec < (*ptr_p)->t_call.t_sec ||
	(atimer->t_call.t_sec == (*ptr_p)->t_call.t_sec &&
	 atimer->t_call.t_nsec <= (*ptr_p)->t_call.t_nsec))
      break;

  atimer->t_next = *ptr_p; /* link it in in the right place */
  atimer->t_prev_p = ptr_p; /* this will be pointing to us */
  if (*ptr_p)
    (*ptr_p)->t_prev_p = &atimer->t_next;
  *ptr_p = atimer;

  atimer->t_flag |= TIMER_ACTIVE;

  return 0; /* convenience return */
}
