/* SpringTimeline.c generated by valac 0.56.18-dirty, the Vala compiler
 * generated from SpringTimeline.vala, do not modify */

/*
 * Copyright 2025 elementary, Inc. (https://elementary.io)
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * Authored by: Leonhard Kargl <leo.kargl@proton.me>
 */

#include "gala.h"
#include <glib.h>
#include <float.h>
#include <math.h>
#include <clutter/clutter.h>
#include <glib-object.h>
#include <string.h>

#define GALA_SPRING_TIMELINE_DELTA 0.001
#define GALA_SPRING_TIMELINE_MAX_ITERATIONS 20000
#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

enum  {
	GALA_SPRING_TIMELINE_0_PROPERTY,
	GALA_SPRING_TIMELINE_VALUE_FROM_PROPERTY,
	GALA_SPRING_TIMELINE_VALUE_TO_PROPERTY,
	GALA_SPRING_TIMELINE_INITIAL_VELOCITY_PROPERTY,
	GALA_SPRING_TIMELINE_DAMPING_PROPERTY,
	GALA_SPRING_TIMELINE_MASS_PROPERTY,
	GALA_SPRING_TIMELINE_STIFFNESS_PROPERTY,
	GALA_SPRING_TIMELINE_EPSILON_PROPERTY,
	GALA_SPRING_TIMELINE_CLAMP_PROPERTY,
	GALA_SPRING_TIMELINE_NUM_PROPERTIES
};
static GParamSpec* gala_spring_timeline_properties[GALA_SPRING_TIMELINE_NUM_PROPERTIES];
#define _g_free0(var) ((var == NULL) ? NULL : (var = (g_free (var), NULL)))
enum  {
	GALA_SPRING_TIMELINE_PROGRESS_SIGNAL,
	GALA_SPRING_TIMELINE_NUM_SIGNALS
};
static guint gala_spring_timeline_signals[GALA_SPRING_TIMELINE_NUM_SIGNALS] = {0};

struct _GalaSpringTimelinePrivate {
	gdouble _value_from;
	gdouble _value_to;
	gdouble _initial_velocity;
	gdouble _damping;
	gdouble _mass;
	gdouble _stiffness;
	gdouble _epsilon;
	gboolean _clamp;
};

static gint GalaSpringTimeline_private_offset;
static gpointer gala_spring_timeline_parent_class = NULL;

static guint gala_spring_timeline_calculate_duration (GalaSpringTimeline* self);
static gboolean gala_spring_timeline_approx (GalaSpringTimeline* self,
                                      gdouble a,
                                      gdouble b,
                                      gdouble epsilon);
static gdouble gala_spring_timeline_oscillate (GalaSpringTimeline* self,
                                        guint time,
                                        gdouble** velocity);
static gdouble* _double_dup (gdouble* self);
static guint gala_spring_timeline_get_first_zero (GalaSpringTimeline* self);
static void gala_spring_timeline_real_new_frame (ClutterTimeline* base,
                                          gint time);
static void gala_spring_timeline_real_stopped (ClutterTimeline* base,
                                        gboolean is_finished);
static void gala_spring_timeline_finalize (GObject * obj);
static GType gala_spring_timeline_get_type_once (void);
static void _vala_gala_spring_timeline_get_property (GObject * object,
                                              guint property_id,
                                              GValue * value,
                                              GParamSpec * pspec);
static void _vala_gala_spring_timeline_set_property (GObject * object,
                                              guint property_id,
                                              const GValue * value,
                                              GParamSpec * pspec);

static inline gpointer
gala_spring_timeline_get_instance_private (GalaSpringTimeline* self)
{
	return G_STRUCT_MEMBER_P (self, GalaSpringTimeline_private_offset);
}

GalaSpringTimeline*
gala_spring_timeline_construct (GType object_type,
                                ClutterActor* actor,
                                gdouble value_from,
                                gdouble value_to,
                                gdouble initial_velocity,
                                gdouble damping_ratio,
                                gdouble mass,
                                gdouble stiffness)
{
	GalaSpringTimeline * self = NULL;
	gdouble critical_damping = 0.0;
	g_return_val_if_fail (actor != NULL, NULL);
	critical_damping = 2 * sqrt (mass * stiffness);
	self = (GalaSpringTimeline*) g_object_new (object_type, "actor", actor, "value-from", value_from, "value-to", value_to, "initial-velocity", initial_velocity, "damping", critical_damping * damping_ratio, "mass", mass, "stiffness", stiffness, NULL);
	clutter_timeline_set_duration ((ClutterTimeline*) self, gala_spring_timeline_calculate_duration (self));
	clutter_timeline_start ((ClutterTimeline*) self);
	return self;
}

GalaSpringTimeline*
gala_spring_timeline_new (ClutterActor* actor,
                          gdouble value_from,
                          gdouble value_to,
                          gdouble initial_velocity,
                          gdouble damping_ratio,
                          gdouble mass,
                          gdouble stiffness)
{
	return gala_spring_timeline_construct (GALA_TYPE_SPRING_TIMELINE, actor, value_from, value_to, initial_velocity, damping_ratio, mass, stiffness);
}

static gboolean
gala_spring_timeline_approx (GalaSpringTimeline* self,
                             gdouble a,
                             gdouble b,
                             gdouble epsilon)
{
	gboolean _tmp0_ = FALSE;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	if (fabs (a - b) < epsilon) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = a == b;
	}
	result = _tmp0_;
	return result;
}

static gdouble*
_double_dup (gdouble* self)
{
	gdouble* dup;
	dup = g_new0 (gdouble, 1);
	memcpy (dup, self, sizeof (gdouble));
	return dup;
}

static gpointer
__double_dup0 (gpointer self)
{
	return self ? _double_dup (self) : NULL;
}

static gdouble
gala_spring_timeline_oscillate (GalaSpringTimeline* self,
                                guint time,
                                gdouble** velocity)
{
	gdouble* _vala_velocity = NULL;
	gdouble b = 0.0;
	gdouble _tmp0_;
	gdouble m = 0.0;
	gdouble _tmp1_;
	gdouble k = 0.0;
	gdouble _tmp2_;
	gdouble v0 = 0.0;
	gdouble _tmp3_;
	gdouble t = 0.0;
	gdouble beta = 0.0;
	gdouble omega0 = 0.0;
	gdouble x0 = 0.0;
	gdouble _tmp4_;
	gdouble _tmp5_;
	gdouble envelope = 0.0;
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	_tmp0_ = self->priv->_damping;
	b = _tmp0_;
	_tmp1_ = self->priv->_mass;
	m = _tmp1_;
	_tmp2_ = self->priv->_stiffness;
	k = _tmp2_;
	_tmp3_ = self->priv->_initial_velocity;
	v0 = _tmp3_;
	t = time / 1000.0;
	beta = b / (2 * m);
	omega0 = sqrt (k / m);
	_tmp4_ = self->priv->_value_from;
	_tmp5_ = self->priv->_value_to;
	x0 = _tmp4_ - _tmp5_;
	envelope = exp ((-beta) * t);
	if (gala_spring_timeline_approx (self, beta, omega0, (gdouble) FLT_EPSILON)) {
		gdouble _tmp6_;
		gdouble* _tmp7_;
		gdouble _tmp8_;
		_tmp6_ = envelope * (((((-beta) * t) * v0) - (((beta * beta) * t) * x0)) + v0);
		_tmp7_ = __double_dup0 (&_tmp6_);
		_g_free0 (_vala_velocity);
		_vala_velocity = _tmp7_;
		_tmp8_ = self->priv->_value_to;
		result = _tmp8_ + (envelope * (x0 + (((beta * x0) + v0) * t)));
		if (velocity) {
			*velocity = _vala_velocity;
		} else {
			_g_free0 (_vala_velocity);
		}
		return result;
	}
	if (beta < omega0) {
		gdouble omega1 = 0.0;
		gdouble _tmp9_;
		gdouble* _tmp10_;
		gdouble _tmp11_;
		omega1 = sqrt ((omega0 * omega0) - (beta * beta));
		_tmp9_ = envelope * ((v0 * cos (omega1 * t)) - (((x0 * omega1) + ((((beta * beta) * x0) + (beta * v0)) / omega1)) * sin (omega1 * t)));
		_tmp10_ = __double_dup0 (&_tmp9_);
		_g_free0 (_vala_velocity);
		_vala_velocity = _tmp10_;
		_tmp11_ = self->priv->_value_to;
		result = _tmp11_ + (envelope * ((x0 * cos (omega1 * t)) + ((((beta * x0) + v0) / omega1) * sin (omega1 * t))));
		if (velocity) {
			*velocity = _vala_velocity;
		} else {
			_g_free0 (_vala_velocity);
		}
		return result;
	}
	if (beta > omega0) {
		gdouble omega2 = 0.0;
		gdouble _tmp12_;
		gdouble* _tmp13_;
		gdouble _tmp14_;
		omega2 = sqrt ((beta * beta) - (omega0 * omega0));
		_tmp12_ = envelope * ((v0 * cosh (omega2 * t)) + (((omega2 * x0) - ((((beta * beta) * x0) + (beta * v0)) / omega2)) * sinh (omega2 * t)));
		_tmp13_ = __double_dup0 (&_tmp12_);
		_g_free0 (_vala_velocity);
		_vala_velocity = _tmp13_;
		_tmp14_ = self->priv->_value_to;
		result = _tmp14_ + (envelope * ((x0 * cosh (omega2 * t)) + ((((beta * x0) + v0) / omega2) * sinh (omega2 * t))));
		if (velocity) {
			*velocity = _vala_velocity;
		} else {
			_g_free0 (_vala_velocity);
		}
		return result;
	}
	g_assert_not_reached ();
}

static guint
gala_spring_timeline_get_first_zero (GalaSpringTimeline* self)
{
	guint i = 0U;
	gdouble y = 0.0;
	guint result;
	g_return_val_if_fail (self != NULL, 0U);
	i = (guint) 1;
	y = gala_spring_timeline_oscillate (self, i, NULL);
	while (TRUE) {
		gboolean _tmp0_ = FALSE;
		gboolean _tmp1_ = FALSE;
		gdouble _tmp2_;
		gdouble _tmp3_;
		guint _tmp11_;
		_tmp2_ = self->priv->_value_to;
		_tmp3_ = self->priv->_value_from;
		if ((_tmp2_ - _tmp3_) > DBL_EPSILON) {
			gdouble _tmp4_;
			gdouble _tmp5_;
			_tmp4_ = self->priv->_value_to;
			_tmp5_ = self->priv->_epsilon;
			_tmp1_ = (_tmp4_ - y) > _tmp5_;
		} else {
			_tmp1_ = FALSE;
		}
		if (_tmp1_) {
			_tmp0_ = TRUE;
		} else {
			gboolean _tmp6_ = FALSE;
			gdouble _tmp7_;
			gdouble _tmp8_;
			_tmp7_ = self->priv->_value_from;
			_tmp8_ = self->priv->_value_to;
			if ((_tmp7_ - _tmp8_) > DBL_EPSILON) {
				gdouble _tmp9_;
				gdouble _tmp10_;
				_tmp9_ = self->priv->_value_to;
				_tmp10_ = self->priv->_epsilon;
				_tmp6_ = (y - _tmp9_) > _tmp10_;
			} else {
				_tmp6_ = FALSE;
			}
			_tmp0_ = _tmp6_;
		}
		if (!_tmp0_) {
			break;
		}
		if (i > ((guint) GALA_SPRING_TIMELINE_MAX_ITERATIONS)) {
			result = (guint) 0;
			return result;
		}
		i = i + 1;
		_tmp11_ = i;
		y = gala_spring_timeline_oscillate (self, _tmp11_, NULL);
	}
	result = i;
	return result;
}

static guint
gala_spring_timeline_calculate_duration (GalaSpringTimeline* self)
{
	gdouble beta = 0.0;
	gdouble _tmp0_;
	gdouble _tmp1_;
	gdouble omega0 = 0.0;
	gdouble x0 = 0.0;
	gdouble y0 = 0.0;
	gdouble x1 = 0.0;
	gdouble y1 = 0.0;
	gdouble m = 0.0;
	gint i = 0;
	gboolean _tmp2_ = FALSE;
	gboolean _tmp3_;
	gdouble _tmp6_;
	gdouble _tmp7_;
	gdouble _tmp8_;
	gboolean _tmp9_ = FALSE;
	gdouble _tmp10_;
	guint result;
	g_return_val_if_fail (self != NULL, 0U);
	_tmp0_ = self->priv->_damping;
	_tmp1_ = self->priv->_mass;
	beta = _tmp0_ / (2 * _tmp1_);
	i = 0;
	if (gala_spring_timeline_approx (self, beta, (gdouble) 0, DBL_EPSILON)) {
		_tmp2_ = TRUE;
	} else {
		_tmp2_ = beta < ((gdouble) 0);
	}
	if (_tmp2_) {
		result = (guint) -1;
		return result;
	}
	_tmp3_ = self->priv->_clamp;
	if (_tmp3_) {
		gdouble _tmp4_;
		gdouble _tmp5_;
		_tmp4_ = self->priv->_value_to;
		_tmp5_ = self->priv->_value_from;
		if (gala_spring_timeline_approx (self, _tmp4_, _tmp5_, DBL_EPSILON)) {
			result = (guint) 0;
			return result;
		}
		result = gala_spring_timeline_get_first_zero (self);
		return result;
	}
	_tmp6_ = self->priv->_stiffness;
	_tmp7_ = self->priv->_mass;
	omega0 = sqrt (_tmp6_ / _tmp7_);
	_tmp8_ = self->priv->_epsilon;
	x0 = (-log (_tmp8_)) / beta;
	if (gala_spring_timeline_approx (self, beta, omega0, (gdouble) FLT_EPSILON)) {
		_tmp9_ = TRUE;
	} else {
		_tmp9_ = beta < omega0;
	}
	if (_tmp9_) {
		result = (guint) (x0 * 1000);
		return result;
	}
	y0 = gala_spring_timeline_oscillate (self, (guint) (x0 * 1000), NULL);
	m = (gala_spring_timeline_oscillate (self, (guint) ((x0 + GALA_SPRING_TIMELINE_DELTA) * 1000), NULL) - y0) / GALA_SPRING_TIMELINE_DELTA;
	_tmp10_ = self->priv->_value_to;
	x1 = ((_tmp10_ - y0) + (m * x0)) / m;
	y1 = gala_spring_timeline_oscillate (self, (guint) (x1 * 1000), NULL);
	while (TRUE) {
		gdouble _tmp11_;
		gdouble _tmp12_;
		gdouble _tmp13_;
		gint _tmp14_;
		_tmp11_ = self->priv->_value_to;
		_tmp12_ = self->priv->_epsilon;
		if (!(fabs (_tmp11_ - y1) > _tmp12_)) {
			break;
		}
		if (i > 1000) {
			result = (guint) 0;
			return result;
		}
		x0 = x1;
		y0 = y1;
		m = (gala_spring_timeline_oscillate (self, (guint) ((x0 + GALA_SPRING_TIMELINE_DELTA) * 1000), NULL) - y0) / GALA_SPRING_TIMELINE_DELTA;
		_tmp13_ = self->priv->_value_to;
		x1 = ((_tmp13_ - y0) + (m * x0)) / m;
		y1 = gala_spring_timeline_oscillate (self, (guint) (x1 * 1000), NULL);
		_tmp14_ = i;
		i = _tmp14_ + 1;
	}
	result = (guint) (x1 * 1000);
	return result;
}

static void
gala_spring_timeline_real_new_frame (ClutterTimeline* base,
                                     gint time)
{
	GalaSpringTimeline * self;
	gdouble velocity = 0.0;
	gdouble val = 0.0;
	gdouble* _tmp0_ = NULL;
	gdouble _tmp1_;
	gdouble* _tmp2_;
	gdouble _tmp3_;
	self = (GalaSpringTimeline*) base;
	_tmp1_ = gala_spring_timeline_oscillate (self, (guint) time, &_tmp0_);
	_tmp2_ = _tmp0_;
	velocity = *_tmp2_;
	_tmp3_ = _tmp1_;
	_g_free0 (_tmp2_);
	val = _tmp3_;
	g_signal_emit (self, gala_spring_timeline_signals[GALA_SPRING_TIMELINE_PROGRESS_SIGNAL], 0, val);
}

static void
gala_spring_timeline_real_stopped (ClutterTimeline* base,
                                   gboolean is_finished)
{
	GalaSpringTimeline * self;
	self = (GalaSpringTimeline*) base;
	if (is_finished) {
		gdouble _tmp0_;
		_tmp0_ = self->priv->_value_to;
		g_signal_emit (self, gala_spring_timeline_signals[GALA_SPRING_TIMELINE_PROGRESS_SIGNAL], 0, _tmp0_);
	}
}

gdouble
gala_spring_timeline_get_value_from (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_value_from;
	return result;
}

static void
gala_spring_timeline_set_value_from (GalaSpringTimeline* self,
                                     gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_value_from (self);
	if (old_value != value) {
		self->priv->_value_from = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_VALUE_FROM_PROPERTY]);
	}
}

gdouble
gala_spring_timeline_get_value_to (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_value_to;
	return result;
}

static void
gala_spring_timeline_set_value_to (GalaSpringTimeline* self,
                                   gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_value_to (self);
	if (old_value != value) {
		self->priv->_value_to = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_VALUE_TO_PROPERTY]);
	}
}

gdouble
gala_spring_timeline_get_initial_velocity (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_initial_velocity;
	return result;
}

static void
gala_spring_timeline_set_initial_velocity (GalaSpringTimeline* self,
                                           gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_initial_velocity (self);
	if (old_value != value) {
		self->priv->_initial_velocity = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_INITIAL_VELOCITY_PROPERTY]);
	}
}

gdouble
gala_spring_timeline_get_damping (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_damping;
	return result;
}

static void
gala_spring_timeline_set_damping (GalaSpringTimeline* self,
                                  gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_damping (self);
	if (old_value != value) {
		self->priv->_damping = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_DAMPING_PROPERTY]);
	}
}

gdouble
gala_spring_timeline_get_mass (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_mass;
	return result;
}

static void
gala_spring_timeline_set_mass (GalaSpringTimeline* self,
                               gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_mass (self);
	if (old_value != value) {
		self->priv->_mass = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_MASS_PROPERTY]);
	}
}

gdouble
gala_spring_timeline_get_stiffness (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_stiffness;
	return result;
}

static void
gala_spring_timeline_set_stiffness (GalaSpringTimeline* self,
                                    gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_stiffness (self);
	if (old_value != value) {
		self->priv->_stiffness = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_STIFFNESS_PROPERTY]);
	}
}

gdouble
gala_spring_timeline_get_epsilon (GalaSpringTimeline* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_epsilon;
	return result;
}

static void
gala_spring_timeline_set_epsilon (GalaSpringTimeline* self,
                                  gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_epsilon (self);
	if (old_value != value) {
		self->priv->_epsilon = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_EPSILON_PROPERTY]);
	}
}

gboolean
gala_spring_timeline_get_clamp (GalaSpringTimeline* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_clamp;
	return result;
}

static void
gala_spring_timeline_set_clamp (GalaSpringTimeline* self,
                                gboolean value)
{
	gboolean old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_spring_timeline_get_clamp (self);
	if (old_value != value) {
		self->priv->_clamp = value;
		g_object_notify_by_pspec ((GObject *) self, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_CLAMP_PROPERTY]);
	}
}

static void
gala_spring_timeline_class_init (GalaSpringTimelineClass * klass,
                                 gpointer klass_data)
{
	gala_spring_timeline_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GalaSpringTimeline_private_offset);
	((ClutterTimelineClass *) klass)->new_frame = (void (*) (ClutterTimeline*, gint)) gala_spring_timeline_real_new_frame;
	((ClutterTimelineClass *) klass)->stopped = (void (*) (ClutterTimeline*, gboolean)) gala_spring_timeline_real_stopped;
	G_OBJECT_CLASS (klass)->get_property = _vala_gala_spring_timeline_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_gala_spring_timeline_set_property;
	G_OBJECT_CLASS (klass)->finalize = gala_spring_timeline_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_VALUE_FROM_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_VALUE_FROM_PROPERTY] = g_param_spec_double ("value-from", "value-from", "value-from", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_VALUE_TO_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_VALUE_TO_PROPERTY] = g_param_spec_double ("value-to", "value-to", "value-to", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_INITIAL_VELOCITY_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_INITIAL_VELOCITY_PROPERTY] = g_param_spec_double ("initial-velocity", "initial-velocity", "initial-velocity", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_DAMPING_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_DAMPING_PROPERTY] = g_param_spec_double ("damping", "damping", "damping", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_MASS_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_MASS_PROPERTY] = g_param_spec_double ("mass", "mass", "mass", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_STIFFNESS_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_STIFFNESS_PROPERTY] = g_param_spec_double ("stiffness", "stiffness", "stiffness", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_EPSILON_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_EPSILON_PROPERTY] = g_param_spec_double ("epsilon", "epsilon", "epsilon", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0001, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_SPRING_TIMELINE_CLAMP_PROPERTY, gala_spring_timeline_properties[GALA_SPRING_TIMELINE_CLAMP_PROPERTY] = g_param_spec_boolean ("clamp", "clamp", "clamp", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	gala_spring_timeline_signals[GALA_SPRING_TIMELINE_PROGRESS_SIGNAL] = g_signal_new ("progress", GALA_TYPE_SPRING_TIMELINE, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE);
}

static void
gala_spring_timeline_instance_init (GalaSpringTimeline * self,
                                    gpointer klass)
{
	self->priv = gala_spring_timeline_get_instance_private (self);
	self->priv->_epsilon = 0.0001;
}

static void
gala_spring_timeline_finalize (GObject * obj)
{
	GalaSpringTimeline * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_SPRING_TIMELINE, GalaSpringTimeline);
	G_OBJECT_CLASS (gala_spring_timeline_parent_class)->finalize (obj);
}

/**
 * Based on libadwaita's AdwSpringAnimation
 * [[https://gitlab.gnome.org/GNOME/libadwaita/-/blob/main/src/adw-spring-animation.c?ref_type=heads]]
 *
 * For documentation about the params refer to [[https://valadoc.org/libadwaita-1/Adw.SpringAnimation.html]]
 * and [[https://valadoc.org/libadwaita-1/Adw.SpringParams.html]].
 */
 G_GNUC_NO_INLINE static GType
gala_spring_timeline_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GalaSpringTimelineClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gala_spring_timeline_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GalaSpringTimeline), 0, (GInstanceInitFunc) gala_spring_timeline_instance_init, NULL };
	GType gala_spring_timeline_type_id;
	gala_spring_timeline_type_id = g_type_register_static (clutter_timeline_get_type (), "GalaSpringTimeline", &g_define_type_info, 0);
	GalaSpringTimeline_private_offset = g_type_add_instance_private (gala_spring_timeline_type_id, sizeof (GalaSpringTimelinePrivate));
	return gala_spring_timeline_type_id;
}

GType
gala_spring_timeline_get_type (void)
{
	static gsize gala_spring_timeline_type_id__once = 0;
	if (g_once_init_enter (&gala_spring_timeline_type_id__once)) {
		GType gala_spring_timeline_type_id;
		gala_spring_timeline_type_id = gala_spring_timeline_get_type_once ();
		g_once_init_leave (&gala_spring_timeline_type_id__once, gala_spring_timeline_type_id);
	}
	return gala_spring_timeline_type_id__once;
}

static void
_vala_gala_spring_timeline_get_property (GObject * object,
                                         guint property_id,
                                         GValue * value,
                                         GParamSpec * pspec)
{
	GalaSpringTimeline * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GALA_TYPE_SPRING_TIMELINE, GalaSpringTimeline);
	switch (property_id) {
		case GALA_SPRING_TIMELINE_VALUE_FROM_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_value_from (self));
		break;
		case GALA_SPRING_TIMELINE_VALUE_TO_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_value_to (self));
		break;
		case GALA_SPRING_TIMELINE_INITIAL_VELOCITY_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_initial_velocity (self));
		break;
		case GALA_SPRING_TIMELINE_DAMPING_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_damping (self));
		break;
		case GALA_SPRING_TIMELINE_MASS_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_mass (self));
		break;
		case GALA_SPRING_TIMELINE_STIFFNESS_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_stiffness (self));
		break;
		case GALA_SPRING_TIMELINE_EPSILON_PROPERTY:
		g_value_set_double (value, gala_spring_timeline_get_epsilon (self));
		break;
		case GALA_SPRING_TIMELINE_CLAMP_PROPERTY:
		g_value_set_boolean (value, gala_spring_timeline_get_clamp (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_gala_spring_timeline_set_property (GObject * object,
                                         guint property_id,
                                         const GValue * value,
                                         GParamSpec * pspec)
{
	GalaSpringTimeline * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GALA_TYPE_SPRING_TIMELINE, GalaSpringTimeline);
	switch (property_id) {
		case GALA_SPRING_TIMELINE_VALUE_FROM_PROPERTY:
		gala_spring_timeline_set_value_from (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_VALUE_TO_PROPERTY:
		gala_spring_timeline_set_value_to (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_INITIAL_VELOCITY_PROPERTY:
		gala_spring_timeline_set_initial_velocity (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_DAMPING_PROPERTY:
		gala_spring_timeline_set_damping (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_MASS_PROPERTY:
		gala_spring_timeline_set_mass (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_STIFFNESS_PROPERTY:
		gala_spring_timeline_set_stiffness (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_EPSILON_PROPERTY:
		gala_spring_timeline_set_epsilon (self, g_value_get_double (value));
		break;
		case GALA_SPRING_TIMELINE_CLAMP_PROPERTY:
		gala_spring_timeline_set_clamp (self, g_value_get_boolean (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

