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

/*
 * Copyright (c) 2021-2025 focus-timer contributors
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * Authors: Kamil Prusko <kamilprusko@gmail.com>
 */

#include "ft_core.h"
#include <string.h>
#include <gio/gio.h>
#include <glib.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <glib-object.h>
#include <gom/gom.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_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_variant_type_free0(var) ((var == NULL) ? NULL : (var = (g_variant_type_free (var), NULL)))
#define _g_variant_unref0(var) ((var == NULL) ? NULL : (var = (g_variant_unref (var), NULL)))
#define _g_variant_builder_unref0(var) ((var == NULL) ? NULL : (var = (g_variant_builder_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))
#define _g_string_free0(var) ((var == NULL) ? NULL : (var = (g_string_free (var, TRUE), NULL)))
enum  {
	FT_SESSION_0_PROPERTY,
	FT_SESSION_START_TIME_PROPERTY,
	FT_SESSION_END_TIME_PROPERTY,
	FT_SESSION_DURATION_PROPERTY,
	FT_SESSION_EXPIRY_TIME_PROPERTY,
	FT_SESSION_NUM_PROPERTIES
};
static GParamSpec* ft_session_properties[FT_SESSION_NUM_PROPERTIES];
typedef struct _Block39Data Block39Data;
enum  {
	FT_SESSION_ADDED_SIGNAL,
	FT_SESSION_REMOVED_SIGNAL,
	FT_SESSION_CHANGED_SIGNAL,
	FT_SESSION_NUM_SIGNALS
};
static guint ft_session_signals[FT_SESSION_NUM_SIGNALS] = {0};
#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);

struct _FtSessionPrivate {
	gint64 _start_time;
	gint64 _end_time;
	gint64 _expiry_time;
	GList* cycles;
	gboolean cycles_need_update;
	gint changed_freeze_count;
	gboolean changed_is_pending;
};

struct _Block39Data {
	int _ref_count_;
	FtSession* self;
	gboolean logged_warnining;
	gint64 offset;
};

static gint FtSession_private_offset;
static gpointer ft_session_parent_class = NULL;

static void ft_session_added (FtSession* self,
                       FtTimeBlock* time_block);
static void ft_session_removed (FtSession* self,
                         FtTimeBlock* time_block);
static void ft_session_changed (FtSession* self);
static void _g_object_unref0_ (gpointer var);
static inline void _g_list_free__g_object_unref0_ (GList* self);
VALA_EXTERN void ft_session_emit_added (FtSession* self,
                            FtTimeBlock* time_block);
static void ft_session_update_time_range (FtSession* self);
VALA_EXTERN void ft_session_invalidate_cycles (FtSession* self);
static void ft_session_update_cycles (FtSession* self);
static void ft_session_update_cycles_if_queued (FtSession* self);
static void ft_session_on_time_block_changed (FtSession* self);
static void _ft_session_on_time_block_changed_ft_time_block_changed (FtTimeBlock* _sender,
                                                              gpointer self);
VALA_EXTERN void ft_session_emit_removed (FtSession* self,
                              FtTimeBlock* time_block);
static void ft_session_emit_changed (FtSession* self);
VALA_EXTERN void ft_session_remove_link (FtSession* self,
                             GList* link);
VALA_EXTERN void ft_session_remove_links_after (FtSession* self,
                                    GList* link);
static Block39Data* block39_data_ref (Block39Data* _data39_);
static void block39_data_unref (void * _userdata_);
static void __lambda7_ (Block39Data* _data39_,
                 FtTimeBlock* time_block);
static void ___lambda7__gfunc (gconstpointer data,
                        gpointer self);
static gboolean __lambda8_ (FtSession* self,
                     FtCycle* cycle);
static gboolean ___lambda8__ft_filter_func (gconstpointer item,
                                     gpointer self);
VALA_EXTERN gboolean ft_session_should_create_entry (FtSession* self);
VALA_EXTERN gboolean ft_time_block_should_create_entry (FtTimeBlock* self);
VALA_EXTERN gboolean ft_session_should_update_entry (FtSession* self);
VALA_EXTERN FtSessionEntry* ft_session_create_or_update_entry (FtSession* self);
VALA_EXTERN void ft_session_unset_entry (FtSession* self);
VALA_EXTERN void ft_time_block_unset_entry (FtTimeBlock* self);
static void ft_session_real_dispose (GObject* base);
static void ft_session_finalize (GObject * obj);
static GType ft_session_get_type_once (void);
static void _vala_ft_session_get_property (GObject * object,
                                    guint property_id,
                                    GValue * value,
                                    GParamSpec * pspec);
static void _vala_ft_session_set_property (GObject * object,
                                    guint property_id,
                                    const GValue * value,
                                    GParamSpec * pspec);
static inline gpointer _vala_memdup2 (gconstpointer mem,
                        gsize byte_size);

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

void
ft_session_template_init_with_defaults (FtSessionTemplate *self)
{
	GSettings* settings = NULL;
	GSettings* _tmp0_;
	GSettings* _tmp1_;
	memset (self, 0, sizeof (FtSessionTemplate));
	_tmp0_ = ft_get_settings ();
	_tmp1_ = _g_object_ref0 (_tmp0_);
	settings = _tmp1_;
	(*self).pomodoro_duration = ft_timestamp_from_seconds_uint (g_settings_get_uint (settings, "pomodoro-duration"));
	(*self).short_break_duration = ft_timestamp_from_seconds_uint (g_settings_get_uint (settings, "short-break-duration"));
	(*self).long_break_duration = ft_timestamp_from_seconds_uint (g_settings_get_uint (settings, "long-break-duration"));
	(*self).cycles = g_settings_get_uint (settings, "cycles");
	_g_object_unref0 (settings);
}

gboolean
ft_session_template_equals (FtSessionTemplate *self,
                            FtSessionTemplate* other)
{
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_ = FALSE;
	gboolean _tmp2_ = FALSE;
	FtSessionTemplate _tmp3_;
	gboolean result;
	g_return_val_if_fail (other != NULL, FALSE);
	_tmp3_ = *other;
	if ((*self).pomodoro_duration == _tmp3_.pomodoro_duration) {
		FtSessionTemplate _tmp4_;
		_tmp4_ = *other;
		_tmp2_ = (*self).short_break_duration == _tmp4_.short_break_duration;
	} else {
		_tmp2_ = FALSE;
	}
	if (_tmp2_) {
		FtSessionTemplate _tmp5_;
		_tmp5_ = *other;
		_tmp1_ = (*self).long_break_duration == _tmp5_.long_break_duration;
	} else {
		_tmp1_ = FALSE;
	}
	if (_tmp1_) {
		FtSessionTemplate _tmp6_;
		_tmp6_ = *other;
		_tmp0_ = (*self).cycles == _tmp6_.cycles;
	} else {
		_tmp0_ = FALSE;
	}
	result = _tmp0_;
	return result;
}

gint64
ft_session_template_calculate_total_duration (FtSessionTemplate *self)
{
	gint64 total_duration = 0LL;
	gint64 _tmp0_ = 0LL;
	gint64 result;
	total_duration = (*self).pomodoro_duration * (*self).cycles;
	if ((*self).cycles > ((guint) 1)) {
		_tmp0_ = ((*self).short_break_duration * ((*self).cycles - 1)) + (*self).long_break_duration;
	} else {
		_tmp0_ = (*self).short_break_duration;
	}
	total_duration += _tmp0_;
	result = total_duration;
	return result;
}

/**
         * Calculate percentage of time allocated for breaks compared to total.
         *
         * Result is in 0 - 100 range.
         */
gdouble
ft_session_template_calculate_break_percentage (FtSessionTemplate *self)
{
	gint64 _tmp0_ = 0LL;
	gint64 breaks_duration = 0LL;
	gint64 total_duration = 0LL;
	gdouble _tmp1_ = 0.0;
	gdouble ratio = 0.0;
	gdouble result;
	if ((*self).cycles > ((guint) 1)) {
		_tmp0_ = ((*self).short_break_duration * ((*self).cycles - 1)) + (*self).long_break_duration;
	} else {
		_tmp0_ = (*self).short_break_duration;
	}
	breaks_duration = _tmp0_;
	total_duration = ((*self).pomodoro_duration * (*self).cycles) + breaks_duration;
	if (total_duration > ((gint64) 0)) {
		_tmp1_ = (100.0 * ((gdouble) breaks_duration)) / ((gdouble) total_duration);
	} else {
		_tmp1_ = 0.0;
	}
	ratio = _tmp1_;
	result = ratio;
	return result;
}

gboolean
ft_session_template_has_uniform_breaks (FtSessionTemplate *self)
{
	gboolean result;
	result = (*self).cycles == ((guint) 1);
	return result;
}

gint64
ft_session_template_get_duration (FtSessionTemplate *self,
                                  FtState state)
{
	gint64 result;
	switch (state) {
		case FT_STATE_POMODORO:
		{
			result = (*self).pomodoro_duration;
			return result;
		}
		case FT_STATE_BREAK:
		case FT_STATE_SHORT_BREAK:
		{
			result = (*self).short_break_duration;
			return result;
		}
		case FT_STATE_LONG_BREAK:
		{
			result = (*self).long_break_duration;
			return result;
		}
		case FT_STATE_STOPPED:
		{
			result = (gint64) 0;
			return result;
		}
		default:
		{
			g_assert_not_reached ();
		}
	}
}

GVariant*
ft_session_template_to_variant (FtSessionTemplate *self)
{
	GVariantBuilder* builder = NULL;
	GVariantType* _tmp0_;
	GVariantType* _tmp1_;
	GVariantBuilder* _tmp2_;
	GVariantBuilder* _tmp3_;
	GVariant* _tmp4_;
	GVariant* _tmp5_;
	GVariant* _tmp6_;
	GVariant* _tmp7_;
	GVariant* _tmp8_;
	GVariant* _tmp9_;
	GVariant* _tmp10_;
	GVariant* _tmp11_;
	GVariant* _tmp12_;
	GVariant* result;
	_tmp0_ = g_variant_type_new ("a{s*}");
	_tmp1_ = _tmp0_;
	_tmp2_ = g_variant_builder_new (_tmp1_);
	_tmp3_ = _tmp2_;
	_g_variant_type_free0 (_tmp1_);
	builder = _tmp3_;
	_tmp4_ = g_variant_new_int64 ((*self).pomodoro_duration);
	g_variant_ref_sink (_tmp4_);
	_tmp5_ = _tmp4_;
	g_variant_builder_add (builder, "{sv}", "pomodoro_duration", _tmp5_, NULL);
	_g_variant_unref0 (_tmp5_);
	_tmp6_ = g_variant_new_int64 ((*self).short_break_duration);
	g_variant_ref_sink (_tmp6_);
	_tmp7_ = _tmp6_;
	g_variant_builder_add (builder, "{sv}", "short_break_duration", _tmp7_, NULL);
	_g_variant_unref0 (_tmp7_);
	_tmp8_ = g_variant_new_int64 ((*self).long_break_duration);
	g_variant_ref_sink (_tmp8_);
	_tmp9_ = _tmp8_;
	g_variant_builder_add (builder, "{sv}", "long_break_duration", _tmp9_, NULL);
	_g_variant_unref0 (_tmp9_);
	_tmp10_ = g_variant_new_uint32 ((guint32) (*self).cycles);
	g_variant_ref_sink (_tmp10_);
	_tmp11_ = _tmp10_;
	g_variant_builder_add (builder, "{sv}", "cycles", _tmp11_, NULL);
	_g_variant_unref0 (_tmp11_);
	_tmp12_ = g_variant_builder_end (builder);
	g_variant_ref_sink (_tmp12_);
	result = _tmp12_;
	_g_variant_builder_unref0 (builder);
	return result;
}

/**
         * Represent template as string.
         *
         * Used in tests.
         */
gchar*
ft_session_template_to_representation (FtSessionTemplate *self)
{
	GString* representation = NULL;
	GString* _tmp0_;
	gchar* _tmp1_;
	gchar* _tmp2_;
	gchar* _tmp3_;
	gchar* _tmp4_;
	gchar* _tmp5_;
	gchar* _tmp6_;
	gchar* _tmp7_;
	gchar* _tmp8_;
	gchar* _tmp9_;
	gchar* _tmp10_;
	gchar* _tmp11_;
	gchar* _tmp12_;
	gchar* _tmp13_;
	gchar* _tmp14_;
	gchar* _tmp15_;
	gchar* _tmp16_;
	const gchar* _tmp17_;
	gchar* _tmp18_;
	gchar* result;
	_tmp0_ = g_string_new ("SessionTemplate (\n");
	representation = _tmp0_;
	_tmp1_ = g_strdup_printf ("%" G_GINT64_FORMAT, (*self).pomodoro_duration);
	_tmp2_ = _tmp1_;
	_tmp3_ = g_strconcat ("    pomodoro_duration = ", _tmp2_, ",\n", NULL);
	_tmp4_ = _tmp3_;
	g_string_append (representation, _tmp4_);
	_g_free0 (_tmp4_);
	_g_free0 (_tmp2_);
	_tmp5_ = g_strdup_printf ("%" G_GINT64_FORMAT, (*self).short_break_duration);
	_tmp6_ = _tmp5_;
	_tmp7_ = g_strconcat ("    short_break_duration = ", _tmp6_, ",\n", NULL);
	_tmp8_ = _tmp7_;
	g_string_append (representation, _tmp8_);
	_g_free0 (_tmp8_);
	_g_free0 (_tmp6_);
	_tmp9_ = g_strdup_printf ("%" G_GINT64_FORMAT, (*self).long_break_duration);
	_tmp10_ = _tmp9_;
	_tmp11_ = g_strconcat ("    long_break_duration = ", _tmp10_, ",\n", NULL);
	_tmp12_ = _tmp11_;
	g_string_append (representation, _tmp12_);
	_g_free0 (_tmp12_);
	_g_free0 (_tmp10_);
	_tmp13_ = g_strdup_printf ("%u", (*self).cycles);
	_tmp14_ = _tmp13_;
	_tmp15_ = g_strconcat ("    cycles = ", _tmp14_, "\n", NULL);
	_tmp16_ = _tmp15_;
	g_string_append (representation, _tmp16_);
	_g_free0 (_tmp16_);
	_g_free0 (_tmp14_);
	g_string_append (representation, ")");
	_tmp17_ = representation->str;
	_tmp18_ = g_strdup (_tmp17_);
	result = _tmp18_;
	_g_string_free0 (representation);
	return result;
}

FtSessionTemplate*
ft_session_template_dup (const FtSessionTemplate* self)
{
	FtSessionTemplate* dup;
	dup = g_new0 (FtSessionTemplate, 1);
	memcpy (dup, self, sizeof (FtSessionTemplate));
	return dup;
}

void
ft_session_template_free (FtSessionTemplate* self)
{
	g_free (self);
}

static GType
ft_session_template_get_type_once (void)
{
	GType ft_session_template_type_id;
	ft_session_template_type_id = g_boxed_type_register_static ("FtSessionTemplate", (GBoxedCopyFunc) ft_session_template_dup, (GBoxedFreeFunc) ft_session_template_free);
	return ft_session_template_type_id;
}

GType
ft_session_template_get_type (void)
{
	static volatile gsize ft_session_template_type_id__once = 0;
	if (g_once_init_enter (&ft_session_template_type_id__once)) {
		GType ft_session_template_type_id;
		ft_session_template_type_id = ft_session_template_get_type_once ();
		g_once_init_leave (&ft_session_template_type_id__once, ft_session_template_type_id);
	}
	return ft_session_template_type_id__once;
}

static inline gpointer
ft_session_get_instance_private (FtSession* self)
{
	return G_STRUCT_MEMBER_P (self, FtSession_private_offset);
}

static void
_g_object_unref0_ (gpointer var)
{
	(var == NULL) ? NULL : (var = (g_object_unref (var), NULL));
}

static inline void
_g_list_free__g_object_unref0_ (GList* self)
{
	g_list_free_full (self, (GDestroyNotify) _g_object_unref0_);
}

/**
         * Create empty session.
         */
FtSession*
ft_session_construct (GType object_type)
{
	FtSession * self = NULL;
	self = (FtSession*) g_object_new (object_type, NULL);
	return self;
}

FtSession*
ft_session_new (void)
{
	return ft_session_construct (FT_TYPE_SESSION);
}

/**
         * Create session with according to given template.
         *
         * Does not take into account users schedule.
         *
         * It's intended to be used in unit tests. In real world, session should be built by `Scheduler`.
         */
FtSession*
ft_session_construct_from_template (GType object_type,
                                    FtSessionTemplate* template,
                                    gint64 timestamp)
{
	FtSession * self = NULL;
	g_return_val_if_fail (template != NULL, NULL);
	self = (FtSession*) g_object_new (object_type, NULL);
	ft_ensure_timestamp (&timestamp);
	ft_session_freeze_changed (self);
	self->priv->_start_time = timestamp;
	{
		guint cycle = 0U;
		cycle = 1U;
		{
			gboolean _tmp0_ = FALSE;
			_tmp0_ = TRUE;
			while (TRUE) {
				FtSessionTemplate _tmp2_;
				gboolean needs_long_break = FALSE;
				FtSessionTemplate _tmp3_;
				FtTimeBlock* pomodoro_time_block = NULL;
				FtTimeBlock* _tmp4_;
				FtTimeBlock* _tmp5_;
				FtSessionTemplate _tmp6_;
				FtTimeBlock* _tmp7_;
				FtTimeBlock* _tmp8_;
				FtTimeBlock* _tmp9_;
				FtTimeBlock* _tmp10_;
				gint64 _tmp11_;
				gint64 _tmp12_;
				FtState _tmp13_ = 0;
				FtTimeBlock* break_time_block = NULL;
				FtTimeBlock* _tmp14_;
				gint64 _tmp15_ = 0LL;
				FtTimeBlock* _tmp18_;
				FtTimeBlock* _tmp19_;
				FtTimeBlock* _tmp20_;
				FtTimeBlock* _tmp21_;
				FtTimeBlock* _tmp22_;
				gint64 _tmp23_;
				gint64 _tmp24_;
				if (!_tmp0_) {
					guint _tmp1_;
					_tmp1_ = cycle;
					cycle = _tmp1_ + 1;
				}
				_tmp0_ = FALSE;
				_tmp2_ = *template;
				if (!(cycle <= _tmp2_.cycles)) {
					break;
				}
				_tmp3_ = *template;
				needs_long_break = cycle >= _tmp3_.cycles;
				_tmp4_ = ft_time_block_new_with_start_time (timestamp, FT_STATE_POMODORO);
				g_object_ref_sink (_tmp4_);
				pomodoro_time_block = _tmp4_;
				_tmp5_ = pomodoro_time_block;
				_tmp6_ = *template;
				ft_schedulable_set_duration ((FtSchedulable*) _tmp5_, _tmp6_.pomodoro_duration);
				_tmp7_ = pomodoro_time_block;
				_tmp8_ = _g_object_ref0 (_tmp7_);
				self->time_blocks = g_list_append (self->time_blocks, _tmp8_);
				_tmp9_ = pomodoro_time_block;
				ft_session_emit_added (self, _tmp9_);
				_tmp10_ = pomodoro_time_block;
				_tmp11_ = ft_schedulable_get_duration ((FtSchedulable*) _tmp10_);
				_tmp12_ = _tmp11_;
				timestamp = timestamp + _tmp12_;
				self->priv->_end_time = timestamp;
				if (needs_long_break) {
					_tmp13_ = FT_STATE_LONG_BREAK;
				} else {
					_tmp13_ = FT_STATE_SHORT_BREAK;
				}
				_tmp14_ = ft_time_block_new_with_start_time (timestamp, _tmp13_);
				g_object_ref_sink (_tmp14_);
				break_time_block = _tmp14_;
				if (needs_long_break) {
					FtSessionTemplate _tmp16_;
					_tmp16_ = *template;
					_tmp15_ = _tmp16_.long_break_duration;
				} else {
					FtSessionTemplate _tmp17_;
					_tmp17_ = *template;
					_tmp15_ = _tmp17_.short_break_duration;
				}
				_tmp18_ = break_time_block;
				ft_schedulable_set_duration ((FtSchedulable*) _tmp18_, _tmp15_);
				_tmp19_ = break_time_block;
				_tmp20_ = _g_object_ref0 (_tmp19_);
				self->time_blocks = g_list_append (self->time_blocks, _tmp20_);
				_tmp21_ = break_time_block;
				ft_session_emit_added (self, _tmp21_);
				_tmp22_ = break_time_block;
				_tmp23_ = ft_schedulable_get_duration ((FtSchedulable*) _tmp22_);
				_tmp24_ = _tmp23_;
				timestamp = timestamp + _tmp24_;
				self->priv->_end_time = timestamp;
				_g_object_unref0 (break_time_block);
				_g_object_unref0 (pomodoro_time_block);
			}
		}
	}
	ft_session_thaw_changed (self);
	return self;
}

FtSession*
ft_session_new_from_template (FtSessionTemplate* template,
                              gint64 timestamp)
{
	return ft_session_construct_from_template (FT_TYPE_SESSION, template, timestamp);
}

static void
ft_session_update_time_range (FtSession* self)
{
	FtTimeBlock* first_time_block = NULL;
	FtTimeBlock* _tmp0_;
	FtTimeBlock* last_time_block = NULL;
	FtTimeBlock* _tmp1_;
	gint64 old_duration = 0LL;
	gint64 _tmp2_ = 0LL;
	FtTimeBlock* _tmp3_;
	gint64 start_time = 0LL;
	gint64 _tmp7_ = 0LL;
	FtTimeBlock* _tmp8_;
	gint64 end_time = 0LL;
	g_return_if_fail (self != NULL);
	_tmp0_ = ft_session_get_first_time_block (self);
	first_time_block = _tmp0_;
	_tmp1_ = ft_session_get_last_time_block (self);
	last_time_block = _tmp1_;
	old_duration = self->priv->_end_time - self->priv->_start_time;
	_tmp3_ = first_time_block;
	if (_tmp3_ != NULL) {
		FtTimeBlock* _tmp4_;
		gint64 _tmp5_;
		gint64 _tmp6_;
		_tmp4_ = first_time_block;
		_tmp5_ = ft_schedulable_get_start_time ((FtSchedulable*) _tmp4_);
		_tmp6_ = _tmp5_;
		_tmp2_ = _tmp6_;
	} else {
		_tmp2_ = FT_TIMESTAMP_UNDEFINED;
	}
	start_time = _tmp2_;
	_tmp8_ = last_time_block;
	if (_tmp8_ != NULL) {
		FtTimeBlock* _tmp9_;
		gint64 _tmp10_;
		gint64 _tmp11_;
		_tmp9_ = last_time_block;
		_tmp10_ = ft_schedulable_get_end_time ((FtSchedulable*) _tmp9_);
		_tmp11_ = _tmp10_;
		_tmp7_ = _tmp11_;
	} else {
		_tmp7_ = FT_TIMESTAMP_UNDEFINED;
	}
	end_time = _tmp7_;
	if (self->priv->_start_time != start_time) {
		self->priv->_start_time = start_time;
		g_object_notify ((GObject*) self, "start-time");
	}
	if (self->priv->_end_time != end_time) {
		self->priv->_end_time = end_time;
		g_object_notify ((GObject*) self, "end-time");
	}
	if ((self->priv->_end_time - self->priv->_start_time) != old_duration) {
		g_object_notify ((GObject*) self, "duration");
	}
}

void
ft_session_invalidate_cycles (FtSession* self)
{
	g_return_if_fail (self != NULL);
	self->priv->cycles_need_update = TRUE;
}

static void
ft_session_update_cycles (FtSession* self)
{
	GList* cycles = NULL;
	FtCycle* last_cycle = NULL;
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	GList* _tmp18_;
	g_return_if_fail (self != NULL);
	cycles = NULL;
	last_cycle = NULL;
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	while (TRUE) {
		GList* _tmp2_;
		gboolean _tmp3_ = FALSE;
		FtCycle* _tmp4_;
		FtCycle* _tmp13_;
		GList* _tmp14_;
		gconstpointer _tmp15_;
		GList* _tmp16_;
		GList* _tmp17_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp4_ = last_cycle;
		if (_tmp4_ == NULL) {
			_tmp3_ = TRUE;
		} else {
			GList* _tmp5_;
			gconstpointer _tmp6_;
			FtState _tmp7_;
			FtState _tmp8_;
			_tmp5_ = link;
			_tmp6_ = _tmp5_->data;
			_tmp7_ = ft_time_block_get_state ((FtTimeBlock*) _tmp6_);
			_tmp8_ = _tmp7_;
			_tmp3_ = _tmp8_ == FT_STATE_POMODORO;
		}
		if (_tmp3_) {
			FtCycle* cycle = NULL;
			FtCycle* _tmp9_;
			FtCycle* _tmp10_;
			FtCycle* _tmp11_;
			FtCycle* _tmp12_;
			_tmp9_ = ft_cycle_new ();
			cycle = _tmp9_;
			_tmp10_ = cycle;
			_tmp11_ = _g_object_ref0 (_tmp10_);
			cycles = g_list_append (cycles, _tmp11_);
			_tmp12_ = cycle;
			last_cycle = _tmp12_;
			_g_object_unref0 (cycle);
		}
		_tmp13_ = last_cycle;
		_tmp14_ = link;
		_tmp15_ = _tmp14_->data;
		ft_cycle_append (_tmp13_, (FtTimeBlock*) _tmp15_);
		_tmp16_ = link;
		_tmp17_ = _tmp16_->next;
		link = _tmp17_;
	}
	_tmp18_ = cycles;
	cycles = NULL;
	(self->priv->cycles == NULL) ? NULL : (self->priv->cycles = (_g_list_free__g_object_unref0_ (self->priv->cycles), NULL));
	self->priv->cycles = _tmp18_;
	self->priv->cycles_need_update = FALSE;
	(cycles == NULL) ? NULL : (cycles = (_g_list_free__g_object_unref0_ (cycles), NULL));
}

static void
ft_session_update_cycles_if_queued (FtSession* self)
{
	g_return_if_fail (self != NULL);
	if (self->priv->cycles_need_update) {
		ft_session_update_cycles (self);
	}
}

static void
_ft_session_on_time_block_changed_ft_time_block_changed (FtTimeBlock* _sender,
                                                         gpointer self)
{
	ft_session_on_time_block_changed ((FtSession*) self);
}

void
ft_session_emit_added (FtSession* self,
                       FtTimeBlock* time_block)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	ft_time_block_set_session (time_block, self);
	g_signal_connect_object (time_block, "changed", (GCallback) _ft_session_on_time_block_changed_ft_time_block_changed, self, 0);
	g_signal_emit (self, ft_session_signals[FT_SESSION_ADDED_SIGNAL], 0, time_block);
}

void
ft_session_emit_removed (FtSession* self,
                         FtTimeBlock* time_block)
{
	guint _tmp0_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	ft_time_block_set_session (time_block, NULL);
	g_signal_parse_name ("changed", FT_TYPE_TIME_BLOCK, &_tmp0_, NULL, FALSE);
	g_signal_handlers_disconnect_matched (time_block, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp0_, 0, NULL, (GCallback) _ft_session_on_time_block_changed_ft_time_block_changed, self);
	g_signal_emit (self, ft_session_signals[FT_SESSION_REMOVED_SIGNAL], 0, time_block);
}

static void
ft_session_emit_changed (FtSession* self)
{
	gulong _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->version;
	self->version = _tmp0_ + 1;
	if (self->priv->changed_freeze_count > 0) {
		self->priv->changed_is_pending = TRUE;
	} else {
		self->priv->changed_is_pending = FALSE;
		g_signal_emit (self, ft_session_signals[FT_SESSION_CHANGED_SIGNAL], 0);
	}
}

void
ft_session_freeze_changed (FtSession* self)
{
	gint _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->changed_freeze_count;
	self->priv->changed_freeze_count = _tmp0_ + 1;
}

void
ft_session_thaw_changed (FtSession* self)
{
	gint _tmp0_;
	gboolean _tmp1_ = FALSE;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->changed_freeze_count;
	self->priv->changed_freeze_count = _tmp0_ - 1;
	if (self->priv->changed_freeze_count == 0) {
		_tmp1_ = self->priv->changed_is_pending;
	} else {
		_tmp1_ = FALSE;
	}
	if (_tmp1_) {
		ft_session_emit_changed (self);
	}
}

static void
ft_session_on_time_block_changed (FtSession* self)
{
	g_return_if_fail (self != NULL);
	ft_session_emit_changed (self);
}

/**
         * Check whether a session is suitable for reuse after being unused.
         */
gboolean
ft_session_is_expired (FtSession* self,
                       gint64 timestamp)
{
	gboolean _tmp0_ = FALSE;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	ft_ensure_timestamp (&timestamp);
	if (self->priv->_expiry_time >= ((gint64) 0)) {
		_tmp0_ = timestamp >= self->priv->_expiry_time;
	} else {
		_tmp0_ = FALSE;
	}
	result = _tmp0_;
	return result;
}

gboolean
ft_session_is_scheduled (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	FtTimeBlockStatus _tmp2_ = 0;
	GList* _tmp3_;
	FtTimeBlockStatus first_status = 0;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	_tmp3_ = link;
	if (_tmp3_ != NULL) {
		GList* _tmp4_;
		gconstpointer _tmp5_;
		_tmp4_ = link;
		_tmp5_ = _tmp4_->data;
		_tmp2_ = ft_time_block_get_status ((FtTimeBlock*) _tmp5_);
	} else {
		_tmp2_ = FT_TIME_BLOCK_STATUS_SCHEDULED;
	}
	first_status = _tmp2_;
	result = first_status == FT_TIME_BLOCK_STATUS_SCHEDULED;
	return result;
}

/**
         * Return whether session has a completed long break.
         *
         * The time-block must be marked with proper status; in-progress status won't do.
         */
gboolean
ft_session_is_completed (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	while (TRUE) {
		GList* _tmp2_;
		gboolean _tmp3_ = FALSE;
		GList* _tmp4_;
		gconstpointer _tmp5_;
		GList* _tmp15_;
		GList* _tmp16_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp4_ = link;
		_tmp5_ = _tmp4_->data;
		if (ft_time_block_get_status ((FtTimeBlock*) _tmp5_) == FT_TIME_BLOCK_STATUS_COMPLETED) {
			gboolean _tmp6_ = FALSE;
			GList* _tmp7_;
			gconstpointer _tmp8_;
			FtState _tmp9_;
			FtState _tmp10_;
			_tmp7_ = link;
			_tmp8_ = _tmp7_->data;
			_tmp9_ = ft_time_block_get_state ((FtTimeBlock*) _tmp8_);
			_tmp10_ = _tmp9_;
			if (_tmp10_ == FT_STATE_LONG_BREAK) {
				_tmp6_ = TRUE;
			} else {
				GList* _tmp11_;
				gconstpointer _tmp12_;
				FtState _tmp13_;
				FtState _tmp14_;
				_tmp11_ = link;
				_tmp12_ = _tmp11_->data;
				_tmp13_ = ft_time_block_get_state ((FtTimeBlock*) _tmp12_);
				_tmp14_ = _tmp13_;
				_tmp6_ = _tmp14_ == FT_STATE_BREAK;
			}
			_tmp3_ = _tmp6_;
		} else {
			_tmp3_ = FALSE;
		}
		if (_tmp3_) {
			result = TRUE;
			return result;
		}
		_tmp15_ = link;
		_tmp16_ = _tmp15_->next;
		link = _tmp16_;
	}
	result = FALSE;
	return result;
}

/**
         * Calculate ratio between time elapsed on breaks and total elapsed time.
         *
         * The intention here is to have a percentage how much of the time is spent on breaks.
         */
gfloat
ft_session_calculate_break_ratio (FtSession* self,
                                  gint64 timestamp)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	gint64 pomodoros_total = 0LL;
	gint64 breaks_total = 0LL;
	gint64 total = 0LL;
	gdouble _tmp13_ = 0.0;
	gdouble ratio = 0.0;
	gfloat result;
	g_return_val_if_fail (self != NULL, -1.0F);
	ft_ensure_timestamp (&timestamp);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	pomodoros_total = (gint64) 0;
	breaks_total = (gint64) 0;
	while (TRUE) {
		GList* _tmp2_;
		FtTimeBlock* time_block = NULL;
		GList* _tmp3_;
		gconstpointer _tmp4_;
		FtTimeBlock* _tmp5_;
		FtTimeBlock* _tmp6_;
		FtState _tmp7_;
		FtState _tmp8_;
		GList* _tmp11_;
		GList* _tmp12_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp3_ = link;
		_tmp4_ = _tmp3_->data;
		_tmp5_ = _g_object_ref0 ((FtTimeBlock*) _tmp4_);
		time_block = _tmp5_;
		_tmp6_ = time_block;
		_tmp7_ = ft_time_block_get_state (_tmp6_);
		_tmp8_ = _tmp7_;
		switch (_tmp8_) {
			case FT_STATE_POMODORO:
			{
				FtTimeBlock* _tmp9_;
				_tmp9_ = time_block;
				pomodoros_total = ft_interval_add (pomodoros_total, ft_time_block_calculate_elapsed (_tmp9_, timestamp));
				break;
			}
			case FT_STATE_BREAK:
			case FT_STATE_SHORT_BREAK:
			case FT_STATE_LONG_BREAK:
			{
				FtTimeBlock* _tmp10_;
				_tmp10_ = time_block;
				breaks_total = ft_interval_add (breaks_total, ft_time_block_calculate_elapsed (_tmp10_, timestamp));
				break;
			}
			default:
			{
				g_assert_not_reached ();
			}
		}
		_tmp11_ = link;
		_tmp12_ = _tmp11_->next;
		link = _tmp12_;
		_g_object_unref0 (time_block);
	}
	total = ft_interval_add (pomodoros_total, breaks_total);
	if (total > ((gint64) 0)) {
		_tmp13_ = ((gdouble) breaks_total) / ((gdouble) total);
	} else {
		_tmp13_ = 0.0;
	}
	ratio = _tmp13_;
	result = (gfloat) ratio;
	return result;
}

/**
         * Remove link.
         */
void
ft_session_remove_link (FtSession* self,
                        GList* link)
{
	FtTimeBlock* time_block = NULL;
	gconstpointer _tmp0_;
	FtTimeBlock* _tmp1_;
	FtTimeBlock* _tmp2_;
	FtTimeBlock* _tmp3_;
	g_return_if_fail (self != NULL);
	if (link == NULL) {
		return;
	}
	_tmp0_ = link->data;
	_tmp1_ = _g_object_ref0 ((FtTimeBlock*) _tmp0_);
	time_block = _tmp1_;
	_tmp2_ = time_block;
	ft_time_block_set_session (_tmp2_, NULL);
	_g_object_unref0 (link->data);
	link->data = NULL;
	self->time_blocks = g_list_delete_link (self->time_blocks, link);
	_tmp3_ = time_block;
	ft_session_emit_removed (self, _tmp3_);
	_g_object_unref0 (time_block);
}

/**
         * Remove links following.
         */
void
ft_session_remove_links_after (FtSession* self,
                               GList* link)
{
	GList* _tmp0_;
	g_return_if_fail (self != NULL);
	if (link == NULL) {
		return;
	}
	_tmp0_ = link->next;
	if (_tmp0_ != NULL) {
		GList* _tmp1_;
		GList* _tmp2_;
		_tmp1_ = link->next;
		ft_session_remove_links_after (self, _tmp1_);
		_tmp2_ = link->next;
		ft_session_remove_link (self, _tmp2_);
	}
}

/**
         * Add the time-block and align it with the last block.
         */
void
ft_session_append (FtSession* self,
                   FtTimeBlock* time_block)
{
	FtSession* _tmp0_;
	FtSession* _tmp1_;
	FtTimeBlock* last_time_block = NULL;
	FtTimeBlock* _tmp2_;
	FtTimeBlock* _tmp3_;
	FtTimeBlock* _tmp4_;
	FtTimeBlock* _tmp8_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	_tmp0_ = ft_time_block_get_session (time_block);
	_tmp1_ = _tmp0_;
	_vala_return_if_fail (_tmp1_ == NULL, "time_block.session == null");
	_tmp2_ = ft_session_get_last_time_block (self);
	_tmp3_ = _g_object_ref0 (_tmp2_);
	last_time_block = _tmp3_;
	_tmp4_ = last_time_block;
	if (_tmp4_ != NULL) {
		FtTimeBlock* _tmp5_;
		gint64 _tmp6_;
		gint64 _tmp7_;
		_tmp5_ = last_time_block;
		_tmp6_ = ft_schedulable_get_end_time ((FtSchedulable*) _tmp5_);
		_tmp7_ = _tmp6_;
		ft_schedulable_move_to ((FtSchedulable*) time_block, _tmp7_);
	}
	_tmp8_ = _g_object_ref0 (time_block);
	self->time_blocks = g_list_append (self->time_blocks, _tmp8_);
	ft_session_emit_added (self, time_block);
	_g_object_unref0 (last_time_block);
}

/**
         * Add the time-block as first and align it to first time-block.
         */
void
ft_session_prepend (FtSession* self,
                    FtTimeBlock* time_block)
{
	FtSession* _tmp0_;
	FtSession* _tmp1_;
	FtTimeBlock* first_time_block = NULL;
	FtTimeBlock* _tmp2_;
	FtTimeBlock* _tmp3_;
	FtTimeBlock* _tmp4_;
	FtTimeBlock* _tmp10_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	_tmp0_ = ft_time_block_get_session (time_block);
	_tmp1_ = _tmp0_;
	_vala_return_if_fail (_tmp1_ == NULL, "time_block.session == null");
	_tmp2_ = ft_session_get_first_time_block (self);
	_tmp3_ = _g_object_ref0 (_tmp2_);
	first_time_block = _tmp3_;
	_tmp4_ = first_time_block;
	if (_tmp4_ != NULL) {
		gint64 new_start_time = 0LL;
		FtTimeBlock* _tmp5_;
		gint64 _tmp6_;
		gint64 _tmp7_;
		gint64 _tmp8_;
		gint64 _tmp9_;
		_tmp5_ = first_time_block;
		_tmp6_ = ft_schedulable_get_start_time ((FtSchedulable*) _tmp5_);
		_tmp7_ = _tmp6_;
		_tmp8_ = ft_schedulable_get_duration ((FtSchedulable*) time_block);
		_tmp9_ = _tmp8_;
		new_start_time = ft_timestamp_subtract (_tmp7_, _tmp9_);
		ft_schedulable_move_to ((FtSchedulable*) time_block, new_start_time);
	}
	_tmp10_ = _g_object_ref0 (time_block);
	self->time_blocks = g_list_prepend (self->time_blocks, _tmp10_);
	ft_session_emit_added (self, time_block);
	_g_object_unref0 (first_time_block);
}

/**
         * Insert the time-block before given time-block.
         */
void
ft_session_insert_before (FtSession* self,
                          FtTimeBlock* time_block,
                          FtTimeBlock* sibling)
{
	FtSession* _tmp0_;
	FtSession* _tmp1_;
	FtSession* _tmp2_;
	FtSession* _tmp3_;
	GList* sibling_link = NULL;
	GList* _tmp4_;
	GList* _tmp5_;
	gint64 _tmp6_;
	gint64 _tmp7_;
	FtTimeBlock* _tmp8_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	g_return_if_fail (sibling != NULL);
	_tmp0_ = ft_time_block_get_session (time_block);
	_tmp1_ = _tmp0_;
	_vala_return_if_fail (_tmp1_ == NULL, "time_block.session == null");
	_tmp2_ = ft_time_block_get_session (sibling);
	_tmp3_ = _tmp2_;
	_vala_return_if_fail (_tmp3_ == self, "sibling.session == this");
	_tmp4_ = self->time_blocks;
	_tmp5_ = g_list_find (_tmp4_, sibling);
	sibling_link = _tmp5_;
	_tmp6_ = ft_schedulable_get_start_time ((FtSchedulable*) sibling);
	_tmp7_ = _tmp6_;
	ft_schedulable_move_to ((FtSchedulable*) time_block, _tmp7_);
	_tmp8_ = _g_object_ref0 (time_block);
	self->time_blocks = g_list_insert_before (self->time_blocks, sibling_link, _tmp8_);
	ft_session_emit_added (self, time_block);
}

/**
         * Insert the time-block after given time-block and align it to the sibling.
         */
void
ft_session_insert_after (FtSession* self,
                         FtTimeBlock* time_block,
                         FtTimeBlock* sibling)
{
	FtSession* _tmp0_;
	FtSession* _tmp1_;
	FtSession* _tmp2_;
	FtSession* _tmp3_;
	GList* sibling_link = NULL;
	GList* _tmp4_;
	GList* _tmp5_;
	GList* _tmp6_;
	GList* _tmp7_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	g_return_if_fail (sibling != NULL);
	_tmp0_ = ft_time_block_get_session (time_block);
	_tmp1_ = _tmp0_;
	_vala_return_if_fail (_tmp1_ == NULL, "time_block.session == null");
	_tmp2_ = ft_time_block_get_session (sibling);
	_tmp3_ = _tmp2_;
	_vala_return_if_fail (_tmp3_ == self, "sibling.session == this");
	_tmp4_ = self->time_blocks;
	_tmp5_ = g_list_find (_tmp4_, sibling);
	sibling_link = _tmp5_;
	_tmp6_ = sibling_link;
	_tmp7_ = _tmp6_->next;
	if (_tmp7_ == NULL) {
		ft_session_append (self, time_block);
	} else {
		gint64 _tmp8_;
		gint64 _tmp9_;
		GList* _tmp10_;
		GList* _tmp11_;
		FtTimeBlock* _tmp12_;
		_tmp8_ = ft_schedulable_get_end_time ((FtSchedulable*) sibling);
		_tmp9_ = _tmp8_;
		ft_schedulable_move_to ((FtSchedulable*) time_block, _tmp9_);
		_tmp10_ = sibling_link;
		_tmp11_ = _tmp10_->next;
		_tmp12_ = _g_object_ref0 (time_block);
		self->time_blocks = g_list_insert_before (self->time_blocks, _tmp11_, _tmp12_);
		ft_session_emit_added (self, time_block);
	}
}

void
ft_session_remove (FtSession* self,
                   FtTimeBlock* time_block)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	GList* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_find (_tmp0_, time_block);
	link = _tmp1_;
	_tmp2_ = link;
	if (_tmp2_ != NULL) {
		GList* _tmp3_;
		_tmp3_ = link;
		ft_session_remove_link (self, _tmp3_);
	} else {
		g_warning ("session.vala:592: Ignoring `Session.remove()`. Time-block does not bel" \
"ong to the session.");
	}
}

void
ft_session_remove_before (FtSession* self,
                          FtTimeBlock* time_block)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	GList* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_find (_tmp0_, time_block);
	link = _tmp1_;
	_tmp2_ = link;
	if (_tmp2_ == NULL) {
		g_warning ("session.vala:601: Ignoring `Session.remove_before()`. Time-block does " \
"not belong to the session.");
		return;
	}
	ft_session_freeze_changed (self);
	while (TRUE) {
		GList* _tmp3_;
		GList* _tmp4_;
		GList* _tmp5_;
		GList* _tmp6_;
		_tmp3_ = link;
		_tmp4_ = _tmp3_->prev;
		if (!(_tmp4_ != NULL)) {
			break;
		}
		_tmp5_ = link;
		_tmp6_ = _tmp5_->prev;
		ft_session_remove_link (self, _tmp6_);
	}
	ft_session_thaw_changed (self);
}

void
ft_session_remove_after (FtSession* self,
                         FtTimeBlock* time_block)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	GList* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_find (_tmp0_, time_block);
	link = _tmp1_;
	_tmp2_ = link;
	if (_tmp2_ == NULL) {
		g_warning ("session.vala:620: Ignoring `Session.remove_after()`. Time-block does n" \
"ot belong to the session.");
		return;
	}
	ft_session_freeze_changed (self);
	while (TRUE) {
		GList* _tmp3_;
		GList* _tmp4_;
		GList* _tmp5_;
		GList* _tmp6_;
		_tmp3_ = link;
		_tmp4_ = _tmp3_->next;
		if (!(_tmp4_ != NULL)) {
			break;
		}
		_tmp5_ = link;
		_tmp6_ = _tmp5_->next;
		ft_session_remove_link (self, _tmp6_);
	}
	ft_session_thaw_changed (self);
}

void
ft_session_remove_scheduled (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	GList* tmp = NULL;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	ft_session_freeze_changed (self);
	while (TRUE) {
		GList* _tmp2_;
		GList* _tmp3_;
		gconstpointer _tmp4_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp3_ = link;
		_tmp4_ = _tmp3_->data;
		if (ft_time_block_get_status ((FtTimeBlock*) _tmp4_) == FT_TIME_BLOCK_STATUS_SCHEDULED) {
			GList* _tmp5_;
			GList* _tmp6_;
			GList* _tmp7_;
			GList* _tmp8_;
			_tmp5_ = link;
			_tmp6_ = _tmp5_->next;
			tmp = _tmp6_;
			_tmp7_ = link;
			ft_session_remove_link (self, _tmp7_);
			_tmp8_ = tmp;
			link = _tmp8_;
		} else {
			GList* _tmp9_;
			GList* _tmp10_;
			_tmp9_ = link;
			_tmp10_ = _tmp9_->next;
			link = _tmp10_;
		}
	}
	ft_session_thaw_changed (self);
}

FtTimeBlock*
ft_session_get_first_time_block (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	FtTimeBlock* _tmp2_ = NULL;
	GList* _tmp3_;
	FtTimeBlock* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	_tmp3_ = link;
	if (_tmp3_ != NULL) {
		GList* _tmp4_;
		gconstpointer _tmp5_;
		_tmp4_ = link;
		_tmp5_ = _tmp4_->data;
		_tmp2_ = (FtTimeBlock*) _tmp5_;
	} else {
		_tmp2_ = NULL;
	}
	result = _tmp2_;
	return result;
}

FtTimeBlock*
ft_session_get_last_time_block (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	FtTimeBlock* _tmp2_ = NULL;
	GList* _tmp3_;
	FtTimeBlock* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_last (_tmp0_);
	link = _tmp1_;
	_tmp3_ = link;
	if (_tmp3_ != NULL) {
		GList* _tmp4_;
		gconstpointer _tmp5_;
		_tmp4_ = link;
		_tmp5_ = _tmp4_->data;
		_tmp2_ = (FtTimeBlock*) _tmp5_;
	} else {
		_tmp2_ = NULL;
	}
	result = _tmp2_;
	return result;
}

FtTimeBlock*
ft_session_get_nth_time_block (FtSession* self,
                               guint index)
{
	GList* _tmp0_;
	gconstpointer _tmp1_;
	FtTimeBlock* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_nth_data (_tmp0_, index);
	result = (FtTimeBlock*) _tmp1_;
	return result;
}

FtTimeBlock*
ft_session_get_previous_time_block (FtSession* self,
                                    FtTimeBlock* time_block)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	gboolean _tmp2_ = FALSE;
	GList* _tmp3_;
	GList* _tmp6_;
	GList* _tmp7_;
	gconstpointer _tmp8_;
	FtTimeBlock* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_find (_tmp0_, time_block);
	link = _tmp1_;
	_tmp3_ = link;
	if (_tmp3_ == NULL) {
		_tmp2_ = TRUE;
	} else {
		GList* _tmp4_;
		GList* _tmp5_;
		_tmp4_ = link;
		_tmp5_ = _tmp4_->prev;
		_tmp2_ = _tmp5_ == NULL;
	}
	if (_tmp2_) {
		result = NULL;
		return result;
	}
	_tmp6_ = link;
	_tmp7_ = _tmp6_->prev;
	_tmp8_ = _tmp7_->data;
	result = (FtTimeBlock*) _tmp8_;
	return result;
}

FtTimeBlock*
ft_session_get_next_time_block (FtSession* self,
                                FtTimeBlock* time_block)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	gboolean _tmp2_ = FALSE;
	GList* _tmp3_;
	GList* _tmp6_;
	GList* _tmp7_;
	gconstpointer _tmp8_;
	FtTimeBlock* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_find (_tmp0_, time_block);
	link = _tmp1_;
	_tmp3_ = link;
	if (_tmp3_ == NULL) {
		_tmp2_ = TRUE;
	} else {
		GList* _tmp4_;
		GList* _tmp5_;
		_tmp4_ = link;
		_tmp5_ = _tmp4_->next;
		_tmp2_ = _tmp5_ == NULL;
	}
	if (_tmp2_) {
		result = NULL;
		return result;
	}
	_tmp6_ = link;
	_tmp7_ = _tmp6_->next;
	_tmp8_ = _tmp7_->data;
	result = (FtTimeBlock*) _tmp8_;
	return result;
}

gint
ft_session_index (FtSession* self,
                  FtTimeBlock* time_block)
{
	GList* _tmp0_;
	gint result;
	g_return_val_if_fail (self != NULL, -1);
	g_return_val_if_fail (time_block != NULL, -1);
	_tmp0_ = self->time_blocks;
	result = g_list_index (_tmp0_, time_block);
	return result;
}

gboolean
ft_session_contains (FtSession* self,
                     FtTimeBlock* time_block)
{
	GList* _tmp0_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (time_block != NULL, FALSE);
	_tmp0_ = self->time_blocks;
	result = g_list_index (_tmp0_, time_block) >= 0;
	return result;
}

void
ft_session_foreach (FtSession* self,
                    GFunc func,
                    gpointer func_target)
{
	GList* _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->time_blocks;
	g_list_foreach (_tmp0_, func, func_target);
}

static Block39Data*
block39_data_ref (Block39Data* _data39_)
{
	g_atomic_int_inc (&_data39_->_ref_count_);
	return _data39_;
}

static void
block39_data_unref (void * _userdata_)
{
	Block39Data* _data39_;
	_data39_ = (Block39Data*) _userdata_;
	if (g_atomic_int_dec_and_test (&_data39_->_ref_count_)) {
		FtSession* self;
		self = _data39_->self;
		_g_object_unref0 (self);
		g_slice_free (Block39Data, _data39_);
	}
}

static void
__lambda7_ (Block39Data* _data39_,
            FtTimeBlock* time_block)
{
	FtSession* self;
	gboolean _tmp0_ = FALSE;
	self = _data39_->self;
	g_return_if_fail (time_block != NULL);
	if (!_data39_->logged_warnining) {
		_tmp0_ = ft_time_block_get_status (time_block) > FT_TIME_BLOCK_STATUS_IN_PROGRESS;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		g_warning ("session.vala:720: Moving time-blocks that have been completed.");
		_data39_->logged_warnining = TRUE;
	}
	ft_schedulable_move_by ((FtSchedulable*) time_block, _data39_->offset);
}

static void
___lambda7__gfunc (gconstpointer data,
                   gpointer self)
{
	__lambda7_ (self, (FtTimeBlock*) data);
}

void
ft_session_move_by (FtSession* self,
                    gint64 offset)
{
	Block39Data* _data39_;
	GList* _tmp0_;
	g_return_if_fail (self != NULL);
	_data39_ = g_slice_new0 (Block39Data);
	_data39_->_ref_count_ = 1;
	_data39_->self = g_object_ref (self);
	_data39_->offset = offset;
	_data39_->logged_warnining = FALSE;
	ft_session_freeze_changed (self);
	_tmp0_ = self->time_blocks;
	g_list_foreach (_tmp0_, ___lambda7__gfunc, _data39_);
	ft_session_thaw_changed (self);
	block39_data_unref (_data39_);
	_data39_ = NULL;
}

/**
         * Move all time blocks to a given timestamp, even started / completed.
         *
         * You manually modify time blocks. Consider calling .reschedule() .
         */
void
ft_session_move_to (FtSession* self,
                    gint64 timestamp)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	GList* _tmp2_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	_tmp2_ = link;
	if (_tmp2_ != NULL) {
		GList* _tmp3_;
		gconstpointer _tmp4_;
		gint64 _tmp5_;
		gint64 _tmp6_;
		_tmp3_ = link;
		_tmp4_ = _tmp3_->data;
		_tmp5_ = ft_schedulable_get_start_time ((FtSchedulable*) ((FtTimeBlock*) _tmp4_));
		_tmp6_ = _tmp5_;
		ft_session_move_by (self, ft_timestamp_subtract (timestamp, _tmp6_));
	}
}

void
ft_session_set_time_block_status (FtSession* self,
                                  FtTimeBlock* time_block,
                                  FtTimeBlockStatus status)
{
	gboolean changed = FALSE;
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	changed = FALSE;
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	if (!ft_session_contains (self, time_block)) {
		return;
	}
	while (TRUE) {
		GList* _tmp2_;
		FtTimeBlockStatus prevoious_status = 0;
		GList* _tmp3_;
		gconstpointer _tmp4_;
		GList* _tmp5_;
		gconstpointer _tmp6_;
		GList* _tmp11_;
		GList* _tmp12_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp3_ = link;
		_tmp4_ = _tmp3_->data;
		prevoious_status = ft_time_block_get_status ((FtTimeBlock*) _tmp4_);
		_tmp5_ = link;
		_tmp6_ = _tmp5_->data;
		if (((FtTimeBlock*) _tmp6_) == time_block) {
			if (prevoious_status != status) {
				GList* _tmp7_;
				gconstpointer _tmp8_;
				_tmp7_ = link;
				_tmp8_ = _tmp7_->data;
				ft_time_block_set_status ((FtTimeBlock*) _tmp8_, status);
				changed = TRUE;
			}
			break;
		}
		if (prevoious_status <= FT_TIME_BLOCK_STATUS_IN_PROGRESS) {
			GList* _tmp9_;
			gconstpointer _tmp10_;
			_tmp9_ = link;
			_tmp10_ = _tmp9_->data;
			ft_time_block_set_status ((FtTimeBlock*) _tmp10_, FT_TIME_BLOCK_STATUS_UNCOMPLETED);
			changed = TRUE;
		}
		_tmp11_ = link;
		_tmp12_ = _tmp11_->next;
		link = _tmp12_;
	}
	if (changed) {
		ft_session_emit_changed (self);
	}
}

/**
         * Cycles are not an structural part of a session, they are more like annotations. They are generated if needed
         * with `get_cycles ()`.
         */
GList*
ft_session_get_cycles (FtSession* self)
{
	GList* _tmp0_;
	GList* _tmp1_;
	GList* result;
	g_return_val_if_fail (self != NULL, NULL);
	ft_session_update_cycles_if_queued (self);
	_tmp0_ = self->priv->cycles;
	_tmp1_ = g_list_copy (_tmp0_);
	result = _tmp1_;
	return result;
}

guint
ft_session_count_time_blocks (FtSession* self,
                              FtFilterFunc func,
                              gpointer func_target)
{
	GList* link = NULL;
	GList* _tmp1_;
	GList* _tmp2_;
	guint count = 0U;
	guint result;
	g_return_val_if_fail (self != NULL, 0U);
	if (func == NULL) {
		GList* _tmp0_;
		_tmp0_ = self->time_blocks;
		result = g_list_length (_tmp0_);
		return result;
	}
	_tmp1_ = self->time_blocks;
	_tmp2_ = g_list_first (_tmp1_);
	link = _tmp2_;
	count = 0U;
	while (TRUE) {
		GList* _tmp3_;
		GList* _tmp4_;
		gconstpointer _tmp5_;
		GList* _tmp7_;
		GList* _tmp8_;
		_tmp3_ = link;
		if (!(_tmp3_ != NULL)) {
			break;
		}
		_tmp4_ = link;
		_tmp5_ = _tmp4_->data;
		if (func ((FtTimeBlock*) _tmp5_, func_target)) {
			guint _tmp6_;
			_tmp6_ = count;
			count = _tmp6_ + 1;
		}
		_tmp7_ = link;
		_tmp8_ = _tmp7_->next;
		link = _tmp8_;
	}
	result = count;
	return result;
}

guint
ft_session_count_cycles (FtSession* self,
                         FtFilterFunc func,
                         gpointer func_target)
{
	GList* link = NULL;
	GList* _tmp1_;
	GList* _tmp2_;
	guint count = 0U;
	guint result;
	g_return_val_if_fail (self != NULL, 0U);
	ft_session_update_cycles_if_queued (self);
	if (func == NULL) {
		GList* _tmp0_;
		_tmp0_ = self->priv->cycles;
		result = g_list_length (_tmp0_);
		return result;
	}
	_tmp1_ = self->priv->cycles;
	_tmp2_ = g_list_first (_tmp1_);
	link = _tmp2_;
	count = 0U;
	while (TRUE) {
		GList* _tmp3_;
		GList* _tmp4_;
		gconstpointer _tmp5_;
		GList* _tmp7_;
		GList* _tmp8_;
		_tmp3_ = link;
		if (!(_tmp3_ != NULL)) {
			break;
		}
		_tmp4_ = link;
		_tmp5_ = _tmp4_->data;
		if (func ((FtCycle*) _tmp5_, func_target)) {
			guint _tmp6_;
			_tmp6_ = count;
			count = _tmp6_ + 1;
		}
		_tmp7_ = link;
		_tmp8_ = _tmp7_->next;
		link = _tmp8_;
	}
	result = count;
	return result;
}

static gboolean
__lambda8_ (FtSession* self,
            FtCycle* cycle)
{
	gboolean result;
	g_return_val_if_fail (cycle != NULL, FALSE);
	result = ft_cycle_is_visible (cycle);
	return result;
}

static gboolean
___lambda8__ft_filter_func (gconstpointer item,
                            gpointer self)
{
	gboolean result;
	result = __lambda8_ ((FtSession*) self, (FtCycle*) item);
	return result;
}

inline guint
ft_session_count_visible_cycles (FtSession* self)
{
	guint result;
	g_return_val_if_fail (self != NULL, 0U);
	result = ft_session_count_cycles (self, ___lambda8__ft_filter_func, self);
	return result;
}

gboolean
ft_session_should_create_entry (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	while (TRUE) {
		GList* _tmp2_;
		GList* _tmp3_;
		gconstpointer _tmp4_;
		GList* _tmp5_;
		GList* _tmp6_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp3_ = link;
		_tmp4_ = _tmp3_->data;
		if (ft_time_block_should_create_entry ((FtTimeBlock*) _tmp4_)) {
			result = TRUE;
			return result;
		}
		_tmp5_ = link;
		_tmp6_ = _tmp5_->next;
		link = _tmp6_;
	}
	result = FALSE;
	return result;
}

gboolean
ft_session_should_update_entry (FtSession* self)
{
	gboolean _tmp0_ = FALSE;
	FtSessionEntry* _tmp1_;
	FtSessionEntry* _tmp5_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp1_ = self->entry;
	if (_tmp1_ == NULL) {
		_tmp0_ = TRUE;
	} else {
		FtSessionEntry* _tmp2_;
		gint64 _tmp3_;
		gint64 _tmp4_;
		_tmp2_ = self->entry;
		_tmp3_ = ft_session_entry_get_id (_tmp2_);
		_tmp4_ = _tmp3_;
		_tmp0_ = _tmp4_ == ((gint64) 0);
	}
	if (_tmp0_) {
		result = TRUE;
		return result;
	}
	_tmp5_ = self->entry;
	result = _tmp5_->version != self->version;
	return result;
}

FtSessionEntry*
ft_session_create_or_update_entry (FtSession* self)
{
	FtSessionEntry* _tmp0_;
	FtSessionEntry* _tmp4_;
	FtSessionEntry* _tmp5_;
	FtSessionEntry* _tmp6_;
	FtSessionEntry* _tmp7_;
	FtSessionEntry* _tmp8_;
	FtSessionEntry* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->entry;
	if (_tmp0_ == NULL) {
		FtSessionEntry* _tmp1_;
		FtSessionEntry* _tmp2_;
		GomRepository* _tmp3_;
		_tmp1_ = ft_session_entry_new ();
		_g_object_unref0 (self->entry);
		self->entry = _tmp1_;
		_tmp2_ = self->entry;
		_tmp3_ = ft_database_get_repository ();
		g_object_set ((GomResource*) _tmp2_, "repository", _tmp3_, NULL);
	}
	_tmp4_ = self->entry;
	ft_session_entry_set_start_time (_tmp4_, self->priv->_start_time);
	_tmp5_ = self->entry;
	ft_session_entry_set_end_time (_tmp5_, self->priv->_end_time);
	_tmp6_ = self->entry;
	ft_session_entry_set_expiry_time (_tmp6_, self->priv->_expiry_time);
	_tmp7_ = self->entry;
	_tmp7_->version = self->version;
	_tmp8_ = self->entry;
	result = _tmp8_;
	return result;
}

void
ft_session_unset_entry (FtSession* self)
{
	GList* link = NULL;
	GList* _tmp0_;
	GList* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->time_blocks;
	_tmp1_ = g_list_first (_tmp0_);
	link = _tmp1_;
	while (TRUE) {
		GList* _tmp2_;
		GList* _tmp3_;
		gconstpointer _tmp4_;
		GList* _tmp5_;
		GList* _tmp6_;
		_tmp2_ = link;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp3_ = link;
		_tmp4_ = _tmp3_->data;
		ft_time_block_unset_entry ((FtTimeBlock*) _tmp4_);
		_tmp5_ = link;
		_tmp6_ = _tmp5_->next;
		link = _tmp6_;
	}
	_g_object_unref0 (self->entry);
	self->entry = NULL;
}

static void
ft_session_real_dispose (GObject* base)
{
	FtSession * self;
	self = (FtSession*) base;
	(self->time_blocks == NULL) ? NULL : (self->time_blocks = (_g_list_free__g_object_unref0_ (self->time_blocks), NULL));
	self->time_blocks = NULL;
	_g_object_unref0 (self->entry);
	self->entry = NULL;
	(self->priv->cycles == NULL) ? NULL : (self->priv->cycles = (_g_list_free__g_object_unref0_ (self->priv->cycles), NULL));
	self->priv->cycles = NULL;
	G_OBJECT_CLASS (ft_session_parent_class)->dispose (G_TYPE_CHECK_INSTANCE_CAST (self, G_TYPE_OBJECT, GObject));
}

gint64
ft_session_get_start_time (FtSession* self)
{
	gint64 result;
	g_return_val_if_fail (self != NULL, -1LL);
	result = self->priv->_start_time;
	return result;
}

gint64
ft_session_get_end_time (FtSession* self)
{
	gint64 result;
	g_return_val_if_fail (self != NULL, -1LL);
	result = self->priv->_end_time;
	return result;
}

gint64
ft_session_get_duration (FtSession* self)
{
	gint64 result;
	g_return_val_if_fail (self != NULL, -1LL);
	result = ft_timestamp_subtract (self->priv->_end_time, self->priv->_start_time);
	return result;
}

gint64
ft_session_get_expiry_time (FtSession* self)
{
	gint64 result;
	g_return_val_if_fail (self != NULL, -1LL);
	result = self->priv->_expiry_time;
	return result;
}

void
ft_session_set_expiry_time (FtSession* self,
                            gint64 value)
{
	gulong _tmp0_;
	g_return_if_fail (self != NULL);
	if (self->priv->_expiry_time == value) {
		return;
	}
	self->priv->_expiry_time = value;
	_tmp0_ = self->version;
	self->version = _tmp0_ + 1;
	g_object_notify ((GObject*) self, "expiry-time");
}

static void
ft_session_real_added (FtSession* self,
                       FtTimeBlock* time_block)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	ft_session_emit_changed (self);
}

static void
ft_session_real_removed (FtSession* self,
                         FtTimeBlock* time_block)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (time_block != NULL);
	ft_session_emit_changed (self);
}

static void
ft_session_real_changed (FtSession* self)
{
	g_return_if_fail (self != NULL);
	ft_session_update_time_range (self);
	ft_session_invalidate_cycles (self);
}

static void
ft_session_class_init (FtSessionClass * klass,
                       gpointer klass_data)
{
	ft_session_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &FtSession_private_offset);
	((GObjectClass *) klass)->dispose = (void (*) (GObject*)) ft_session_real_dispose;
	G_OBJECT_CLASS (klass)->get_property = _vala_ft_session_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_ft_session_set_property;
	G_OBJECT_CLASS (klass)->finalize = ft_session_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_SESSION_START_TIME_PROPERTY, ft_session_properties[FT_SESSION_START_TIME_PROPERTY] = g_param_spec_int64 ("start-time", "start-time", "start-time", G_MININT64, G_MAXINT64, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_SESSION_END_TIME_PROPERTY, ft_session_properties[FT_SESSION_END_TIME_PROPERTY] = g_param_spec_int64 ("end-time", "end-time", "end-time", G_MININT64, G_MAXINT64, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	         * Duration of a session.
	         *
	         * It will include interruptions / gap times. For real time spent use `calculate_elapsed()`.
	         */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_SESSION_DURATION_PROPERTY, ft_session_properties[FT_SESSION_DURATION_PROPERTY] = g_param_spec_int64 ("duration", "duration", "duration", G_MININT64, G_MAXINT64, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	         * Manually set expiry time.
	         *
	         * A session can't determine whether it expired on its own in some circumstances.
	         * For instance it's not aware when the timer gets paused, so the responsibility of managing expiry
	         * passes on to a session manager.
	         */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_SESSION_EXPIRY_TIME_PROPERTY, ft_session_properties[FT_SESSION_EXPIRY_TIME_PROPERTY] = g_param_spec_int64 ("expiry-time", "expiry-time", "expiry-time", G_MININT64, G_MAXINT64, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY));
	ft_session_signals[FT_SESSION_ADDED_SIGNAL] = g_signal_new_class_handler ("added", FT_TYPE_SESSION, G_SIGNAL_RUN_LAST, (GCallback) ft_session_real_added, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, FT_TYPE_TIME_BLOCK);
	ft_session_signals[FT_SESSION_REMOVED_SIGNAL] = g_signal_new_class_handler ("removed", FT_TYPE_SESSION, G_SIGNAL_RUN_LAST, (GCallback) ft_session_real_removed, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, FT_TYPE_TIME_BLOCK);
	ft_session_signals[FT_SESSION_CHANGED_SIGNAL] = g_signal_new_class_handler ("changed", FT_TYPE_SESSION, G_SIGNAL_RUN_FIRST, (GCallback) ft_session_real_changed, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static void
ft_session_instance_init (FtSession * self,
                          gpointer klass)
{
	self->priv = ft_session_get_instance_private (self);
	self->version = (gulong) 0;
	self->entry = NULL;
	self->priv->_start_time = FT_TIMESTAMP_UNDEFINED;
	self->priv->_end_time = FT_TIMESTAMP_UNDEFINED;
	self->priv->_expiry_time = FT_TIMESTAMP_UNDEFINED;
	self->priv->cycles_need_update = TRUE;
	self->priv->changed_freeze_count = 0;
	self->priv->changed_is_pending = FALSE;
}

static void
ft_session_finalize (GObject * obj)
{
	FtSession * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, FT_TYPE_SESSION, FtSession);
	(self->time_blocks == NULL) ? NULL : (self->time_blocks = (_g_list_free__g_object_unref0_ (self->time_blocks), NULL));
	_g_object_unref0 (self->entry);
	(self->priv->cycles == NULL) ? NULL : (self->priv->cycles = (_g_list_free__g_object_unref0_ (self->priv->cycles), NULL));
	G_OBJECT_CLASS (ft_session_parent_class)->finalize (obj);
}

/**
     * Ft.Session class.
     *
     * By "session" in this project we mean mostly a streak of pomodoros interleaved with breaks.
     * Session ends with either by a long break or inactivity.
     *
     * Class acts as a container. It merely defines a group of time blocks. It can be used to represent
     * historic sessions.
     */
static GType
ft_session_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (FtSessionClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) ft_session_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (FtSession), 0, (GInstanceInitFunc) ft_session_instance_init, NULL };
	GType ft_session_type_id;
	ft_session_type_id = g_type_register_static (G_TYPE_OBJECT, "FtSession", &g_define_type_info, 0);
	FtSession_private_offset = g_type_add_instance_private (ft_session_type_id, sizeof (FtSessionPrivate));
	return ft_session_type_id;
}

GType
ft_session_get_type (void)
{
	static volatile gsize ft_session_type_id__once = 0;
	if (g_once_init_enter (&ft_session_type_id__once)) {
		GType ft_session_type_id;
		ft_session_type_id = ft_session_get_type_once ();
		g_once_init_leave (&ft_session_type_id__once, ft_session_type_id);
	}
	return ft_session_type_id__once;
}

static void
_vala_ft_session_get_property (GObject * object,
                               guint property_id,
                               GValue * value,
                               GParamSpec * pspec)
{
	FtSession * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, FT_TYPE_SESSION, FtSession);
	switch (property_id) {
		case FT_SESSION_START_TIME_PROPERTY:
		g_value_set_int64 (value, ft_session_get_start_time (self));
		break;
		case FT_SESSION_END_TIME_PROPERTY:
		g_value_set_int64 (value, ft_session_get_end_time (self));
		break;
		case FT_SESSION_DURATION_PROPERTY:
		g_value_set_int64 (value, ft_session_get_duration (self));
		break;
		case FT_SESSION_EXPIRY_TIME_PROPERTY:
		g_value_set_int64 (value, ft_session_get_expiry_time (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_ft_session_set_property (GObject * object,
                               guint property_id,
                               const GValue * value,
                               GParamSpec * pspec)
{
	FtSession * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, FT_TYPE_SESSION, FtSession);
	switch (property_id) {
		case FT_SESSION_EXPIRY_TIME_PROPERTY:
		ft_session_set_expiry_time (self, g_value_get_int64 (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

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;
}

