/* gcalc-math-equation-manager.c generated by valac 0.56.18-dirty, the Vala compiler
 * generated from gcalc-math-equation-manager.vala, do not modify */

/* gcalc-math-equation-manager.vala
 *
 * Copyright (C) 2018  Daniel Espinosa <esodan@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *      Daniel Espinosa <esodan@gmail.com>
 */

#include "gcalc/gcalc.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gee.h>
#include <glib-object.h>
#include "gcalc.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)))

static GCalcMathVariable* gcalc_math_equation_manager_real_find_variable (GCalcMathEquationManager* self,
                                                                   const gchar* name);
static GType gcalc_math_equation_manager_get_type_once (void);

/**
   * Set of variables or parameters defined in the set of equations.
   */
static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static GCalcMathVariable*
gcalc_math_equation_manager_real_find_variable (GCalcMathEquationManager* self,
                                                const gchar* name)
{
	GCalcMathVariable* res = NULL;
	GCalcMathVariable* result;
	g_return_val_if_fail (name != NULL, NULL);
	res = NULL;
	{
		GCalcExpressionContainer* _e_list = NULL;
		GCalcExpressionContainer* _tmp0_;
		GCalcExpressionContainer* _tmp1_;
		gint _e_size = 0;
		GCalcExpressionContainer* _tmp2_;
		gint _tmp3_;
		gint _tmp4_;
		gint _e_index = 0;
		_tmp0_ = gcalc_math_equation_manager_get_equations (self);
		_tmp1_ = _tmp0_;
		_e_list = _tmp1_;
		_tmp2_ = _e_list;
		_tmp3_ = gee_abstract_collection_get_size ((GeeAbstractCollection*) _tmp2_);
		_tmp4_ = _tmp3_;
		_e_size = _tmp4_;
		_e_index = -1;
		while (TRUE) {
			gint _tmp5_;
			gint _tmp6_;
			GCalcMathExpression* e = NULL;
			GCalcExpressionContainer* _tmp7_;
			gpointer _tmp8_;
			GCalcMathEquation* eq = NULL;
			GCalcMathExpression* _tmp9_;
			GCalcMathEquation* _tmp10_;
			GCalcMathExpression* _tmp11_;
			GCalcMathVariable* v = NULL;
			GCalcMathEquation* _tmp12_;
			GCalcExpressionHashMap* _tmp13_;
			GCalcExpressionHashMap* _tmp14_;
			GCalcMathExpression* _tmp15_;
			GCalcMathVariable* _tmp16_;
			GCalcMathVariable* _tmp17_;
			_e_index = _e_index + 1;
			_tmp5_ = _e_index;
			_tmp6_ = _e_size;
			if (!(_tmp5_ < _tmp6_)) {
				break;
			}
			_tmp7_ = _e_list;
			_tmp8_ = gee_abstract_list_get ((GeeAbstractList*) _tmp7_, _e_index);
			e = (GCalcMathExpression*) _tmp8_;
			_tmp9_ = e;
			_tmp10_ = _g_object_ref0 (GCALC_IS_MATH_EQUATION (_tmp9_) ? ((GCalcMathEquation*) _tmp9_) : NULL);
			eq = _tmp10_;
			_tmp11_ = e;
			if (_tmp11_ == NULL) {
				_g_object_unref0 (eq);
				_g_object_unref0 (e);
				continue;
			}
			_tmp12_ = eq;
			_tmp13_ = gcalc_math_equation_get_variables (_tmp12_);
			_tmp14_ = _tmp13_;
			_tmp15_ = gcalc_expression_hash_map_find_named (_tmp14_, name);
			_tmp16_ = GCALC_IS_MATH_VARIABLE (_tmp15_) ? ((GCalcMathVariable*) _tmp15_) : NULL;
			if (_tmp16_ == NULL) {
				_g_object_unref0 (_tmp15_);
			}
			v = _tmp16_;
			_tmp17_ = v;
			if (_tmp17_ != NULL) {
				GCalcMathVariable* _tmp18_;
				GCalcMathVariable* _tmp19_;
				_tmp18_ = v;
				_tmp19_ = _g_object_ref0 (_tmp18_);
				_g_object_unref0 (res);
				res = _tmp19_;
				_g_object_unref0 (v);
				_g_object_unref0 (eq);
				_g_object_unref0 (e);
				break;
			}
			_g_object_unref0 (v);
			_g_object_unref0 (eq);
			_g_object_unref0 (e);
		}
	}
	result = res;
	return result;
}

GCalcMathVariable*
gcalc_math_equation_manager_find_variable (GCalcMathEquationManager* self,
                                           const gchar* name)
{
	GCalcMathEquationManagerIface* _iface_;
	g_return_val_if_fail (self != NULL, NULL);
	_iface_ = GCALC_MATH_EQUATION_MANAGER_GET_INTERFACE (self);
	if (_iface_->find_variable) {
		return _iface_->find_variable (self, name);
	}
	return NULL;
}

GCalcExpressionContainer*
gcalc_math_equation_manager_get_equations (GCalcMathEquationManager* self)
{
	GCalcMathEquationManagerIface* _iface_;
	g_return_val_if_fail (self != NULL, NULL);
	_iface_ = GCALC_MATH_EQUATION_MANAGER_GET_INTERFACE (self);
	if (_iface_->get_equations) {
		return _iface_->get_equations (self);
	}
	return NULL;
}

GCalcExpressionContainer*
gcalc_math_equation_manager_get_functions (GCalcMathEquationManager* self)
{
	GCalcMathEquationManagerIface* _iface_;
	g_return_val_if_fail (self != NULL, NULL);
	_iface_ = GCALC_MATH_EQUATION_MANAGER_GET_INTERFACE (self);
	if (_iface_->get_functions) {
		return _iface_->get_functions (self);
	}
	return NULL;
}

static void
gcalc_math_equation_manager_default_init (GCalcMathEquationManagerIface * iface,
                                          gpointer iface_data)
{
	/**
	   * Set of equations. They can be related or not.
	   */
	g_object_interface_install_property (iface, g_param_spec_object ("equations", "equations", "equations", GCALC_TYPE_EXPRESSION_CONTAINER, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	   * Set of functions defined to be possibily used in equations.
	   */
	g_object_interface_install_property (iface, g_param_spec_object ("functions", "functions", "functions", GCALC_TYPE_EXPRESSION_CONTAINER, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	iface->find_variable = gcalc_math_equation_manager_real_find_variable;
}

/**
 * Equation manager, holding a set of equations and variables.
 *
 * Equations can depend on calculated expression from variables or
 * values set to variables when they are a {@link MathParameter}
 *
 * In the next code you create a parser, then use {@link Parser.parse}
 * to add the parsed equation to an equation manager.
 * {{{
 *  var parser = new Parser ();
 *  var eqman = new EquationManager ();
 *  parser.parse ("3*5", eqman);
 *  var eq = eqman.equations.get_item (0) as MathEquation;
 *  var res = eq.solve ();
 *  var c = (MathConstant) res;
 *  // Result will be 15
 *  stdout.printf ("%g", c.real ());
 * }}}
 *
 * Is possible to create expressions, set to a variable, add to an equation manager
 * create an expression using that variable to add to the manager; then solve the
 * dependant equation and then the variable will be evalated too, in order to produce
 * a result:
 * {{{
 *  var parser = new Parser ();
 *  var eqman = new EquationManager ();
 *  parser.parse ("x=3*5", eqman);
 *  parser.parse ("2*x+7*x^2", eqman);
 *  var eq = eqman.equations.get_item (1) as MathEquation;
 *  var res = eq.solve ();
 *  var c = (MathConstant) res;
 *  // Result will be 1605
 *  stdout.printf ("%g", c.real ());
 * }}}
 *
 * Is possible to define parameters instead of {@link MathVariable}. To do so,
 * fine them at parsing time, then you can get it to change its value, to
 * evaluate the dependant equation.
 * {{{
 *  var parser = new Parser ();
 *  var eqman = new EquationManager ();
 *  parser.parse ("$param1*5", eqman);
 *  var eq = eqman.equations.get_item (1) as MathEquation;
 *  var p = eqman.variable.find_named ("param1");
 *  p.set_value (5.0);
 *  var res = eq.solve ();
 *  var c = (MathConstant) res;
 *  // Result will be 25
 *  stdout.printf ("%g", c.real ());
 * }}}
 */
static GType
gcalc_math_equation_manager_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GCalcMathEquationManagerIface), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gcalc_math_equation_manager_default_init, (GClassFinalizeFunc) NULL, NULL, 0, 0, (GInstanceInitFunc) NULL, NULL };
	GType gcalc_math_equation_manager_type_id;
	gcalc_math_equation_manager_type_id = g_type_register_static (G_TYPE_INTERFACE, "GCalcMathEquationManager", &g_define_type_info, 0);
	g_type_interface_add_prerequisite (gcalc_math_equation_manager_type_id, G_TYPE_OBJECT);
	return gcalc_math_equation_manager_type_id;
}

GType
gcalc_math_equation_manager_get_type (void)
{
	static volatile gsize gcalc_math_equation_manager_type_id__once = 0;
	if (g_once_init_enter (&gcalc_math_equation_manager_type_id__once)) {
		GType gcalc_math_equation_manager_type_id;
		gcalc_math_equation_manager_type_id = gcalc_math_equation_manager_get_type_once ();
		g_once_init_leave (&gcalc_math_equation_manager_type_id__once, gcalc_math_equation_manager_type_id);
	}
	return gcalc_math_equation_manager_type_id__once;
}

