/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
 *
 * Copyright 2024, 2025 GNOME Foundation, Inc.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Authors:
 *  - Philip Withnall <pwithnall@gnome.org>
 */

#include "config.h"

#include <glib.h>
#include <libmalcontent-timer/time-span.h>
#include <stdint.h>


/**
 * MctTimeSpan:
 *
 * A time span representing an interval of one second or longer.
 *
 * Times are stored as Unix timestamps, without timezone data.
 *
 * The span is inclusive of its start and end time, and the end time may be
 * equal to the start time. Formally (in
 * [ISO 31-11 notation](https://en.wikipedia.org/wiki/Interval_(mathematics)#Including_or_excluding_endpoints)),
 * the span is `[start, end]`. If the end time is equal to the start time, the
 * span is one second long; this is the shortest representable span.
 *
 * Since: 0.14.0
 */

struct _MctTimeSpan
{
  uint64_t start_time_secs;
  uint64_t end_time_secs;  /* >= start_time_secs */
};

/**
 * mct_time_span_new:
 * @start_time_secs: start (inclusive) of the time span, as a Unix timestamp
 * @end_time_secs: end (inclusive) of the time span, as a Unix timestamp
 *
 * Create a new [struct@MalcontentTimer.TimeSpan].
 *
 * The end time must not be before the start time.
 *
 * Returns: (transfer full): a new [struct@MalcontentTimer.TimeSpan]
 * Since: 0.14.0
 */
MctTimeSpan *
mct_time_span_new (uint64_t start_time_secs,
                   uint64_t end_time_secs)
{
  g_autoptr(MctTimeSpan) span = NULL;

  g_return_val_if_fail (start_time_secs < end_time_secs, NULL);

  span = g_new0 (MctTimeSpan, 1);
  span->start_time_secs = start_time_secs;
  span->end_time_secs = end_time_secs;
  return g_steal_pointer (&span);
}

/**
 * mct_time_span_free:
 * @self: (transfer full): a time span
 *
 * Free the given [struct@MalcontentTimer.TimeSpan].
 *
 * Since: 0.14.0
 */
void
mct_time_span_free (MctTimeSpan *self)
{
  g_return_if_fail (self != NULL);

  g_free (self);
}

/**
 * mct_time_span_copy:
 * @self: a time span
 *
 * Copy the given time span.
 *
 * Returns: (transfer full): a copy of @self
 * Since: 0.14.0
 */
MctTimeSpan *
mct_time_span_copy (const MctTimeSpan *self)
{
  g_return_val_if_fail (self != NULL, NULL);

  return mct_time_span_new (self->start_time_secs,
                            self->end_time_secs);
}

/**
 * mct_time_span_compare:
 * @self: a time span
 * @other: another time span
 *
 * Compare two time spans to give a total order.
 *
 * If the time spans are identical, `0` is returned.
 *
 * Otherwise, their start times are compared and `-1` is returned is @self comes
 * before @other; `1` is returned if @self comes after @other.
 *
 * If their start times are equal, their end times are compared and `-1` or `1`
 * is returned depending on whether the end time of @self comes before or after
 * the end time of @other.
 *
 * Returns: an integer representing the total order of @self and @other, with
 *   similar semantics to [`strcmp()`](man:strcmp(3))
 * Since: 0.14.0
 */
int
mct_time_span_compare (const MctTimeSpan *self,
                       const MctTimeSpan *other)
{
  g_return_val_if_fail (self != NULL, 0);
  g_return_val_if_fail (other != NULL, 0);

  /* We can’t do the normal (a - b) trick here because the members of
   * MctTimeSpan are uint64_t, but the return value is only a 32-bit signed int. */
  if (self->start_time_secs != other->start_time_secs)
    return (self->start_time_secs < other->start_time_secs) ? -1 : 1;

  if (self->end_time_secs != other->end_time_secs)
    return (self->end_time_secs < other->end_time_secs) ? -1 : 1;

  return 0;
}

/**
 * mct_time_span_get_start_time_secs:
 * @self: an [struct@MalcontentTimer.TimeSpan]
 *
 * Get the start time of the time span.
 *
 * This is included in the time span.
 *
 * Returns: start time of the time span, as a Unix timestamp
 * Since: 0.14.0
 */
uint64_t
mct_time_span_get_start_time_secs (const MctTimeSpan *self)
{
  g_return_val_if_fail (self != NULL, 0);

  return self->start_time_secs;
}

/**
 * mct_time_span_get_end_time_secs:
 * @self: an [struct@MalcontentTimer.TimeSpan]
 *
 * Get the end time of the time span.
 *
 * This is included in the time span.
 *
 * Returns: end time of the time span, as a Unix timestamp
 * Since: 0.14.0
 */
uint64_t
mct_time_span_get_end_time_secs (const MctTimeSpan *self)
{
  g_return_val_if_fail (self != NULL, 0);

  return self->end_time_secs;
}
