/* sudoku-game.c generated by valac 0.50.3, the Vala compiler
 * generated from sudoku-game.vala, do not modify */

/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Copyright © 2014 Parin Porecha
 * Copyright © 2014 Michael Catanzaro
 *
 * This file is part of GNOME Sudoku.
 *
 * GNOME Sudoku 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 3 of the License, or
 * (at your option) any later version.
 *
 * GNOME Sudoku 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNOME Sudoku. If not, see <http://www.gnu.org/licenses/>.
 */

#include "libsudoku.h"
#include <glib.h>
#include <gee.h>
#include <glib-object.h>
#include <float.h>
#include <math.h>

#define SUDOKU_GAME_TYPE_UNDO_ITEM (sudoku_game_undo_item_get_type ())
typedef struct _SudokuGameUndoItem SudokuGameUndoItem;
enum  {
	SUDOKU_GAME_0_PROPERTY,
	SUDOKU_GAME_PAUSED_PROPERTY,
	SUDOKU_GAME_NUM_PROPERTIES
};
static GParamSpec* sudoku_game_properties[SUDOKU_GAME_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_timer_destroy0(var) ((var == NULL) ? NULL : (var = (g_timer_destroy (var), NULL)))
#define _sudoku_game_undo_item_free0(var) ((var == NULL) ? NULL : (var = (sudoku_game_undo_item_free (var), NULL)))
enum  {
	SUDOKU_GAME_TICK_SIGNAL,
	SUDOKU_GAME_PAUSED_CHANGED_SIGNAL,
	SUDOKU_GAME_CELL_CHANGED_SIGNAL,
	SUDOKU_GAME_NUM_SIGNALS
};
static guint sudoku_game_signals[SUDOKU_GAME_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 _SudokuGameUndoItem {
	gint row;
	gint col;
	gint val;
	gboolean* earmarks;
	gint earmarks_length1;
	gint _earmarks_size_;
};

struct _SudokuGamePrivate {
	guint clock_timeout;
	gboolean _paused;
	GeeList* undostack;
	GeeList* redostack;
};

static gint SudokuGame_private_offset;
static gpointer sudoku_game_parent_class = NULL;

static GType sudoku_game_undo_item_get_type (void) G_GNUC_CONST G_GNUC_UNUSED;
static SudokuGameUndoItem* sudoku_game_undo_item_dup (const SudokuGameUndoItem* self);
static void sudoku_game_undo_item_free (SudokuGameUndoItem* self);
static void sudoku_game_undo_item_copy (const SudokuGameUndoItem* self,
                                 SudokuGameUndoItem* dest);
static void sudoku_game_undo_item_destroy (SudokuGameUndoItem* self);
static void sudoku_game_apply_stack (SudokuGame* self,
                              GeeList* from,
                              GeeList* to);
static void sudoku_game_add_to_stack (SudokuGame* self,
                               GeeList* stack,
                               gint r,
                               gint c,
                               gint v,
                               gboolean* e,
                               gint e_length1);
static gboolean* _vala_array_dup9 (gboolean* self,
                            gint length);
static gboolean sudoku_game_timeout_cb (SudokuGame* self);
static gboolean _sudoku_game_timeout_cb_gsource_func (gpointer self);
static void sudoku_game_set_paused (SudokuGame* self,
                             gboolean value);
static void g_cclosure_user_marshal_VOID__INT_INT_INT_INT (GClosure * closure,
                                                    GValue * return_value,
                                                    guint n_param_values,
                                                    const GValue * param_values,
                                                    gpointer invocation_hint,
                                                    gpointer marshal_data);
static gboolean* _vala_array_dup10 (gboolean* self,
                             gint length);
static void sudoku_game_finalize (GObject * obj);
static GType sudoku_game_get_type_once (void);
static void _vala_sudoku_game_get_property (GObject * object,
                                     guint property_id,
                                     GValue * value,
                                     GParamSpec * pspec);
static void _vala_sudoku_game_set_property (GObject * object,
                                     guint property_id,
                                     const GValue * value,
                                     GParamSpec * pspec);

static inline gpointer
sudoku_game_get_instance_private (SudokuGame* self)
{
	return G_STRUCT_MEMBER_P (self, SudokuGame_private_offset);
}

gboolean
sudoku_game_is_undostack_null (SudokuGame* self)
{
	GeeList* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	gboolean result = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->priv->undostack;
	_tmp1_ = gee_collection_get_size ((GeeCollection*) _tmp0_);
	_tmp2_ = _tmp1_;
	result = _tmp2_ == 0;
	return result;
}

gboolean
sudoku_game_is_redostack_null (SudokuGame* self)
{
	GeeList* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	gboolean result = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->priv->redostack;
	_tmp1_ = gee_collection_get_size ((GeeCollection*) _tmp0_);
	_tmp2_ = _tmp1_;
	result = _tmp2_ == 0;
	return result;
}

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

SudokuGame*
sudoku_game_construct (GType object_type,
                       SudokuBoard* board)
{
	SudokuGame * self = NULL;
	SudokuBoard* _tmp0_;
	GTimer* _tmp1_;
	GeeArrayList* _tmp2_;
	GeeArrayList* _tmp3_;
	g_return_val_if_fail (board != NULL, NULL);
	self = (SudokuGame*) g_object_new (object_type, NULL);
	_tmp0_ = _g_object_ref0 (board);
	_g_object_unref0 (self->board);
	self->board = _tmp0_;
	self->mode = GAME_MODE_PLAY;
	_tmp1_ = g_timer_new ();
	_g_timer_destroy0 (self->timer);
	self->timer = _tmp1_;
	_tmp2_ = gee_array_list_new (SUDOKU_GAME_TYPE_UNDO_ITEM, (GBoxedCopyFunc) sudoku_game_undo_item_dup, (GDestroyNotify) sudoku_game_undo_item_free, NULL, NULL, NULL);
	_g_object_unref0 (self->priv->undostack);
	self->priv->undostack = (GeeList*) _tmp2_;
	_tmp3_ = gee_array_list_new (SUDOKU_GAME_TYPE_UNDO_ITEM, (GBoxedCopyFunc) sudoku_game_undo_item_dup, (GDestroyNotify) sudoku_game_undo_item_free, NULL, NULL, NULL);
	_g_object_unref0 (self->priv->redostack);
	self->priv->redostack = (GeeList*) _tmp3_;
	return self;
}

SudokuGame*
sudoku_game_new (SudokuBoard* board)
{
	return sudoku_game_construct (TYPE_SUDOKU_GAME, board);
}

void
sudoku_game_enable_earmark (SudokuGame* self,
                            gint row,
                            gint col,
                            gint k_no)
{
	gint old_val = 0;
	SudokuBoard* _tmp0_;
	gboolean* old_earmarks = NULL;
	SudokuBoard* _tmp1_;
	gint _tmp2_ = 0;
	gboolean* _tmp3_;
	gint old_earmarks_length1;
	gint _old_earmarks_size_;
	SudokuBoard* _tmp4_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->board;
	old_val = sudoku_board_get (_tmp0_, row, col);
	_tmp1_ = self->board;
	_tmp3_ = sudoku_board_get_earmarks (_tmp1_, row, col, &_tmp2_);
	old_earmarks = _tmp3_;
	old_earmarks_length1 = _tmp2_;
	_old_earmarks_size_ = old_earmarks_length1;
	sudoku_game_update_undo (self, row, col, old_val, old_earmarks, (gint) old_earmarks_length1);
	_tmp4_ = self->board;
	sudoku_board_enable_earmark (_tmp4_, row, col, k_no);
	old_earmarks = (g_free (old_earmarks), NULL);
}

void
sudoku_game_disable_earmark (SudokuGame* self,
                             gint row,
                             gint col,
                             gint k_no)
{
	gint old_val = 0;
	SudokuBoard* _tmp0_;
	gboolean* old_earmarks = NULL;
	SudokuBoard* _tmp1_;
	gint _tmp2_ = 0;
	gboolean* _tmp3_;
	gint old_earmarks_length1;
	gint _old_earmarks_size_;
	SudokuBoard* _tmp4_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->board;
	old_val = sudoku_board_get (_tmp0_, row, col);
	_tmp1_ = self->board;
	_tmp3_ = sudoku_board_get_earmarks (_tmp1_, row, col, &_tmp2_);
	old_earmarks = _tmp3_;
	old_earmarks_length1 = _tmp2_;
	_old_earmarks_size_ = old_earmarks_length1;
	sudoku_game_update_undo (self, row, col, old_val, old_earmarks, (gint) old_earmarks_length1);
	_tmp4_ = self->board;
	sudoku_board_disable_earmark (_tmp4_, row, col, k_no);
	old_earmarks = (g_free (old_earmarks), NULL);
}

void
sudoku_game_insert (SudokuGame* self,
                    gint row,
                    gint col,
                    gint val)
{
	gint old_val = 0;
	SudokuBoard* _tmp0_;
	gboolean* old_earmarks = NULL;
	SudokuBoard* _tmp1_;
	gint _tmp2_ = 0;
	gboolean* _tmp3_;
	gint old_earmarks_length1;
	gint _old_earmarks_size_;
	gboolean* _tmp4_;
	gint _tmp4__length1;
	GameMode _tmp5_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->board;
	old_val = sudoku_board_get (_tmp0_, row, col);
	_tmp1_ = self->board;
	_tmp3_ = sudoku_board_get_earmarks (_tmp1_, row, col, &_tmp2_);
	old_earmarks = _tmp3_;
	old_earmarks_length1 = _tmp2_;
	_old_earmarks_size_ = old_earmarks_length1;
	_tmp4_ = old_earmarks;
	_tmp4__length1 = old_earmarks_length1;
	sudoku_game_update_undo (self, row, col, old_val, _tmp4_, (gint) _tmp4__length1);
	_tmp5_ = self->mode;
	if (_tmp5_ == GAME_MODE_CREATE) {
		SudokuBoard* _tmp6_;
		SudokuBoard* _tmp7_;
		gboolean* _tmp8_;
		gint _tmp8__length1;
		gint _tmp8__length2;
		_tmp6_ = self->board;
		sudoku_board_insert (_tmp6_, row, col, val, TRUE);
		_tmp7_ = self->board;
		_tmp8_ = _tmp7_->is_fixed;
		_tmp8__length1 = _tmp7_->is_fixed_length1;
		_tmp8__length2 = _tmp7_->is_fixed_length2;
		_tmp8_[(row * _tmp8__length2) + col] = TRUE;
	} else {
		SudokuBoard* _tmp9_;
		_tmp9_ = self->board;
		sudoku_board_insert (_tmp9_, row, col, val, FALSE);
	}
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_CELL_CHANGED_SIGNAL], 0, row, col, old_val, val);
	old_earmarks = (g_free (old_earmarks), NULL);
}

void
sudoku_game_remove (SudokuGame* self,
                    gint row,
                    gint col)
{
	gint old_val = 0;
	SudokuBoard* _tmp0_;
	gboolean* old_earmarks = NULL;
	SudokuBoard* _tmp1_;
	gint _tmp2_ = 0;
	gboolean* _tmp3_;
	gint old_earmarks_length1;
	gint _old_earmarks_size_;
	gboolean* _tmp4_;
	gint _tmp4__length1;
	GameMode _tmp5_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->board;
	old_val = sudoku_board_get (_tmp0_, row, col);
	_tmp1_ = self->board;
	_tmp3_ = sudoku_board_get_earmarks (_tmp1_, row, col, &_tmp2_);
	old_earmarks = _tmp3_;
	old_earmarks_length1 = _tmp2_;
	_old_earmarks_size_ = old_earmarks_length1;
	_tmp4_ = old_earmarks;
	_tmp4__length1 = old_earmarks_length1;
	sudoku_game_update_undo (self, row, col, old_val, _tmp4_, (gint) _tmp4__length1);
	_tmp5_ = self->mode;
	if (_tmp5_ == GAME_MODE_CREATE) {
		SudokuBoard* _tmp6_;
		SudokuBoard* _tmp7_;
		gboolean* _tmp8_;
		gint _tmp8__length1;
		gint _tmp8__length2;
		_tmp6_ = self->board;
		sudoku_board_remove (_tmp6_, row, col, TRUE);
		_tmp7_ = self->board;
		_tmp8_ = _tmp7_->is_fixed;
		_tmp8__length1 = _tmp7_->is_fixed_length1;
		_tmp8__length2 = _tmp7_->is_fixed_length2;
		_tmp8_[(row * _tmp8__length2) + col] = FALSE;
	} else {
		SudokuBoard* _tmp9_;
		_tmp9_ = self->board;
		sudoku_board_remove (_tmp9_, row, col, FALSE);
	}
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_CELL_CHANGED_SIGNAL], 0, row, col, old_val, 0);
	old_earmarks = (g_free (old_earmarks), NULL);
}

gboolean
sudoku_game_is_empty (SudokuGame* self)
{
	GameMode _tmp0_;
	gboolean result = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->mode;
	if (_tmp0_ == GAME_MODE_CREATE) {
		SudokuBoard* _tmp1_;
		gint _tmp2_;
		gint _tmp3_;
		_tmp1_ = self->board;
		_tmp2_ = sudoku_board_get_filled (_tmp1_);
		_tmp3_ = _tmp2_;
		result = _tmp3_ == 0;
		return result;
	} else {
		SudokuBoard* _tmp4_;
		_tmp4_ = self->board;
		result = sudoku_board_is_empty (_tmp4_);
		return result;
	}
}

void
sudoku_game_undo (SudokuGame* self)
{
	GeeList* _tmp0_;
	GeeList* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->undostack;
	_tmp1_ = self->priv->redostack;
	sudoku_game_apply_stack (self, _tmp0_, _tmp1_);
}

void
sudoku_game_redo (SudokuGame* self)
{
	GeeList* _tmp0_;
	GeeList* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->redostack;
	_tmp1_ = self->priv->undostack;
	sudoku_game_apply_stack (self, _tmp0_, _tmp1_);
}

void
sudoku_game_reset (SudokuGame* self)
{
	SudokuBoard* _tmp0_;
	GTimer* _tmp1_;
	GeeList* _tmp2_;
	GeeList* _tmp3_;
	SudokuBoard* _tmp26_;
	GeeSet* _tmp27_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->board;
	sudoku_board_set_previous_played_time (_tmp0_, (gdouble) 0);
	_tmp1_ = self->timer;
	g_timer_start (_tmp1_);
	_tmp2_ = self->priv->undostack;
	gee_collection_clear ((GeeCollection*) _tmp2_);
	_tmp3_ = self->priv->redostack;
	gee_collection_clear ((GeeCollection*) _tmp3_);
	{
		gint l1 = 0;
		l1 = 0;
		{
			gboolean _tmp4_ = FALSE;
			_tmp4_ = TRUE;
			while (TRUE) {
				SudokuBoard* _tmp6_;
				gint _tmp7_;
				gint _tmp8_;
				if (!_tmp4_) {
					gint _tmp5_;
					_tmp5_ = l1;
					l1 = _tmp5_ + 1;
				}
				_tmp4_ = FALSE;
				_tmp6_ = self->board;
				_tmp7_ = sudoku_board_get_rows (_tmp6_);
				_tmp8_ = _tmp7_;
				if (!(l1 < _tmp8_)) {
					break;
				}
				{
					gint l2 = 0;
					l2 = 0;
					{
						gboolean _tmp9_ = FALSE;
						_tmp9_ = TRUE;
						while (TRUE) {
							SudokuBoard* _tmp11_;
							gint _tmp12_;
							gint _tmp13_;
							gboolean _tmp14_ = FALSE;
							GameMode _tmp15_;
							SudokuBoard* _tmp19_;
							SudokuBoard* _tmp20_;
							gboolean* _tmp21_;
							gint _tmp21__length1;
							gint _tmp21__length2;
							gboolean _tmp22_;
							SudokuBoard* _tmp23_;
							gboolean* _tmp24_;
							gint _tmp24__length1;
							gint _tmp24__length2;
							SudokuBoard* _tmp25_;
							if (!_tmp9_) {
								gint _tmp10_;
								_tmp10_ = l2;
								l2 = _tmp10_ + 1;
							}
							_tmp9_ = FALSE;
							_tmp11_ = self->board;
							_tmp12_ = sudoku_board_get_cols (_tmp11_);
							_tmp13_ = _tmp12_;
							if (!(l2 < _tmp13_)) {
								break;
							}
							_tmp15_ = self->mode;
							if (_tmp15_ == GAME_MODE_PLAY) {
								SudokuBoard* _tmp16_;
								gboolean* _tmp17_;
								gint _tmp17__length1;
								gint _tmp17__length2;
								gboolean _tmp18_;
								_tmp16_ = self->board;
								_tmp17_ = _tmp16_->is_fixed;
								_tmp17__length1 = _tmp16_->is_fixed_length1;
								_tmp17__length2 = _tmp16_->is_fixed_length2;
								_tmp18_ = _tmp17_[(l1 * _tmp17__length2) + l2];
								_tmp14_ = _tmp18_;
							} else {
								_tmp14_ = FALSE;
							}
							if (_tmp14_) {
								continue;
							}
							_tmp19_ = self->board;
							_tmp20_ = self->board;
							_tmp21_ = _tmp20_->is_fixed;
							_tmp21__length1 = _tmp20_->is_fixed_length1;
							_tmp21__length2 = _tmp20_->is_fixed_length2;
							_tmp22_ = _tmp21_[(l1 * _tmp21__length2) + l2];
							sudoku_board_remove (_tmp19_, l1, l2, _tmp22_);
							_tmp23_ = self->board;
							_tmp24_ = _tmp23_->is_fixed;
							_tmp24__length1 = _tmp23_->is_fixed_length1;
							_tmp24__length2 = _tmp23_->is_fixed_length2;
							_tmp24_[(l1 * _tmp24__length2) + l2] = FALSE;
							_tmp25_ = self->board;
							g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_CELL_CHANGED_SIGNAL], 0, l1, l2, sudoku_board_get (_tmp25_, l1, l2), 0);
						}
					}
				}
			}
		}
	}
	_tmp26_ = self->board;
	_tmp27_ = _tmp26_->broken_coords;
	gee_collection_clear ((GeeCollection*) _tmp27_);
}

void
sudoku_game_cell_changed_cb (SudokuGame* self,
                             gint row,
                             gint col,
                             gint old_val,
                             gint new_val)
{
	g_return_if_fail (self != NULL);
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_CELL_CHANGED_SIGNAL], 0, row, col, old_val, new_val);
}

void
sudoku_game_update_undo (SudokuGame* self,
                         gint row,
                         gint col,
                         gint old_val,
                         gboolean* old_earmarks,
                         gint old_earmarks_length1)
{
	GeeList* _tmp0_;
	GeeList* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->undostack;
	sudoku_game_add_to_stack (self, _tmp0_, row, col, old_val, old_earmarks, (gint) old_earmarks_length1);
	_tmp1_ = self->priv->redostack;
	gee_collection_clear ((GeeCollection*) _tmp1_);
}

static gboolean*
_vala_array_dup9 (gboolean* self,
                  gint length)
{
	if (length > 0) {
		return g_memdup (self, length * sizeof (gboolean));
	}
	return NULL;
}

static void
sudoku_game_add_to_stack (SudokuGame* self,
                          GeeList* stack,
                          gint r,
                          gint c,
                          gint v,
                          gboolean* e,
                          gint e_length1)
{
	SudokuGameUndoItem step = {0};
	gboolean* _tmp0_;
	gint _tmp0__length1;
	SudokuGameUndoItem _tmp1_ = {0};
	SudokuGameUndoItem _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (stack != NULL);
	_tmp0_ = (e != NULL) ? _vala_array_dup9 (e, e_length1) : ((gpointer) e);
	_tmp0__length1 = e_length1;
	_tmp1_.row = r;
	_tmp1_.col = c;
	_tmp1_.val = v;
	_tmp1_.earmarks = (g_free (_tmp1_.earmarks), NULL);
	_tmp1_.earmarks = _tmp0_;
	_tmp1_.earmarks_length1 = _tmp0__length1;
	_tmp1_._earmarks_size_ = _tmp1_.earmarks_length1;
	step = _tmp1_;
	_tmp2_ = step;
	gee_collection_add ((GeeCollection*) stack, &_tmp2_);
	sudoku_game_undo_item_destroy (&step);
}

static void
sudoku_game_apply_stack (SudokuGame* self,
                         GeeList* from,
                         GeeList* to)
{
	gint _tmp0_;
	gint _tmp1_;
	SudokuGameUndoItem* top = NULL;
	gint _tmp2_;
	gint _tmp3_;
	gpointer _tmp4_;
	gint old_val = 0;
	SudokuBoard* _tmp5_;
	SudokuGameUndoItem* _tmp6_;
	SudokuGameUndoItem* _tmp7_;
	gboolean* old_earmarks = NULL;
	SudokuBoard* _tmp8_;
	SudokuGameUndoItem* _tmp9_;
	SudokuGameUndoItem* _tmp10_;
	gint _tmp11_ = 0;
	gboolean* _tmp12_;
	gint old_earmarks_length1;
	gint _old_earmarks_size_;
	SudokuGameUndoItem* _tmp13_;
	SudokuGameUndoItem* _tmp14_;
	gboolean* _tmp15_;
	gint _tmp15__length1;
	GameMode _tmp16_;
	SudokuGameUndoItem* _tmp32_;
	SudokuGameUndoItem* _tmp64_;
	SudokuGameUndoItem* _tmp65_;
	SudokuGameUndoItem* _tmp66_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (from != NULL);
	g_return_if_fail (to != NULL);
	_tmp0_ = gee_collection_get_size ((GeeCollection*) from);
	_tmp1_ = _tmp0_;
	if (_tmp1_ == 0) {
		return;
	}
	_tmp2_ = gee_collection_get_size ((GeeCollection*) from);
	_tmp3_ = _tmp2_;
	_tmp4_ = gee_list_remove_at (from, _tmp3_ - 1);
	top = (SudokuGameUndoItem*) _tmp4_;
	_tmp5_ = self->board;
	_tmp6_ = top;
	_tmp7_ = top;
	old_val = sudoku_board_get (_tmp5_, (*_tmp6_).row, (*_tmp7_).col);
	_tmp8_ = self->board;
	_tmp9_ = top;
	_tmp10_ = top;
	_tmp12_ = sudoku_board_get_earmarks (_tmp8_, (*_tmp9_).row, (*_tmp10_).col, &_tmp11_);
	old_earmarks = _tmp12_;
	old_earmarks_length1 = _tmp11_;
	_old_earmarks_size_ = old_earmarks_length1;
	_tmp13_ = top;
	_tmp14_ = top;
	_tmp15_ = old_earmarks;
	_tmp15__length1 = old_earmarks_length1;
	sudoku_game_add_to_stack (self, to, (*_tmp13_).row, (*_tmp14_).col, old_val, _tmp15_, (gint) _tmp15__length1);
	_tmp16_ = self->mode;
	if (_tmp16_ == GAME_MODE_CREATE) {
		SudokuBoard* _tmp17_;
		SudokuGameUndoItem* _tmp18_;
		SudokuGameUndoItem* _tmp19_;
		SudokuBoard* _tmp20_;
		gboolean* _tmp21_;
		gint _tmp21__length1;
		gint _tmp21__length2;
		SudokuGameUndoItem* _tmp22_;
		SudokuGameUndoItem* _tmp23_;
		gboolean _tmp24_;
		SudokuBoard* _tmp25_;
		gboolean* _tmp26_;
		gint _tmp26__length1;
		gint _tmp26__length2;
		SudokuGameUndoItem* _tmp27_;
		SudokuGameUndoItem* _tmp28_;
		_tmp17_ = self->board;
		_tmp18_ = top;
		_tmp19_ = top;
		_tmp20_ = self->board;
		_tmp21_ = _tmp20_->is_fixed;
		_tmp21__length1 = _tmp20_->is_fixed_length1;
		_tmp21__length2 = _tmp20_->is_fixed_length2;
		_tmp22_ = top;
		_tmp23_ = top;
		_tmp24_ = _tmp21_[((*_tmp22_).row * _tmp21__length2) + (*_tmp23_).col];
		sudoku_board_remove (_tmp17_, (*_tmp18_).row, (*_tmp19_).col, _tmp24_);
		_tmp25_ = self->board;
		_tmp26_ = _tmp25_->is_fixed;
		_tmp26__length1 = _tmp25_->is_fixed_length1;
		_tmp26__length2 = _tmp25_->is_fixed_length2;
		_tmp27_ = top;
		_tmp28_ = top;
		_tmp26_[((*_tmp27_).row * _tmp26__length2) + (*_tmp28_).col] = FALSE;
	} else {
		SudokuBoard* _tmp29_;
		SudokuGameUndoItem* _tmp30_;
		SudokuGameUndoItem* _tmp31_;
		_tmp29_ = self->board;
		_tmp30_ = top;
		_tmp31_ = top;
		sudoku_board_remove (_tmp29_, (*_tmp30_).row, (*_tmp31_).col, FALSE);
	}
	_tmp32_ = top;
	if ((*_tmp32_).val != 0) {
		GameMode _tmp33_;
		_tmp33_ = self->mode;
		if (_tmp33_ == GAME_MODE_CREATE) {
			SudokuBoard* _tmp34_;
			SudokuGameUndoItem* _tmp35_;
			SudokuGameUndoItem* _tmp36_;
			SudokuGameUndoItem* _tmp37_;
			SudokuBoard* _tmp38_;
			gboolean* _tmp39_;
			gint _tmp39__length1;
			gint _tmp39__length2;
			SudokuGameUndoItem* _tmp40_;
			SudokuGameUndoItem* _tmp41_;
			gboolean _tmp42_;
			SudokuBoard* _tmp43_;
			gboolean* _tmp44_;
			gint _tmp44__length1;
			gint _tmp44__length2;
			SudokuGameUndoItem* _tmp45_;
			SudokuGameUndoItem* _tmp46_;
			_tmp34_ = self->board;
			_tmp35_ = top;
			_tmp36_ = top;
			_tmp37_ = top;
			_tmp38_ = self->board;
			_tmp39_ = _tmp38_->is_fixed;
			_tmp39__length1 = _tmp38_->is_fixed_length1;
			_tmp39__length2 = _tmp38_->is_fixed_length2;
			_tmp40_ = top;
			_tmp41_ = top;
			_tmp42_ = _tmp39_[((*_tmp40_).row * _tmp39__length2) + (*_tmp41_).col];
			sudoku_board_insert (_tmp34_, (*_tmp35_).row, (*_tmp36_).col, (*_tmp37_).val, _tmp42_);
			_tmp43_ = self->board;
			_tmp44_ = _tmp43_->is_fixed;
			_tmp44__length1 = _tmp43_->is_fixed_length1;
			_tmp44__length2 = _tmp43_->is_fixed_length2;
			_tmp45_ = top;
			_tmp46_ = top;
			_tmp44_[((*_tmp45_).row * _tmp44__length2) + (*_tmp46_).col] = TRUE;
		} else {
			SudokuBoard* _tmp47_;
			SudokuGameUndoItem* _tmp48_;
			SudokuGameUndoItem* _tmp49_;
			SudokuGameUndoItem* _tmp50_;
			_tmp47_ = self->board;
			_tmp48_ = top;
			_tmp49_ = top;
			_tmp50_ = top;
			sudoku_board_insert (_tmp47_, (*_tmp48_).row, (*_tmp49_).col, (*_tmp50_).val, FALSE);
		}
	}
	{
		gint i = 0;
		i = 1;
		{
			gboolean _tmp51_ = FALSE;
			_tmp51_ = TRUE;
			while (TRUE) {
				SudokuGameUndoItem* _tmp53_;
				gboolean* _tmp54_;
				gint _tmp54__length1;
				SudokuGameUndoItem* _tmp55_;
				gboolean* _tmp56_;
				gint _tmp56__length1;
				gboolean _tmp57_;
				if (!_tmp51_) {
					gint _tmp52_;
					_tmp52_ = i;
					i = _tmp52_ + 1;
				}
				_tmp51_ = FALSE;
				_tmp53_ = top;
				_tmp54_ = (*_tmp53_).earmarks;
				_tmp54__length1 = (*_tmp53_).earmarks_length1;
				if (!(i <= _tmp54__length1)) {
					break;
				}
				_tmp55_ = top;
				_tmp56_ = (*_tmp55_).earmarks;
				_tmp56__length1 = (*_tmp55_).earmarks_length1;
				_tmp57_ = _tmp56_[i - 1];
				if (_tmp57_) {
					SudokuBoard* _tmp58_;
					SudokuGameUndoItem* _tmp59_;
					SudokuGameUndoItem* _tmp60_;
					_tmp58_ = self->board;
					_tmp59_ = top;
					_tmp60_ = top;
					sudoku_board_enable_earmark (_tmp58_, (*_tmp59_).row, (*_tmp60_).col, i);
				} else {
					SudokuBoard* _tmp61_;
					SudokuGameUndoItem* _tmp62_;
					SudokuGameUndoItem* _tmp63_;
					_tmp61_ = self->board;
					_tmp62_ = top;
					_tmp63_ = top;
					sudoku_board_disable_earmark (_tmp61_, (*_tmp62_).row, (*_tmp63_).col, i);
				}
			}
		}
	}
	_tmp64_ = top;
	_tmp65_ = top;
	_tmp66_ = top;
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_CELL_CHANGED_SIGNAL], 0, (*_tmp64_).row, (*_tmp65_).col, old_val, (*_tmp66_).val);
	old_earmarks = (g_free (old_earmarks), NULL);
	_sudoku_game_undo_item_free0 (top);
}

gdouble
sudoku_game_get_total_time_played (SudokuGame* self)
{
	SudokuBoard* _tmp0_;
	gdouble _tmp1_;
	gdouble _tmp2_;
	GTimer* _tmp3_;
	gdouble result = 0.0;
	g_return_val_if_fail (self != NULL, 0.0);
	_tmp0_ = self->board;
	_tmp1_ = sudoku_board_get_previous_played_time (_tmp0_);
	_tmp2_ = _tmp1_;
	_tmp3_ = self->timer;
	result = _tmp2_ + g_timer_elapsed (_tmp3_, NULL);
	return result;
}

static gboolean
_sudoku_game_timeout_cb_gsource_func (gpointer self)
{
	gboolean result;
	result = sudoku_game_timeout_cb ((SudokuGame*) self);
	return result;
}

static gboolean
sudoku_game_timeout_cb (SudokuGame* self)
{
	gboolean result = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	self->priv->clock_timeout = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, (guint) 1, _sudoku_game_timeout_cb_gsource_func, g_object_ref (self), g_object_unref);
	g_source_set_name_by_id (self->priv->clock_timeout, "[gnome-sudoku] timeout_cb");
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_TICK_SIGNAL], 0);
	result = FALSE;
	return result;
}

void
sudoku_game_start_clock (SudokuGame* self)
{
	GTimer* _tmp0_;
	GTimer* _tmp2_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->timer;
	if (_tmp0_ == NULL) {
		GTimer* _tmp1_;
		_tmp1_ = g_timer_new ();
		_g_timer_destroy0 (self->timer);
		self->timer = _tmp1_;
	}
	_tmp2_ = self->timer;
	g_timer_start (_tmp2_);
	sudoku_game_timeout_cb (self);
}

void
sudoku_game_stop_clock (SudokuGame* self)
{
	GTimer* _tmp0_;
	GTimer* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->timer;
	_vala_return_if_fail (_tmp0_ != NULL, "timer != null");
	if (self->priv->clock_timeout != ((guint) 0)) {
		g_source_remove (self->priv->clock_timeout);
	}
	self->priv->clock_timeout = (guint) 0;
	sudoku_game_set_paused (self, TRUE);
	_tmp1_ = self->timer;
	g_timer_stop (_tmp1_);
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_TICK_SIGNAL], 0);
}

void
sudoku_game_resume_clock (SudokuGame* self)
{
	GTimer* _tmp0_;
	GTimer* _tmp1_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->timer;
	_vala_return_if_fail ((_tmp0_ != NULL) && (self->priv->clock_timeout == ((guint) 0)), "timer != null && clock_timeout == 0");
	_tmp1_ = self->timer;
	g_timer_continue (_tmp1_);
	sudoku_game_set_paused (self, FALSE);
	sudoku_game_timeout_cb (self);
}

gboolean
sudoku_game_get_paused (SudokuGame* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_paused;
	return result;
}

static void
sudoku_game_set_paused (SudokuGame* self,
                        gboolean value)
{
	g_return_if_fail (self != NULL);
	self->priv->_paused = value;
	g_signal_emit (self, sudoku_game_signals[SUDOKU_GAME_PAUSED_CHANGED_SIGNAL], 0);
	g_object_notify_by_pspec ((GObject *) self, sudoku_game_properties[SUDOKU_GAME_PAUSED_PROPERTY]);
}

static void
g_cclosure_user_marshal_VOID__INT_INT_INT_INT (GClosure * closure,
                                               GValue * return_value,
                                               guint n_param_values,
                                               const GValue * param_values,
                                               gpointer invocation_hint,
                                               gpointer marshal_data)
{
	typedef void (*GMarshalFunc_VOID__INT_INT_INT_INT) (gpointer data1, gint arg_1, gint arg_2, gint arg_3, gint arg_4, gpointer data2);
	register GMarshalFunc_VOID__INT_INT_INT_INT callback;
	register GCClosure * cc;
	register gpointer data1;
	register gpointer data2;
	cc = (GCClosure *) closure;
	g_return_if_fail (n_param_values == 5);
	if (G_CCLOSURE_SWAP_DATA (closure)) {
		data1 = closure->data;
		data2 = param_values->data[0].v_pointer;
	} else {
		data1 = param_values->data[0].v_pointer;
		data2 = closure->data;
	}
	callback = (GMarshalFunc_VOID__INT_INT_INT_INT) (marshal_data ? marshal_data : cc->callback);
	callback (data1, g_value_get_int (param_values + 1), g_value_get_int (param_values + 2), g_value_get_int (param_values + 3), g_value_get_int (param_values + 4), data2);
}

static gboolean*
_vala_array_dup10 (gboolean* self,
                   gint length)
{
	if (length > 0) {
		return g_memdup (self, length * sizeof (gboolean));
	}
	return NULL;
}

static void
sudoku_game_undo_item_copy (const SudokuGameUndoItem* self,
                            SudokuGameUndoItem* dest)
{
	gboolean* _tmp0_;
	gint _tmp0__length1;
	gboolean* _tmp1_;
	gint _tmp1__length1;
	(*dest).row = (*self).row;
	(*dest).col = (*self).col;
	(*dest).val = (*self).val;
	_tmp0_ = (*self).earmarks;
	_tmp0__length1 = (*self).earmarks_length1;
	_tmp1_ = (_tmp0_ != NULL) ? _vala_array_dup10 (_tmp0_, _tmp0__length1) : ((gpointer) _tmp0_);
	_tmp1__length1 = _tmp0__length1;
	(*dest).earmarks = (g_free ((*dest).earmarks), NULL);
	(*dest).earmarks = _tmp1_;
	(*dest).earmarks_length1 = _tmp1__length1;
	(*dest)._earmarks_size_ = (*dest).earmarks_length1;
}

static void
sudoku_game_undo_item_destroy (SudokuGameUndoItem* self)
{
	(*self).earmarks = (g_free ((*self).earmarks), NULL);
}

static SudokuGameUndoItem*
sudoku_game_undo_item_dup (const SudokuGameUndoItem* self)
{
	SudokuGameUndoItem* dup;
	dup = g_new0 (SudokuGameUndoItem, 1);
	sudoku_game_undo_item_copy (self, dup);
	return dup;
}

static void
sudoku_game_undo_item_free (SudokuGameUndoItem* self)
{
	sudoku_game_undo_item_destroy (self);
	g_free (self);
}

static GType
sudoku_game_undo_item_get_type_once (void)
{
	GType sudoku_game_undo_item_type_id;
	sudoku_game_undo_item_type_id = g_boxed_type_register_static ("SudokuGameUndoItem", (GBoxedCopyFunc) sudoku_game_undo_item_dup, (GBoxedFreeFunc) sudoku_game_undo_item_free);
	return sudoku_game_undo_item_type_id;
}

static GType
sudoku_game_undo_item_get_type (void)
{
	static volatile gsize sudoku_game_undo_item_type_id__volatile = 0;
	if (g_once_init_enter (&sudoku_game_undo_item_type_id__volatile)) {
		GType sudoku_game_undo_item_type_id;
		sudoku_game_undo_item_type_id = sudoku_game_undo_item_get_type_once ();
		g_once_init_leave (&sudoku_game_undo_item_type_id__volatile, sudoku_game_undo_item_type_id);
	}
	return sudoku_game_undo_item_type_id__volatile;
}

static void
sudoku_game_class_init (SudokuGameClass * klass,
                        gpointer klass_data)
{
	sudoku_game_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &SudokuGame_private_offset);
	G_OBJECT_CLASS (klass)->get_property = _vala_sudoku_game_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_sudoku_game_set_property;
	G_OBJECT_CLASS (klass)->finalize = sudoku_game_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), SUDOKU_GAME_PAUSED_PROPERTY, sudoku_game_properties[SUDOKU_GAME_PAUSED_PROPERTY] = g_param_spec_boolean ("paused", "paused", "paused", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	sudoku_game_signals[SUDOKU_GAME_TICK_SIGNAL] = g_signal_new ("tick", TYPE_SUDOKU_GAME, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
	sudoku_game_signals[SUDOKU_GAME_PAUSED_CHANGED_SIGNAL] = g_signal_new ("paused-changed", TYPE_SUDOKU_GAME, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
	sudoku_game_signals[SUDOKU_GAME_CELL_CHANGED_SIGNAL] = g_signal_new ("cell-changed", TYPE_SUDOKU_GAME, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
}

static void
sudoku_game_instance_init (SudokuGame * self,
                           gpointer klass)
{
	self->priv = sudoku_game_get_instance_private (self);
	self->priv->_paused = FALSE;
}

static void
sudoku_game_finalize (GObject * obj)
{
	SudokuGame * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_SUDOKU_GAME, SudokuGame);
	_g_object_unref0 (self->board);
	_g_timer_destroy0 (self->timer);
	_g_object_unref0 (self->priv->undostack);
	_g_object_unref0 (self->priv->redostack);
	G_OBJECT_CLASS (sudoku_game_parent_class)->finalize (obj);
}

static GType
sudoku_game_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (SudokuGameClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) sudoku_game_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (SudokuGame), 0, (GInstanceInitFunc) sudoku_game_instance_init, NULL };
	GType sudoku_game_type_id;
	sudoku_game_type_id = g_type_register_static (G_TYPE_OBJECT, "SudokuGame", &g_define_type_info, 0);
	SudokuGame_private_offset = g_type_add_instance_private (sudoku_game_type_id, sizeof (SudokuGamePrivate));
	return sudoku_game_type_id;
}

GType
sudoku_game_get_type (void)
{
	static volatile gsize sudoku_game_type_id__volatile = 0;
	if (g_once_init_enter (&sudoku_game_type_id__volatile)) {
		GType sudoku_game_type_id;
		sudoku_game_type_id = sudoku_game_get_type_once ();
		g_once_init_leave (&sudoku_game_type_id__volatile, sudoku_game_type_id);
	}
	return sudoku_game_type_id__volatile;
}

static void
_vala_sudoku_game_get_property (GObject * object,
                                guint property_id,
                                GValue * value,
                                GParamSpec * pspec)
{
	SudokuGame * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_SUDOKU_GAME, SudokuGame);
	switch (property_id) {
		case SUDOKU_GAME_PAUSED_PROPERTY:
		g_value_set_boolean (value, sudoku_game_get_paused (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_sudoku_game_set_property (GObject * object,
                                guint property_id,
                                const GValue * value,
                                GParamSpec * pspec)
{
	SudokuGame * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_SUDOKU_GAME, SudokuGame);
	switch (property_id) {
		case SUDOKU_GAME_PAUSED_PROPERTY:
		sudoku_game_set_paused (self, g_value_get_boolean (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static GType
game_mode_get_type_once (void)
{
	static const GEnumValue values[] = {{GAME_MODE_PLAY, "GAME_MODE_PLAY", "play"}, {GAME_MODE_CREATE, "GAME_MODE_CREATE", "create"}, {0, NULL, NULL}};
	GType game_mode_type_id;
	game_mode_type_id = g_enum_register_static ("GameMode", values);
	return game_mode_type_id;
}

GType
game_mode_get_type (void)
{
	static volatile gsize game_mode_type_id__volatile = 0;
	if (g_once_init_enter (&game_mode_type_id__volatile)) {
		GType game_mode_type_id;
		game_mode_type_id = game_mode_get_type_once ();
		g_once_init_leave (&game_mode_type_id__volatile, game_mode_type_id);
	}
	return game_mode_type_id__volatile;
}

