// SPDX-License-Identifier: ISC

#include <libbasis/misc.h>
#include <libbasis/timespec.h>

bool timespec_is_less(const struct timespec *lhs, const struct timespec *rhs)
{
	if (lhs->tv_sec < rhs->tv_sec)
		return true;
	if (lhs->tv_sec > rhs->tv_sec)
		return false;
	return lhs->tv_nsec < rhs->tv_nsec;
}

bool timespec_add(struct timespec *out, const struct timespec *lhs,
		  const struct timespec *rhs)
{
	out->tv_sec = lhs->tv_sec + rhs->tv_sec;
	out->tv_nsec = lhs->tv_nsec + rhs->tv_nsec;

	if (out->tv_nsec >= NSEC_PER_SEC) {
		out->tv_sec++;
		out->tv_nsec -= NSEC_PER_SEC;
	}

	return true;
}

bool timespec_add_msec(struct timespec *out, const struct timespec *lhs,
		       unsigned long add_msec)
{
	struct timespec add;

	add.tv_sec = add_msec / MSEC_PER_SEC;
	add.tv_nsec = (add_msec % MSEC_PER_SEC) * (NSEC_PER_SEC / MSEC_PER_SEC);

	return timespec_add(out, lhs, &add);
}

bool timespec_sub(struct timespec *out, const struct timespec *lhs,
		  const struct timespec *rhs)
{
	if (lhs->tv_sec < rhs->tv_sec)
		return false;
	if (lhs->tv_sec == rhs->tv_sec &&
	    lhs->tv_nsec < rhs->tv_nsec)
		return false;

	out->tv_sec = lhs->tv_sec - rhs->tv_sec;
	out->tv_nsec = lhs->tv_nsec - rhs->tv_nsec;

	if (out->tv_nsec < 0) {
		out->tv_sec--;
		out->tv_nsec += NSEC_PER_SEC;
	}

	return true;
}

unsigned long timespec_to_msec(const struct timespec *ts)
{
	unsigned long msec;

	msec = ts->tv_sec;
	msec *= 1000;
	msec += ts->tv_nsec / (NSEC_PER_SEC / MSEC_PER_SEC);

	return msec;
}