/* time difference objects and functions, for libreswan
 *
 * Copyright (C) 1998, 1999, 2000  Henry Spencer.
 * Copyright (C) 1999, 2000, 2001  Richard Guy Briggs
 * Copyright (C) 2018 Andrew Cagney
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  See <https://www.gnu.org/licenses/lgpl-2.1.txt>.
 *
 * This library 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 Library General Public
 * License for more details.
 *
 */

#ifndef DELTATIME_H
#define DELTATIME_H    /* seen it, no need to see it again */

#include <time.h>		/* for time_t */
#include <sys/time.h>		/* for struct timeval */
#include <stdint.h>		/* for intmax_t */
#include <stdbool.h>		/* for bool */

#include "diag.h"
#include "shunk.h"

struct jambuf;
struct timescale;

/*
 * deltatime_t: relative time between events.  Presumed continuous.
 *
 * A struct initializer for an object of static storage duration
 * cannot include a compound literal (or a function call).
 * DELTATIME_INIT is suitable for a struct initializer.
 * It's optional in an initializer for an object of automatic storage duration.
 * Because it lacks the cast, this macro should not be used in other contexts.
 * Sigh.
 */

typedef struct { struct timeval dt; } deltatime_t;

extern const deltatime_t deltatime_zero;

#define DELTATIME_INIT(S) { .dt = { .tv_sec = (S), } }

deltatime_t deltatime(time_t secs);
deltatime_t deltatime_ms(intmax_t milliseconds);

/* for monotime(a-b) and realtime(a-b) */
deltatime_t deltatime_timevals_diff(struct timeval l, struct timeval r);

/* sign(a - b); see timercmp() for hacks origin */
int deltatime_sub_sign(deltatime_t l, deltatime_t r);
#define deltatime_cmp(L, OP, R) (deltatime_sub_sign(L, R) OP 0)

/* max(a, b) */
deltatime_t deltatime_max(deltatime_t a, deltatime_t b);

/* a+b */
deltatime_t deltatime_add(deltatime_t a, deltatime_t b);

/* a-b */
deltatime_t deltatime_sub(deltatime_t a, deltatime_t b);

/* a*s */
deltatime_t deltatime_mulu(deltatime_t a, unsigned scalar);

/* a/s */
deltatime_t deltatime_divu(deltatime_t a, unsigned scalar);

intmax_t deltamillisecs(deltatime_t d);
intmax_t deltasecs(deltatime_t d);
deltatime_t deltatime_scale(deltatime_t d, int num, int denom);

/* Convert to/from struct timeval - time used by libevent. */
struct timeval timeval_from_deltatime(deltatime_t);
deltatime_t deltatime_from_timeval(const struct timeval a);

/* output as "smart" seconds */

typedef struct {
	/* slightly over size */
	char buf[sizeof("-18446744073709551615.1000000")+1/*canary*/]; /* true length ???? */
} deltatime_buf;

const char *str_deltatime(deltatime_t d, deltatime_buf *buf);
size_t jam_deltatime(struct jambuf *buf, deltatime_t d);

diag_t ttodeltatime(const char *t, deltatime_t *d, const struct timescale *default_scale);

/* primitives used to implement times. */

struct timeval timeval_ms(intmax_t milliseconds);
/* for *time_cmp(): sign(l-r) */
int timeval_sub_sign(struct timeval l, struct timeval r);

#endif
