/* timestamp.c generated by valac 0.56.19, the Vala compiler
 * generated from timestamp.vala, do not modify */

/*
 * Copyright (c) 2021-2025 focus-timer contributors
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
/* TODO: move to interval.vala*/

#include "ft_core.h"
#include <glib.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gi18n-lib.h>

#if !defined(VALA_STRICT_C)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
#elif defined(__clang__) && (__clang_major__ >= 16)
#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#endif
#endif

#define _g_string_free0(var) ((var == NULL) ? NULL : (var = (g_string_free (var, TRUE), NULL)))
#define _g_date_time_unref0(var) ((var == NULL) ? NULL : (var = (g_date_time_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))
#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);

VALA_EXTERN gint64 ft_timestamp_current_time;
gint64 ft_timestamp_current_time = FT_TIMESTAMP_UNDEFINED;
VALA_EXTERN gint64 ft_timestamp_advance_by;
gint64 ft_timestamp_advance_by = (gint64) 0;

static inline gpointer _vala_memdup2 (gconstpointer mem,
                        gsize byte_size);

gint64
ft_interval_from_value (gint value,
                        gint64 unit)
{
	gint64 result;
	result = unit * value;
	return result;
}

gint64
ft_interval_from_seconds (gdouble seconds)
{
	gint64 result;
	result = (gint64) floor (seconds * ((gdouble) FT_INTERVAL_SECOND));
	return result;
}

gint64
ft_interval_add (gint64 interval,
                 gint64 other)
{
	gint64 result;
	if (other > ((gint64) 0)) {
		gint64 _tmp0_ = 0LL;
		if (interval < (FT_INTERVAL_MAX - other)) {
			_tmp0_ = interval + other;
		} else {
			_tmp0_ = FT_INTERVAL_MAX;
		}
		result = _tmp0_;
		return result;
	} else {
		gint64 _tmp1_ = 0LL;
		if (interval > (FT_INTERVAL_MIN - other)) {
			_tmp1_ = interval + other;
		} else {
			_tmp1_ = FT_INTERVAL_MIN;
		}
		result = _tmp1_;
		return result;
	}
}

gint64
ft_interval_subtract (gint64 interval,
                      gint64 other)
{
	gint64 result;
	result = ft_interval_add (interval, -other);
	return result;
}

gint64
ft_interval_round (gint64 interval,
                   gint64 unit)
{
	gint64 unit_half = 0LL;
	gint64 remainder = 0LL;
	gint64 result;
	unit_half = unit / 2;
	remainder = interval % unit;
	if (remainder > unit_half) {
		result = (interval - remainder) + unit;
		return result;
	}
	if (remainder < (-unit_half)) {
		result = (interval - remainder) - unit;
		return result;
	}
	result = interval - remainder;
	return result;
}

gint64
ft_interval_round_seconds (gint64 interval)
{
	gint64 result;
	result = ft_interval_round (interval, FT_INTERVAL_SECOND);
	return result;
}

gdouble
ft_interval_to_seconds (gint64 interval)
{
	gdouble result;
	result = ((gdouble) interval) / ((gdouble) FT_INTERVAL_SECOND);
	return result;
}

gchar*
ft_interval_format_short (gint64 interval,
                          gint64 unit)
{
	gint seconds = 0;
	gint hours = 0;
	gint minutes = 0;
	gboolean show_hours = FALSE;
	gboolean show_minutes = FALSE;
	GString* _result_ = NULL;
	GString* _tmp0_;
	gboolean _tmp3_ = FALSE;
	GString* _tmp6_;
	const gchar* _tmp7_;
	gchar* _tmp8_;
	gchar* result;
	seconds = (gint) (interval / FT_INTERVAL_SECOND);
	hours = 0;
	minutes = 0;
	show_hours = FALSE;
	show_minutes = FALSE;
	_tmp0_ = g_string_new ("");
	_result_ = _tmp0_;
	if (unit == FT_INTERVAL_HOUR) {
		hours = seconds / 3600;
		show_hours = TRUE;
	} else {
		if (unit == FT_INTERVAL_MINUTE) {
			minutes = seconds / 60;
			show_minutes = TRUE;
		} else {
			gboolean _tmp1_ = FALSE;
			hours = seconds / 3600;
			if (hours < 0) {
				seconds = abs (seconds);
			}
			minutes = (seconds % 3600) / 60;
			show_hours = hours != 0;
			if (minutes != 0) {
				_tmp1_ = TRUE;
			} else {
				_tmp1_ = hours == 0;
			}
			show_minutes = _tmp1_;
		}
	}
	if (show_hours) {
		GString* _tmp2_;
		_tmp2_ = _result_;
		g_string_append_printf (_tmp2_, _ ("%uh"), hours);
	}
	if (show_hours) {
		_tmp3_ = show_minutes;
	} else {
		_tmp3_ = FALSE;
	}
	if (_tmp3_) {
		GString* _tmp4_;
		_tmp4_ = _result_;
		g_string_append (_tmp4_, "\u00A0");
	}
	if (show_minutes) {
		GString* _tmp5_;
		_tmp5_ = _result_;
		g_string_append_printf (_tmp5_, _ ("%um"), minutes);
	}
	_tmp6_ = _result_;
	_tmp7_ = _tmp6_->str;
	_tmp8_ = g_strdup (_tmp7_);
	result = _tmp8_;
	_g_string_free0 (_result_);
	return result;
}

gint64
ft_timestamp_from_now (void)
{
	gint64 result;
	if (ft_timestamp_current_time >= ((gint64) 0)) {
		gint64 tmp = 0LL;
		tmp = ft_timestamp_current_time;
		ft_timestamp_current_time = ft_timestamp_current_time + ft_timestamp_advance_by;
		result = tmp;
		return result;
	}
	result = g_get_real_time ();
	return result;
}

gint64
ft_timestamp_from_seconds (gdouble seconds)
{
	gint64 result;
	result = (gint64) round (seconds * ((gdouble) FT_INTERVAL_SECOND));
	return result;
}

gint64
ft_timestamp_from_seconds_uint (guint seconds)
{
	gint64 result;
	result = ((gint64) seconds) * FT_INTERVAL_SECOND;
	return result;
}

gint64
ft_timestamp_from_milliseconds_uint (guint milliseconds)
{
	gint64 result;
	result = ((gint64) milliseconds) * FT_INTERVAL_MILLISECOND;
	return result;
}

gint64
ft_timestamp_from_iso8601 (const gchar* text)
{
	GDateTime* datetime = NULL;
	GDateTime* _tmp0_;
	gint64 _tmp1_ = 0LL;
	GDateTime* _tmp2_;
	gint64 result;
	g_return_val_if_fail (text != NULL, -1LL);
	_tmp0_ = g_date_time_new_from_iso8601 (text, NULL);
	datetime = _tmp0_;
	_tmp2_ = datetime;
	if (_tmp2_ != NULL) {
		GDateTime* _tmp3_;
		GDateTime* _tmp4_;
		_tmp3_ = datetime;
		_tmp4_ = datetime;
		_tmp1_ = (g_date_time_to_unix (_tmp3_) * FT_INTERVAL_SECOND) + g_date_time_get_microsecond (_tmp4_);
	} else {
		_tmp1_ = FT_TIMESTAMP_UNDEFINED;
	}
	result = _tmp1_;
	_g_date_time_unref0 (datetime);
	return result;
}

gint64
ft_timestamp_from_datetime (GDateTime* datetime)
{
	gint64 result;
	g_return_val_if_fail (datetime != NULL, -1LL);
	result = g_date_time_to_unix (datetime) * FT_INTERVAL_SECOND;
	return result;
}

gdouble
ft_timestamp_to_seconds (gint64 timestamp)
{
	gdouble result;
	result = ((gdouble) timestamp) / ((gdouble) FT_INTERVAL_SECOND);
	return result;
}

guint
ft_timestamp_to_seconds_uint (gint64 timestamp)
{
	guint result;
	result = (guint) CLAMP (timestamp / FT_INTERVAL_SECOND, (gint64) 0, (gint64) G_MAXUINT);
	return result;
}

guint
ft_timestamp_to_seconds_uint32 (gint64 timestamp)
{
	guint result;
	result = (guint) ((guint32) CLAMP (timestamp / FT_INTERVAL_SECOND, (gint64) 0, (gint64) G_MAXUINT32));
	return result;
}

gdouble
ft_timestamp_to_milliseconds (gint64 timestamp)
{
	gdouble result;
	result = ((gdouble) timestamp) / ((gdouble) FT_INTERVAL_MILLISECOND);
	return result;
}

guint
ft_timestamp_to_milliseconds_uint (gint64 timestamp)
{
	guint result;
	result = (guint) CLAMP (timestamp / FT_INTERVAL_MILLISECOND, (gint64) 0, (gint64) G_MAXUINT);
	return result;
}

GDateTime*
ft_timestamp_to_datetime (gint64 timestamp,
                          GTimeZone* timezone)
{
	GDateTime* datetime = NULL;
	GDateTime* _tmp0_;
	GDateTime* _tmp1_ = NULL;
	GDateTime* _tmp6_;
	GDateTime* result;
	if (ft_timestamp_is_undefined (timestamp)) {
		result = NULL;
		return result;
	}
	_tmp0_ = g_date_time_new_from_unix_utc (timestamp / FT_INTERVAL_SECOND);
	datetime = _tmp0_;
	if (timezone != NULL) {
		GDateTime* _tmp2_;
		GDateTime* _tmp3_;
		_tmp2_ = datetime;
		_tmp3_ = g_date_time_to_timezone (_tmp2_, timezone);
		_g_date_time_unref0 (_tmp1_);
		_tmp1_ = _tmp3_;
	} else {
		GDateTime* _tmp4_;
		GDateTime* _tmp5_;
		_tmp4_ = datetime;
		_tmp5_ = g_date_time_to_local (_tmp4_);
		_g_date_time_unref0 (_tmp1_);
		_tmp1_ = _tmp5_;
	}
	_tmp6_ = _tmp1_;
	_tmp1_ = NULL;
	result = _tmp6_;
	_g_date_time_unref0 (_tmp1_);
	_g_date_time_unref0 (datetime);
	return result;
}

static gchar*
string_splice (const gchar* self,
               glong start,
               glong end,
               const gchar* str)
{
	glong string_length = 0L;
	gint _tmp0_;
	gint _tmp1_;
	gboolean _tmp2_ = FALSE;
	gboolean _tmp3_ = FALSE;
	gsize str_size = 0UL;
	const gchar* _result_ = NULL;
	void* _tmp6_;
	gchar* dest = NULL;
	const gchar* _tmp7_;
	gchar* _tmp8_;
	gchar* _tmp9_;
	gchar* _tmp12_;
	const gchar* _tmp13_;
	gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = strlen (self);
	_tmp1_ = _tmp0_;
	string_length = (glong) _tmp1_;
	if (start < ((glong) 0)) {
		start = string_length + start;
	}
	if (end < ((glong) 0)) {
		end = string_length + end;
	}
	if (start >= ((glong) 0)) {
		_tmp2_ = start <= string_length;
	} else {
		_tmp2_ = FALSE;
	}
	g_return_val_if_fail (_tmp2_, NULL);
	if (end >= ((glong) 0)) {
		_tmp3_ = end <= string_length;
	} else {
		_tmp3_ = FALSE;
	}
	g_return_val_if_fail (_tmp3_, NULL);
	g_return_val_if_fail (start <= end, NULL);
	if (str == NULL) {
		str_size = (gsize) 0;
	} else {
		gint _tmp4_;
		gint _tmp5_;
		_tmp4_ = strlen ((const gchar*) str);
		_tmp5_ = _tmp4_;
		str_size = (gsize) _tmp5_;
	}
	_tmp6_ = g_malloc0 (((string_length - (end - start)) + str_size) + 1);
	_result_ = _tmp6_;
	_tmp7_ = _result_;
	dest = (gchar*) _tmp7_;
	_tmp8_ = dest;
	memcpy (_tmp8_, self, (gsize) start);
	_tmp9_ = dest;
	dest = _tmp9_ + start;
	if (str != NULL) {
		gchar* _tmp10_;
		gchar* _tmp11_;
		_tmp10_ = dest;
		memcpy (_tmp10_, str, str_size);
		_tmp11_ = dest;
		dest = _tmp11_ + str_size;
	}
	_tmp12_ = dest;
	memcpy (_tmp12_, ((gchar*) self) + end, (gsize) (string_length - end));
	_tmp13_ = _result_;
	_result_ = NULL;
	result = (gchar*) _tmp13_;
	return result;
}

static const gchar*
string_to_string (const gchar* self)
{
	const gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	result = self;
	return result;
}

gchar*
ft_timestamp_to_iso8601 (gint64 timestamp)
{
	gint64 seconds = 0LL;
	gint64 microseconds = 0LL;
	gchar* datetime_string = NULL;
	GDateTime* _tmp1_;
	GDateTime* _tmp2_;
	gchar* _tmp3_;
	gchar* _tmp4_;
	gchar* result;
	if (timestamp < ((gint64) 0)) {
		gchar* _tmp0_;
		_tmp0_ = g_strdup ("");
		result = _tmp0_;
		return result;
	}
	seconds = timestamp / FT_INTERVAL_SECOND;
	microseconds = timestamp % FT_INTERVAL_SECOND;
	_tmp1_ = g_date_time_new_from_unix_utc (seconds);
	_tmp2_ = _tmp1_;
	_tmp3_ = g_date_time_format_iso8601 (_tmp2_);
	_tmp4_ = _tmp3_;
	_g_date_time_unref0 (_tmp2_);
	datetime_string = _tmp4_;
	if (microseconds > ((gint64) 0)) {
		const gchar* _tmp5_;
		const gchar* _tmp6_;
		gchar* _tmp7_;
		gchar* _tmp8_;
		gchar* _tmp9_;
		gchar* _tmp10_;
		gchar* _tmp11_;
		_tmp5_ = datetime_string;
		_tmp6_ = string_to_string (G_GINT64_FORMAT);
		_tmp7_ = g_strconcat (".%06", _tmp6_, NULL);
		_tmp8_ = _tmp7_;
		_tmp9_ = g_strdup_printf (_tmp8_, microseconds);
		_tmp10_ = _tmp9_;
		_tmp11_ = string_splice (_tmp5_, (glong) -1, (glong) -1, _tmp10_);
		_g_free0 (datetime_string);
		datetime_string = _tmp11_;
		_g_free0 (_tmp10_);
		_g_free0 (_tmp8_);
	}
	result = datetime_string;
	return result;
}

inline gboolean
ft_timestamp_is_defined (gint64 timestamp)
{
	gboolean result;
	result = timestamp >= FT_TIMESTAMP_MIN;
	return result;
}

inline gboolean
ft_timestamp_is_undefined (gint64 timestamp)
{
	gboolean result;
	result = timestamp < FT_TIMESTAMP_MIN;
	return result;
}

gint64
ft_timestamp_add_interval (gint64 timestamp,
                           gint64 interval)
{
	gint64 result;
	if (ft_timestamp_is_undefined (timestamp)) {
		result = FT_TIMESTAMP_UNDEFINED;
		return result;
	}
	if (interval >= ((gint64) 0)) {
		gint64 _tmp0_ = 0LL;
		if (interval < (FT_TIMESTAMP_MAX - timestamp)) {
			_tmp0_ = timestamp + interval;
		} else {
			_tmp0_ = FT_TIMESTAMP_MAX;
		}
		result = _tmp0_;
		return result;
	} else {
		gint64 _tmp1_ = 0LL;
		if ((-interval) < (FT_TIMESTAMP_MIN + timestamp)) {
			_tmp1_ = timestamp + interval;
		} else {
			_tmp1_ = FT_TIMESTAMP_MIN;
		}
		result = _tmp1_;
		return result;
	}
}

/**
     * Subtract two timestamps. The result is an interval.
     */
gint64
ft_timestamp_subtract (gint64 timestamp,
                       gint64 other)
{
	gint64 result;
	if (ft_timestamp_is_undefined (timestamp)) {
		result = (gint64) 0;
		return result;
	}
	if (ft_timestamp_is_undefined (other)) {
		result = (gint64) 0;
		return result;
	}
	result = timestamp - other;
	return result;
}

gint64
ft_timestamp_subtract_interval (gint64 timestamp,
                                gint64 interval)
{
	gint64 result;
	result = ft_timestamp_add_interval (timestamp, -interval);
	return result;
}

gint64
ft_timestamp_round (gint64 timestamp,
                    gint64 unit)
{
	gint64 _tmp0_ = 0LL;
	gint64 result;
	if (ft_timestamp_is_defined (timestamp)) {
		_tmp0_ = ft_interval_round (timestamp, unit);
	} else {
		_tmp0_ = FT_TIMESTAMP_UNDEFINED;
	}
	result = _tmp0_;
	return result;
}

gint64
ft_timestamp_round_seconds (gint64 timestamp)
{
	gint64 result;
	result = ft_timestamp_round (timestamp, FT_INTERVAL_SECOND);
	return result;
}

/**
     * Freeze `Ft.Timestamp.from_now()` to current time. Used in unittests.
     */
gint64
ft_timestamp_freeze (void)
{
	gint64 result;
	if (ft_timestamp_is_undefined (ft_timestamp_current_time)) {
		ft_timestamp_current_time = ft_timestamp_from_now ();
	}
	result = ft_timestamp_current_time;
	return result;
}

/**
     * Freeze `Ft.Timestamp.from_now()` to a given value. Used in unittests.
     */
void
ft_timestamp_freeze_to (gint64 timestamp)
{
	ft_timestamp_current_time = timestamp;
}

/**
     * Revert `freeze()` call. Used in unittests.
     */
void
ft_timestamp_thaw (void)
{
	ft_timestamp_current_time = FT_TIMESTAMP_UNDEFINED;
}

gboolean
ft_timestamp_is_frozen (void)
{
	gboolean result;
	result = ft_timestamp_is_defined (ft_timestamp_current_time);
	return result;
}

/**
     * Return current time if frozen.
     */
gint64
ft_timestamp_peek (void)
{
	gint64 result;
	result = ft_timestamp_current_time;
	return result;
}

/**
     * Advance frozen time. Used in unittests.
     */
gint64
ft_timestamp_advance (gint64 interval)
{
	gint64 result;
	_vala_return_val_if_fail (interval >= ((gint64) 0), "interval >= 0", -1LL);
	if (!ft_timestamp_is_frozen ()) {
		ft_timestamp_freeze ();
	}
	ft_timestamp_current_time = ft_timestamp_current_time + interval;
	result = ft_timestamp_current_time;
	return result;
}

/**
     * If frozen, make every call `Ft.Timestamp.from_now ()` advance by given interval. Used in unittests.
     */
void
ft_timestamp_set_auto_advance (gint64 interval)
{
	_vala_return_if_fail (interval >= ((gint64) 0), "interval >= 0");
	ft_timestamp_advance_by = interval;
}

static inline gpointer
_vala_memdup2 (gconstpointer mem,
               gsize byte_size)
{
	gpointer new_mem;
	if (mem && byte_size != 0) {
		new_mem = g_malloc (byte_size);
		memcpy (new_mem, mem, byte_size);
	} else {
		new_mem = NULL;
	}
	return new_mem;
}

