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

/*
 * Copyright (C) 2018 Robert Roth
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 2 of the License, or (at your option) any later
 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
 * license.
 */

#include <glib-object.h>
#include <glib.h>
#include <math.h>
#include <float.h>

#define BOARD_VIEW_size 5
#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
#if !defined(VALA_EXTERN)
#if defined(_MSC_VER)
#define VALA_EXTERN __declspec(dllexport) extern
#elif __GNUC__ >= 4
#define VALA_EXTERN __attribute__((visibility("default"))) extern
#else
#define VALA_EXTERN extern
#endif
#endif

#define TYPE_BOARD_VIEW (board_view_get_type ())
#define BOARD_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_BOARD_VIEW, BoardView))
#define IS_BOARD_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_BOARD_VIEW))
#define BOARD_VIEW_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TYPE_BOARD_VIEW, BoardViewIface))

typedef struct _BoardView BoardView;
typedef struct _BoardViewIface BoardViewIface;

#define TYPE_PUZZLE_GENERATOR (puzzle_generator_get_type ())
#define PUZZLE_GENERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_PUZZLE_GENERATOR, PuzzleGenerator))
#define PUZZLE_GENERATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_PUZZLE_GENERATOR, PuzzleGeneratorClass))
#define IS_PUZZLE_GENERATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_PUZZLE_GENERATOR))
#define IS_PUZZLE_GENERATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_PUZZLE_GENERATOR))
#define PUZZLE_GENERATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_PUZZLE_GENERATOR, PuzzleGeneratorClass))

typedef struct _PuzzleGenerator PuzzleGenerator;
typedef struct _PuzzleGeneratorClass PuzzleGeneratorClass;
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
enum  {
	BOARD_VIEW_COMPLETED_SIGNAL,
	BOARD_VIEW_GAME_WON_SIGNAL,
	BOARD_VIEW_LIGHT_TOGGLED_SIGNAL,
	BOARD_VIEW_NUM_SIGNALS
};
static guint board_view_signals[BOARD_VIEW_NUM_SIGNALS] = {0};

struct _BoardViewIface {
	GTypeInterface parent_iface;
	PuzzleGenerator* (*get_puzzle_generator) (BoardView* self);
	void (*clear_level) (BoardView* self);
	void (*toggle_light) (BoardView* self, gint x, gint y, gboolean user_initiated);
	gboolean (*is_light_active) (BoardView* self, gint x, gint y);
	GObject* (*get_light_at) (BoardView* self, gint x, gint y);
};

VALA_EXTERN GType puzzle_generator_get_type (void) G_GNUC_CONST ;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (PuzzleGenerator, g_object_unref)
VALA_EXTERN GType board_view_get_type (void) G_GNUC_CONST ;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (BoardView, g_object_unref)
VALA_EXTERN PuzzleGenerator* board_view_get_puzzle_generator (BoardView* self);
VALA_EXTERN void board_view_clear_level (BoardView* self);
VALA_EXTERN void board_view_toggle_light (BoardView* self,
                              gint x,
                              gint y,
                              gboolean user_initiated);
VALA_EXTERN gboolean board_view_is_light_active (BoardView* self,
                                     gint x,
                                     gint y);
VALA_EXTERN GObject* board_view_get_light_at (BoardView* self,
                                  gint x,
                                  gint y);
VALA_EXTERN void board_view_load_level (BoardView* self,
                            gint level);
VALA_EXTERN gboolean* puzzle_generator_minimal_solution (PuzzleGenerator* self,
                                             gint solution_length,
                                             gint* result_length1,
                                             gint* result_length2);
VALA_EXTERN void board_view_handle_toggle (BoardView* self,
                               GObject* light);
VALA_EXTERN void board_view_find_light (BoardView* self,
                            GObject* light,
                            gint* x,
                            gint* y);
VALA_EXTERN void board_view_move_to (BoardView* self,
                         gint x,
                         gint y);
VALA_EXTERN gboolean board_view_is_completed (BoardView* self);
static gboolean board_view_game_won_timeout (BoardView* self);
static gboolean _board_view_game_won_timeout_gsource_func (gpointer self);
static GType board_view_get_type_once (void);

PuzzleGenerator*
board_view_get_puzzle_generator (BoardView* self)
{
	BoardViewIface* _iface_;
	g_return_val_if_fail (self != NULL, NULL);
	_iface_ = BOARD_VIEW_GET_INTERFACE (self);
	if (_iface_->get_puzzle_generator) {
		return _iface_->get_puzzle_generator (self);
	}
	return NULL;
}

void
board_view_clear_level (BoardView* self)
{
	BoardViewIface* _iface_;
	g_return_if_fail (self != NULL);
	_iface_ = BOARD_VIEW_GET_INTERFACE (self);
	if (_iface_->clear_level) {
		_iface_->clear_level (self);
	}
}

void
board_view_toggle_light (BoardView* self,
                         gint x,
                         gint y,
                         gboolean user_initiated)
{
	BoardViewIface* _iface_;
	g_return_if_fail (self != NULL);
	_iface_ = BOARD_VIEW_GET_INTERFACE (self);
	if (_iface_->toggle_light) {
		_iface_->toggle_light (self, x, y, user_initiated);
	}
}

gboolean
board_view_is_light_active (BoardView* self,
                            gint x,
                            gint y)
{
	BoardViewIface* _iface_;
	g_return_val_if_fail (self != NULL, FALSE);
	_iface_ = BOARD_VIEW_GET_INTERFACE (self);
	if (_iface_->is_light_active) {
		return _iface_->is_light_active (self, x, y);
	}
	return FALSE;
}

GObject*
board_view_get_light_at (BoardView* self,
                         gint x,
                         gint y)
{
	BoardViewIface* _iface_;
	g_return_val_if_fail (self != NULL, NULL);
	_iface_ = BOARD_VIEW_GET_INTERFACE (self);
	if (_iface_->get_light_at) {
		return _iface_->get_light_at (self, x, y);
	}
	return NULL;
}

void
board_view_load_level (BoardView* self,
                       gint level)
{
	gint solution_length = 0;
	gboolean* sol = NULL;
	PuzzleGenerator* _tmp0_;
	PuzzleGenerator* _tmp1_;
	gint _tmp2_ = 0;
	gint _tmp3_ = 0;
	gboolean* _tmp4_;
	gboolean* _tmp5_;
	gint _tmp5__length1;
	gint _tmp5__length2;
	gint sol_length1;
	gint sol_length2;
	if (level < 1) {
		level = 1;
	}
	board_view_clear_level (self);
	g_random_set_seed ((guint32) level);
	solution_length = (gint) floor ((2 * log ((gdouble) level)) + 1);
	_tmp0_ = board_view_get_puzzle_generator (self);
	_tmp1_ = _tmp0_;
	_tmp4_ = puzzle_generator_minimal_solution (_tmp1_, solution_length, &_tmp2_, &_tmp3_);
	_tmp5_ = _tmp4_;
	_tmp5__length1 = _tmp2_;
	_tmp5__length2 = _tmp3_;
	_g_object_unref0 (_tmp1_);
	sol = _tmp5_;
	sol_length1 = _tmp5__length1;
	sol_length2 = _tmp5__length2;
	{
		gint x = 0;
		x = 0;
		{
			gboolean _tmp6_ = FALSE;
			_tmp6_ = TRUE;
			while (TRUE) {
				if (!_tmp6_) {
					gint _tmp7_;
					_tmp7_ = x;
					x = _tmp7_ + 1;
				}
				_tmp6_ = FALSE;
				if (!(x < BOARD_VIEW_size)) {
					break;
				}
				{
					gint y = 0;
					y = 0;
					{
						gboolean _tmp8_ = FALSE;
						_tmp8_ = TRUE;
						while (TRUE) {
							gboolean* _tmp10_;
							gint _tmp10__length1;
							gint _tmp10__length2;
							gboolean _tmp11_;
							if (!_tmp8_) {
								gint _tmp9_;
								_tmp9_ = y;
								y = _tmp9_ + 1;
							}
							_tmp8_ = FALSE;
							if (!(y < BOARD_VIEW_size)) {
								break;
							}
							_tmp10_ = sol;
							_tmp10__length1 = sol_length1;
							_tmp10__length2 = sol_length2;
							_tmp11_ = _tmp10_[(x * _tmp10__length2) + y];
							if (_tmp11_) {
								board_view_toggle_light (self, x, y, FALSE);
							}
						}
					}
				}
			}
		}
	}
	sol = (g_free (sol), NULL);
}

void
board_view_handle_toggle (BoardView* self,
                          GObject* light)
{
	gint x = 0;
	gint y = 0;
	gint _tmp0_ = 0;
	gint _tmp1_ = 0;
	g_return_if_fail (light != NULL);
	board_view_find_light (self, light, &_tmp0_, &_tmp1_);
	x = _tmp0_;
	y = _tmp1_;
	board_view_move_to (self, x, y);
}

void
board_view_find_light (BoardView* self,
                       GObject* light,
                       gint* x,
                       gint* y)
{
	gint _vala_x = 0;
	gint _vala_y = 0;
	g_return_if_fail (light != NULL);
	_vala_y = 0;
	_vala_x = _vala_y;
	{
		gboolean _tmp0_ = FALSE;
		_vala_x = 0;
		_tmp0_ = TRUE;
		while (TRUE) {
			if (!_tmp0_) {
				gint _tmp1_;
				_tmp1_ = _vala_x;
				_vala_x = _tmp1_ + 1;
			}
			_tmp0_ = FALSE;
			if (!(_vala_x < BOARD_VIEW_size)) {
				break;
			}
			{
				gboolean _tmp2_ = FALSE;
				_vala_y = 0;
				_tmp2_ = TRUE;
				while (TRUE) {
					GObject* _tmp4_;
					GObject* _tmp5_;
					gboolean _tmp6_;
					if (!_tmp2_) {
						gint _tmp3_;
						_tmp3_ = _vala_y;
						_vala_y = _tmp3_ + 1;
					}
					_tmp2_ = FALSE;
					if (!(_vala_y < BOARD_VIEW_size)) {
						break;
					}
					_tmp4_ = board_view_get_light_at (self, _vala_x, _vala_y);
					_tmp5_ = _tmp4_;
					_tmp6_ = _tmp5_ == light;
					_g_object_unref0 (_tmp5_);
					if (_tmp6_) {
						if (x) {
							*x = _vala_x;
						}
						if (y) {
							*y = _vala_y;
						}
						return;
					}
				}
			}
		}
	}
	if (x) {
		*x = _vala_x;
	}
	if (y) {
		*y = _vala_y;
	}
}

static gboolean
_board_view_game_won_timeout_gsource_func (gpointer self)
{
	gboolean result;
	result = board_view_game_won_timeout ((BoardView*) self);
	return result;
}

void
board_view_move_to (BoardView* self,
                    gint x,
                    gint y)
{
	board_view_toggle_light (self, x, y, TRUE);
	g_signal_emit (self, board_view_signals[BOARD_VIEW_LIGHT_TOGGLED_SIGNAL], 0);
	if (board_view_is_completed (self)) {
		g_signal_emit (self, board_view_signals[BOARD_VIEW_COMPLETED_SIGNAL], 0);
		g_timeout_add_full (G_PRIORITY_DEFAULT, (guint) 300, _board_view_game_won_timeout_gsource_func, g_object_ref (self), g_object_unref);
	}
}

static gboolean
board_view_game_won_timeout (BoardView* self)
{
	gboolean result;
	g_signal_emit (self, board_view_signals[BOARD_VIEW_GAME_WON_SIGNAL], 0);
	result = G_SOURCE_REMOVE;
	return result;
}

gboolean
board_view_is_completed (BoardView* self)
{
	gboolean result;
	{
		gint x = 0;
		x = 0;
		{
			gboolean _tmp0_ = FALSE;
			_tmp0_ = TRUE;
			while (TRUE) {
				if (!_tmp0_) {
					gint _tmp1_;
					_tmp1_ = x;
					x = _tmp1_ + 1;
				}
				_tmp0_ = FALSE;
				if (!(x < BOARD_VIEW_size)) {
					break;
				}
				{
					gint y = 0;
					y = 0;
					{
						gboolean _tmp2_ = FALSE;
						_tmp2_ = TRUE;
						while (TRUE) {
							if (!_tmp2_) {
								gint _tmp3_;
								_tmp3_ = y;
								y = _tmp3_ + 1;
							}
							_tmp2_ = FALSE;
							if (!(y < BOARD_VIEW_size)) {
								break;
							}
							if (board_view_is_light_active (self, x, y)) {
								result = FALSE;
								return result;
							}
						}
					}
				}
			}
		}
	}
	result = TRUE;
	return result;
}

static void
board_view_default_init (BoardViewIface * iface,
                         gpointer iface_data)
{
	board_view_signals[BOARD_VIEW_COMPLETED_SIGNAL] = g_signal_new ("completed", TYPE_BOARD_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
	board_view_signals[BOARD_VIEW_GAME_WON_SIGNAL] = g_signal_new ("game-won", TYPE_BOARD_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
	board_view_signals[BOARD_VIEW_LIGHT_TOGGLED_SIGNAL] = g_signal_new ("light-toggled", TYPE_BOARD_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static GType
board_view_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (BoardViewIface), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) board_view_default_init, (GClassFinalizeFunc) NULL, NULL, 0, 0, (GInstanceInitFunc) NULL, NULL };
	GType board_view_type_id;
	board_view_type_id = g_type_register_static (G_TYPE_INTERFACE, "BoardView", &g_define_type_info, 0);
	g_type_interface_add_prerequisite (board_view_type_id, G_TYPE_OBJECT);
	return board_view_type_id;
}

GType
board_view_get_type (void)
{
	static volatile gsize board_view_type_id__once = 0;
	if (g_once_init_enter (&board_view_type_id__once)) {
		GType board_view_type_id;
		board_view_type_id = board_view_get_type_once ();
		g_once_init_leave (&board_view_type_id__once, board_view_type_id);
	}
	return board_view_type_id__once;
}

