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

/*
* Copyright (c) 2011-2013 Yorba Foundation
*
* This program 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 program 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 this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/

#include "io.elementary.photos.h"
#include <glib.h>
#include <string.h>
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#include <sqlite3.h>
#include <gee.h>
#include <stdlib.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_free0(var) (var = (g_free (var), NULL))
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
typedef struct _ParamSpecTagRow ParamSpecTagRow;
#define _sqlite3_finalize0(var) ((var == NULL) ? NULL : (var = (sqlite3_finalize (var), NULL)))
#define _database_table_unref0(var) ((var == NULL) ? NULL : (var = (database_table_unref (var), NULL)))
#define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL)))
#define _tag_row_unref0(var) ((var == NULL) ? NULL : (var = (tag_row_unref (var), NULL)))
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
#define _g_string_free0(var) ((var == NULL) ? NULL : (var = (g_string_free (var, TRUE), NULL)))

struct _ParamSpecTagRow {
	GParamSpec parent_instance;
};

static gpointer tag_row_parent_class = NULL;
static gpointer tag_table_parent_class = NULL;
static TagTable* tag_table_instance;
static TagTable* tag_table_instance = NULL;

static void tag_row_finalize (TagRow * obj);
static GType tag_row_get_type_once (void);
static TagTable* tag_table_new (void);
static TagTable* tag_table_construct (GType object_type);
static gchar* tag_table_serialize_source_ids (TagTable* self,
                                       GeeCollection* source_ids);
static GeeSet* tag_table_unserialize_source_ids (TagTable* self,
                                          const gchar* text_list);
static void tag_table_finalize (DatabaseTable * obj);
static GType tag_table_get_type_once (void);
static void _vala_array_destroy (gpointer array,
                          gssize array_length,
                          GDestroyNotify destroy_func);
static void _vala_array_free (gpointer array,
                       gssize array_length,
                       GDestroyNotify destroy_func);
static gssize _vala_array_length (gpointer array);

void
tag_id_init (TagID *self,
             gint64 id)
{
	memset (self, 0, sizeof (TagID));
	(*self).id = id;
}

gboolean
tag_id_is_invalid (TagID *self)
{
	gboolean result;
	result = (*self).id == TAG_ID_INVALID;
	return result;
}

gboolean
tag_id_is_valid (TagID *self)
{
	gboolean result;
	result = (*self).id != TAG_ID_INVALID;
	return result;
}

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

void
tag_id_free (TagID* self)
{
	g_free (self);
}

static GType
tag_id_get_type_once (void)
{
	GType tag_id_type_id;
	tag_id_type_id = g_boxed_type_register_static ("TagID", (GBoxedCopyFunc) tag_id_dup, (GBoxedFreeFunc) tag_id_free);
	return tag_id_type_id;
}

GType
tag_id_get_type (void)
{
	static volatile gsize tag_id_type_id__once = 0;
	if (g_once_init_enter (&tag_id_type_id__once)) {
		GType tag_id_type_id;
		tag_id_type_id = tag_id_get_type_once ();
		g_once_init_leave (&tag_id_type_id__once, tag_id_type_id);
	}
	return tag_id_type_id__once;
}

TagRow*
tag_row_construct (GType object_type)
{
	TagRow* self = NULL;
	self = (TagRow*) g_type_create_instance (object_type);
	return self;
}

TagRow*
tag_row_new (void)
{
	return tag_row_construct (TYPE_TAG_ROW);
}

static void
value_tag_row_init (GValue* value)
{
	value->data[0].v_pointer = NULL;
}

static void
value_tag_row_free_value (GValue* value)
{
	if (value->data[0].v_pointer) {
		tag_row_unref (value->data[0].v_pointer);
	}
}

static void
value_tag_row_copy_value (const GValue* src_value,
                          GValue* dest_value)
{
	if (src_value->data[0].v_pointer) {
		dest_value->data[0].v_pointer = tag_row_ref (src_value->data[0].v_pointer);
	} else {
		dest_value->data[0].v_pointer = NULL;
	}
}

static gpointer
value_tag_row_peek_pointer (const GValue* value)
{
	return value->data[0].v_pointer;
}

static gchar*
value_tag_row_collect_value (GValue* value,
                             guint n_collect_values,
                             GTypeCValue* collect_values,
                             guint collect_flags)
{
	if (collect_values[0].v_pointer) {
		TagRow * object;
		object = collect_values[0].v_pointer;
		if (object->parent_instance.g_class == NULL) {
			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
		}
		value->data[0].v_pointer = tag_row_ref (object);
	} else {
		value->data[0].v_pointer = NULL;
	}
	return NULL;
}

static gchar*
value_tag_row_lcopy_value (const GValue* value,
                           guint n_collect_values,
                           GTypeCValue* collect_values,
                           guint collect_flags)
{
	TagRow ** object_p;
	object_p = collect_values[0].v_pointer;
	if (!object_p) {
		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
	}
	if (!value->data[0].v_pointer) {
		*object_p = NULL;
	} else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
		*object_p = value->data[0].v_pointer;
	} else {
		*object_p = tag_row_ref (value->data[0].v_pointer);
	}
	return NULL;
}

GParamSpec*
param_spec_tag_row (const gchar* name,
                    const gchar* nick,
                    const gchar* blurb,
                    GType object_type,
                    GParamFlags flags)
{
	ParamSpecTagRow* spec;
	g_return_val_if_fail (g_type_is_a (object_type, TYPE_TAG_ROW), NULL);
	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
	G_PARAM_SPEC (spec)->value_type = object_type;
	return G_PARAM_SPEC (spec);
}

gpointer
value_get_tag_row (const GValue* value)
{
	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_TAG_ROW), NULL);
	return value->data[0].v_pointer;
}

void
value_set_tag_row (GValue* value,
                   gpointer v_object)
{
	TagRow * old;
	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_TAG_ROW));
	old = value->data[0].v_pointer;
	if (v_object) {
		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_TAG_ROW));
		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
		value->data[0].v_pointer = v_object;
		tag_row_ref (value->data[0].v_pointer);
	} else {
		value->data[0].v_pointer = NULL;
	}
	if (old) {
		tag_row_unref (old);
	}
}

void
value_take_tag_row (GValue* value,
                    gpointer v_object)
{
	TagRow * old;
	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_TAG_ROW));
	old = value->data[0].v_pointer;
	if (v_object) {
		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_TAG_ROW));
		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
		value->data[0].v_pointer = v_object;
	} else {
		value->data[0].v_pointer = NULL;
	}
	if (old) {
		tag_row_unref (old);
	}
}

static void
tag_row_class_init (TagRowClass * klass,
                    gpointer klass_data)
{
	tag_row_parent_class = g_type_class_peek_parent (klass);
	((TagRowClass *) klass)->finalize = tag_row_finalize;
}

static void
tag_row_instance_init (TagRow * self,
                       gpointer klass)
{
	self->ref_count = 1;
}

static void
tag_row_finalize (TagRow * obj)
{
	TagRow * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_TAG_ROW, TagRow);
	g_signal_handlers_destroy (self);
	_g_free0 (self->name);
	_g_object_unref0 (self->source_id_list);
}

static GType
tag_row_get_type_once (void)
{
	static const GTypeValueTable g_define_type_value_table = { value_tag_row_init, value_tag_row_free_value, value_tag_row_copy_value, value_tag_row_peek_pointer, "p", value_tag_row_collect_value, "p", value_tag_row_lcopy_value };
	static const GTypeInfo g_define_type_info = { sizeof (TagRowClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) tag_row_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (TagRow), 0, (GInstanceInitFunc) tag_row_instance_init, &g_define_type_value_table };
	static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
	GType tag_row_type_id;
	tag_row_type_id = g_type_register_fundamental (g_type_fundamental_next (), "TagRow", &g_define_type_info, &g_define_type_fundamental_info, 0);
	return tag_row_type_id;
}

GType
tag_row_get_type (void)
{
	static volatile gsize tag_row_type_id__once = 0;
	if (g_once_init_enter (&tag_row_type_id__once)) {
		GType tag_row_type_id;
		tag_row_type_id = tag_row_get_type_once ();
		g_once_init_leave (&tag_row_type_id__once, tag_row_type_id);
	}
	return tag_row_type_id__once;
}

gpointer
tag_row_ref (gpointer instance)
{
	TagRow * self;
	self = instance;
	g_atomic_int_inc (&self->ref_count);
	return instance;
}

void
tag_row_unref (gpointer instance)
{
	TagRow * self;
	self = instance;
	if (g_atomic_int_dec_and_test (&self->ref_count)) {
		TAG_ROW_GET_CLASS (self)->finalize (self);
		g_type_free_instance ((GTypeInstance *) self);
	}
}

static TagTable*
tag_table_construct (GType object_type)
{
	TagTable* self = NULL;
	sqlite3_stmt* stmt = NULL;
	sqlite3_stmt* _tmp0_;
	gint res = 0;
	sqlite3_stmt* _tmp1_;
	self = (TagTable*) database_table_construct (object_type);
	database_table_set_table_name ((DatabaseTable*) self, "TagTable");
	_tmp0_ = database_table_create_stmt ((DatabaseTable*) self, "CREATE TABLE IF NOT EXISTS " "TagTable " "(" "id INTEGER PRIMARY KEY, " "name TEXT UNIQUE NOT NULL, " "photo_id_list TEXT, " "time_created INTEGER" ")");
	stmt = _tmp0_;
	_tmp1_ = stmt;
	res = sqlite3_step (_tmp1_);
	if (res != SQLITE_DONE) {
		database_table_fatal ("create TagTable", res);
	}
	_sqlite3_finalize0 (stmt);
	return self;
}

static TagTable*
tag_table_new (void)
{
	return tag_table_construct (TYPE_TAG_TABLE);
}

static gpointer
_database_table_ref0 (gpointer self)
{
	return self ? database_table_ref (self) : NULL;
}

TagTable*
tag_table_get_instance (void)
{
	TagTable* _tmp0_;
	TagTable* _tmp2_;
	TagTable* _tmp3_;
	TagTable* result;
	_tmp0_ = tag_table_instance;
	if (_tmp0_ == NULL) {
		TagTable* _tmp1_;
		_tmp1_ = tag_table_new ();
		_database_table_unref0 (tag_table_instance);
		tag_table_instance = _tmp1_;
	}
	_tmp2_ = tag_table_instance;
	_tmp3_ = _database_table_ref0 (_tmp2_);
	result = _tmp3_;
	return result;
}

static gchar*
string_replace (const gchar* self,
                const gchar* old,
                const gchar* replacement)
{
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_ = FALSE;
	GError* _inner_error0_ = NULL;
	gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (old != NULL, NULL);
	g_return_val_if_fail (replacement != NULL, NULL);
	if ((*((gchar*) self)) == '\0') {
		_tmp1_ = TRUE;
	} else {
		_tmp1_ = (*((gchar*) old)) == '\0';
	}
	if (_tmp1_) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = g_strcmp0 (old, replacement) == 0;
	}
	if (_tmp0_) {
		gchar* _tmp2_;
		_tmp2_ = g_strdup (self);
		result = _tmp2_;
		return result;
	}
	{
		GRegex* regex = NULL;
		gchar* _tmp3_;
		gchar* _tmp4_;
		GRegex* _tmp5_;
		GRegex* _tmp6_;
		gchar* _tmp7_ = NULL;
		GRegex* _tmp8_;
		gchar* _tmp9_;
		gchar* _tmp10_;
		_tmp3_ = g_regex_escape_string (old, -1);
		_tmp4_ = _tmp3_;
		_tmp5_ = g_regex_new (_tmp4_, 0, 0, &_inner_error0_);
		_tmp6_ = _tmp5_;
		_g_free0 (_tmp4_);
		regex = _tmp6_;
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			if (_inner_error0_->domain == G_REGEX_ERROR) {
				goto __catch0_g_regex_error;
			}
			g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return NULL;
		}
		_tmp8_ = regex;
		_tmp9_ = g_regex_replace_literal (_tmp8_, self, (gssize) -1, 0, replacement, 0, &_inner_error0_);
		_tmp7_ = _tmp9_;
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			_g_regex_unref0 (regex);
			if (_inner_error0_->domain == G_REGEX_ERROR) {
				goto __catch0_g_regex_error;
			}
			g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return NULL;
		}
		_tmp10_ = _tmp7_;
		_tmp7_ = NULL;
		result = _tmp10_;
		_g_free0 (_tmp7_);
		_g_regex_unref0 (regex);
		return result;
	}
	goto __finally0;
	__catch0_g_regex_error:
	{
		g_clear_error (&_inner_error0_);
		g_assert_not_reached ();
	}
	__finally0:
	g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
	g_clear_error (&_inner_error0_);
	return NULL;
}

void
tag_table_upgrade_for_htags (void)
{
	TagTable* table = NULL;
	TagTable* _tmp0_;
	GError* _inner_error0_ = NULL;
	_tmp0_ = tag_table_get_instance ();
	table = _tmp0_;
	{
		GeeList* rows = NULL;
		TagTable* _tmp1_;
		GeeList* _tmp2_;
		_tmp1_ = table;
		_tmp2_ = tag_table_get_all_rows (_tmp1_, &_inner_error0_);
		rows = _tmp2_;
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			if (_inner_error0_->domain == DATABASE_ERROR) {
				goto __catch0_database_error;
			}
			_database_table_unref0 (table);
			g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return;
		}
		{
			GeeList* _row_list = NULL;
			GeeList* _tmp3_;
			gint _row_size = 0;
			GeeList* _tmp4_;
			gint _tmp5_;
			gint _tmp6_;
			gint _row_index = 0;
			_tmp3_ = rows;
			_row_list = _tmp3_;
			_tmp4_ = _row_list;
			_tmp5_ = gee_collection_get_size ((GeeCollection*) _tmp4_);
			_tmp6_ = _tmp5_;
			_row_size = _tmp6_;
			_row_index = -1;
			while (TRUE) {
				gint _tmp7_;
				gint _tmp8_;
				TagRow* row = NULL;
				GeeList* _tmp9_;
				gpointer _tmp10_;
				TagRow* _tmp11_;
				TagRow* _tmp12_;
				const gchar* _tmp13_;
				gchar* _tmp14_;
				TagTable* _tmp15_;
				TagRow* _tmp16_;
				TagID _tmp17_;
				TagRow* _tmp18_;
				const gchar* _tmp19_;
				_row_index = _row_index + 1;
				_tmp7_ = _row_index;
				_tmp8_ = _row_size;
				if (!(_tmp7_ < _tmp8_)) {
					break;
				}
				_tmp9_ = _row_list;
				_tmp10_ = gee_list_get (_tmp9_, _row_index);
				row = (TagRow*) _tmp10_;
				_tmp11_ = row;
				_tmp12_ = row;
				_tmp13_ = _tmp12_->name;
				_tmp14_ = string_replace (_tmp13_, TAG_PATH_SEPARATOR_STRING, "-");
				_g_free0 (_tmp11_->name);
				_tmp11_->name = _tmp14_;
				_tmp15_ = table;
				_tmp16_ = row;
				_tmp17_ = _tmp16_->tag_id;
				_tmp18_ = row;
				_tmp19_ = _tmp18_->name;
				tag_table_rename (_tmp15_, &_tmp17_, _tmp19_, &_inner_error0_);
				if (G_UNLIKELY (_inner_error0_ != NULL)) {
					_tag_row_unref0 (row);
					_g_object_unref0 (rows);
					if (_inner_error0_->domain == DATABASE_ERROR) {
						goto __catch0_database_error;
					}
					_database_table_unref0 (table);
					g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
					g_clear_error (&_inner_error0_);
					return;
				}
				_tag_row_unref0 (row);
			}
		}
		_g_object_unref0 (rows);
	}
	goto __finally0;
	__catch0_database_error:
	{
		GError* e = NULL;
		const gchar* _tmp20_;
		e = _inner_error0_;
		_inner_error0_ = NULL;
		_tmp20_ = e->message;
		g_error ("TagTable.vala:83: TagTable: can't upgrade tag names for hierarchical t" \
"ag support: %s", _tmp20_);
		_g_error_free0 (e);
	}
	__finally0:
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		_database_table_unref0 (table);
		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
		g_clear_error (&_inner_error0_);
		return;
	}
	_database_table_unref0 (table);
}

TagRow*
tag_table_add (TagTable* self,
               const gchar* name,
               GError** error)
{
	sqlite3_stmt* stmt = NULL;
	sqlite3_stmt* _tmp0_;
	gint64 time_created = 0LL;
	sqlite3_stmt* _tmp1_;
	sqlite3_stmt* _tmp2_;
	gint res = 0;
	sqlite3_stmt* _tmp3_;
	TagRow* row = NULL;
	TagRow* _tmp4_;
	TagRow* _tmp5_;
	sqlite3* _tmp6_;
	TagRow* _tmp7_;
	gchar* _tmp8_;
	TagRow* _tmp9_;
	TagRow* _tmp10_;
	GError* _inner_error0_ = NULL;
	TagRow* result;
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (name != NULL, NULL);
	_tmp0_ = database_table_create_stmt ((DatabaseTable*) self, "INSERT INTO TagTable (name, time_created) VALUES (?, ?)");
	stmt = _tmp0_;
	time_created = now_sec ();
	_tmp1_ = stmt;
	database_table_bind_text (_tmp1_, 1, name);
	_tmp2_ = stmt;
	database_table_bind_int64 (_tmp2_, 2, time_created);
	_tmp3_ = stmt;
	res = sqlite3_step (_tmp3_);
	if (res != SQLITE_DONE) {
		database_table_throw_error ("TagTable.add", res, &_inner_error0_);
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			if (_inner_error0_->domain == DATABASE_ERROR) {
				g_propagate_error (error, _inner_error0_);
				_sqlite3_finalize0 (stmt);
				return NULL;
			} else {
				_sqlite3_finalize0 (stmt);
				g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
				g_clear_error (&_inner_error0_);
				return NULL;
			}
		}
	}
	_tmp4_ = tag_row_new ();
	row = _tmp4_;
	_tmp5_ = row;
	_tmp6_ = database_table_db;
	tag_id_init (&_tmp5_->tag_id, sqlite3_last_insert_rowid (_tmp6_));
	_tmp7_ = row;
	_tmp8_ = g_strdup (name);
	_g_free0 (_tmp7_->name);
	_tmp7_->name = _tmp8_;
	_tmp9_ = row;
	_g_object_unref0 (_tmp9_->source_id_list);
	_tmp9_->source_id_list = NULL;
	_tmp10_ = row;
	_tmp10_->time_created = time_created;
	result = row;
	_sqlite3_finalize0 (stmt);
	return result;
}

void
tag_table_create_from_row (TagTable* self,
                           TagRow* row,
                           TagID* result,
                           GError** error)
{
	sqlite3_stmt* stmt = NULL;
	sqlite3_stmt* _tmp0_;
	sqlite3_stmt* _tmp1_;
	const gchar* _tmp2_;
	sqlite3_stmt* _tmp3_;
	GeeSet* _tmp4_;
	gchar* _tmp5_;
	gchar* _tmp6_;
	sqlite3_stmt* _tmp7_;
	gint res = 0;
	sqlite3_stmt* _tmp8_;
	sqlite3* _tmp9_;
	TagID _tmp10_ = {0};
	GError* _inner_error0_ = NULL;
	g_return_if_fail (self != NULL);
	g_return_if_fail (row != NULL);
	_tmp0_ = database_table_create_stmt ((DatabaseTable*) self, "INSERT INTO TagTable (name, photo_id_list, time_created) VALUES (?, ?," \
" ?)");
	stmt = _tmp0_;
	_tmp1_ = stmt;
	_tmp2_ = row->name;
	database_table_bind_text (_tmp1_, 1, _tmp2_);
	_tmp3_ = stmt;
	_tmp4_ = row->source_id_list;
	_tmp5_ = tag_table_serialize_source_ids (self, (GeeCollection*) _tmp4_);
	_tmp6_ = _tmp5_;
	database_table_bind_text (_tmp3_, 2, _tmp6_);
	_g_free0 (_tmp6_);
	_tmp7_ = stmt;
	database_table_bind_int64 (_tmp7_, 3, row->time_created);
	_tmp8_ = stmt;
	res = sqlite3_step (_tmp8_);
	if (res != SQLITE_DONE) {
		database_table_throw_error ("TagTable.create_from_row", res, &_inner_error0_);
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			if (_inner_error0_->domain == DATABASE_ERROR) {
				g_propagate_error (error, _inner_error0_);
				_sqlite3_finalize0 (stmt);
				return;
			} else {
				_sqlite3_finalize0 (stmt);
				g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
				g_clear_error (&_inner_error0_);
				return;
			}
		}
	}
	_tmp9_ = database_table_db;
	tag_id_init (&_tmp10_, sqlite3_last_insert_rowid (_tmp9_));
	*result = _tmp10_;
	_sqlite3_finalize0 (stmt);
	return;
}

void
tag_table_remove (TagTable* self,
                  TagID* tag_id,
                  GError** error)
{
	TagID _tmp0_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (self != NULL);
	g_return_if_fail (tag_id != NULL);
	_tmp0_ = *tag_id;
	database_table_delete_by_id ((DatabaseTable*) self, _tmp0_.id, &_inner_error0_);
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		if (_inner_error0_->domain == DATABASE_ERROR) {
			g_propagate_error (error, _inner_error0_);
			return;
		} else {
			g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return;
		}
	}
}

gchar*
tag_table_get_name (TagTable* self,
                    TagID* tag_id,
                    GError** error)
{
	sqlite3_stmt* stmt = NULL;
	TagID _tmp0_;
	sqlite3_stmt* _tmp1_ = NULL;
	gboolean _tmp2_;
	sqlite3_stmt* _tmp3_;
	const gchar* _tmp4_;
	gchar* _tmp5_;
	gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (tag_id != NULL, NULL);
	_tmp0_ = *tag_id;
	_tmp2_ = database_table_select_by_id ((DatabaseTable*) self, _tmp0_.id, "name", &_tmp1_);
	_sqlite3_finalize0 (stmt);
	stmt = _tmp1_;
	if (!_tmp2_) {
		result = NULL;
		_sqlite3_finalize0 (stmt);
		return result;
	}
	_tmp3_ = stmt;
	_tmp4_ = (const gchar*) sqlite3_column_text (_tmp3_, 0);
	_tmp5_ = g_strdup (_tmp4_);
	result = _tmp5_;
	_sqlite3_finalize0 (stmt);
	return result;
}

TagRow*
tag_table_get_row (TagTable* self,
                   TagID* tag_id,
                   GError** error)
{
	sqlite3_stmt* stmt = NULL;
	sqlite3_stmt* _tmp0_;
	sqlite3_stmt* _tmp1_;
	TagID _tmp2_;
	gint res = 0;
	sqlite3_stmt* _tmp3_;
	TagRow* row = NULL;
	TagRow* _tmp4_;
	TagRow* _tmp5_;
	TagID _tmp6_;
	TagRow* _tmp7_;
	sqlite3_stmt* _tmp8_;
	const gchar* _tmp9_;
	gchar* _tmp10_;
	TagRow* _tmp11_;
	sqlite3_stmt* _tmp12_;
	const gchar* _tmp13_;
	GeeSet* _tmp14_;
	TagRow* _tmp15_;
	sqlite3_stmt* _tmp16_;
	GError* _inner_error0_ = NULL;
	TagRow* result;
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (tag_id != NULL, NULL);
	_tmp0_ = database_table_create_stmt ((DatabaseTable*) self, "SELECT name, photo_id_list, time_created FROM TagTable WHERE id=?");
	stmt = _tmp0_;
	_tmp1_ = stmt;
	_tmp2_ = *tag_id;
	database_table_bind_int64 (_tmp1_, 1, _tmp2_.id);
	_tmp3_ = stmt;
	res = sqlite3_step (_tmp3_);
	if (res == SQLITE_DONE) {
		result = NULL;
		_sqlite3_finalize0 (stmt);
		return result;
	} else {
		if (res != SQLITE_ROW) {
			database_table_throw_error ("TagTable.get_row", res, &_inner_error0_);
			if (G_UNLIKELY (_inner_error0_ != NULL)) {
				if (_inner_error0_->domain == DATABASE_ERROR) {
					g_propagate_error (error, _inner_error0_);
					_sqlite3_finalize0 (stmt);
					return NULL;
				} else {
					_sqlite3_finalize0 (stmt);
					g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
					g_clear_error (&_inner_error0_);
					return NULL;
				}
			}
		}
	}
	_tmp4_ = tag_row_new ();
	row = _tmp4_;
	_tmp5_ = row;
	_tmp6_ = *tag_id;
	_tmp5_->tag_id = _tmp6_;
	_tmp7_ = row;
	_tmp8_ = stmt;
	_tmp9_ = (const gchar*) sqlite3_column_text (_tmp8_, 0);
	_tmp10_ = g_strdup (_tmp9_);
	_g_free0 (_tmp7_->name);
	_tmp7_->name = _tmp10_;
	_tmp11_ = row;
	_tmp12_ = stmt;
	_tmp13_ = (const gchar*) sqlite3_column_text (_tmp12_, 1);
	_tmp14_ = tag_table_unserialize_source_ids (self, _tmp13_);
	_g_object_unref0 (_tmp11_->source_id_list);
	_tmp11_->source_id_list = _tmp14_;
	_tmp15_ = row;
	_tmp16_ = stmt;
	_tmp15_->time_created = sqlite3_column_int64 (_tmp16_, 2);
	result = row;
	_sqlite3_finalize0 (stmt);
	return result;
}

GeeList*
tag_table_get_all_rows (TagTable* self,
                        GError** error)
{
	sqlite3_stmt* stmt = NULL;
	sqlite3_stmt* _tmp0_;
	GeeList* rows = NULL;
	GeeArrayList* _tmp1_;
	GError* _inner_error0_ = NULL;
	GeeList* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = database_table_create_stmt ((DatabaseTable*) self, "SELECT id, name, photo_id_list, time_created FROM TagTable");
	stmt = _tmp0_;
	_tmp1_ = gee_array_list_new (TYPE_TAG_ROW, (GBoxedCopyFunc) tag_row_ref, (GDestroyNotify) tag_row_unref, NULL, NULL, NULL);
	rows = (GeeList*) _tmp1_;
	{
		gboolean _tmp2_ = FALSE;
		_tmp2_ = TRUE;
		while (TRUE) {
			gint res = 0;
			sqlite3_stmt* _tmp3_;
			TagRow* row = NULL;
			TagRow* _tmp4_;
			TagRow* _tmp5_;
			sqlite3_stmt* _tmp6_;
			TagRow* _tmp7_;
			sqlite3_stmt* _tmp8_;
			const gchar* _tmp9_;
			gchar* _tmp10_;
			TagRow* _tmp11_;
			sqlite3_stmt* _tmp12_;
			const gchar* _tmp13_;
			GeeSet* _tmp14_;
			TagRow* _tmp15_;
			sqlite3_stmt* _tmp16_;
			GeeList* _tmp17_;
			TagRow* _tmp18_;
			if (!_tmp2_) {
			}
			_tmp2_ = FALSE;
			_tmp3_ = stmt;
			res = sqlite3_step (_tmp3_);
			if (res == SQLITE_DONE) {
				break;
			} else {
				if (res != SQLITE_ROW) {
					database_table_throw_error ("TagTable.get_all_rows", res, &_inner_error0_);
					if (G_UNLIKELY (_inner_error0_ != NULL)) {
						if (_inner_error0_->domain == DATABASE_ERROR) {
							g_propagate_error (error, _inner_error0_);
							_g_object_unref0 (rows);
							_sqlite3_finalize0 (stmt);
							return NULL;
						} else {
							_g_object_unref0 (rows);
							_sqlite3_finalize0 (stmt);
							g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
							g_clear_error (&_inner_error0_);
							return NULL;
						}
					}
				}
			}
			_tmp4_ = tag_row_new ();
			row = _tmp4_;
			_tmp5_ = row;
			_tmp6_ = stmt;
			tag_id_init (&_tmp5_->tag_id, sqlite3_column_int64 (_tmp6_, 0));
			_tmp7_ = row;
			_tmp8_ = stmt;
			_tmp9_ = (const gchar*) sqlite3_column_text (_tmp8_, 1);
			_tmp10_ = g_strdup (_tmp9_);
			_g_free0 (_tmp7_->name);
			_tmp7_->name = _tmp10_;
			_tmp11_ = row;
			_tmp12_ = stmt;
			_tmp13_ = (const gchar*) sqlite3_column_text (_tmp12_, 2);
			_tmp14_ = tag_table_unserialize_source_ids (self, _tmp13_);
			_g_object_unref0 (_tmp11_->source_id_list);
			_tmp11_->source_id_list = _tmp14_;
			_tmp15_ = row;
			_tmp16_ = stmt;
			_tmp15_->time_created = sqlite3_column_int64 (_tmp16_, 3);
			_tmp17_ = rows;
			_tmp18_ = row;
			gee_collection_add ((GeeCollection*) _tmp17_, _tmp18_);
			_tag_row_unref0 (row);
		}
	}
	result = rows;
	_sqlite3_finalize0 (stmt);
	return result;
}

void
tag_table_rename (TagTable* self,
                  TagID* tag_id,
                  const gchar* new_name,
                  GError** error)
{
	TagID _tmp0_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (self != NULL);
	g_return_if_fail (tag_id != NULL);
	g_return_if_fail (new_name != NULL);
	_tmp0_ = *tag_id;
	database_table_update_text_by_id_2 ((DatabaseTable*) self, _tmp0_.id, "name", new_name, &_inner_error0_);
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		if (_inner_error0_->domain == DATABASE_ERROR) {
			g_propagate_error (error, _inner_error0_);
			return;
		} else {
			g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return;
		}
	}
}

void
tag_table_set_tagged_sources (TagTable* self,
                              TagID* tag_id,
                              GeeCollection* source_ids,
                              GError** error)
{
	sqlite3_stmt* stmt = NULL;
	sqlite3_stmt* _tmp0_;
	gchar* serialized = NULL;
	gchar* _tmp1_;
	const gchar* _tmp2_;
	sqlite3_stmt* _tmp6_;
	TagID _tmp7_;
	gint res = 0;
	sqlite3_stmt* _tmp8_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (self != NULL);
	g_return_if_fail (tag_id != NULL);
	g_return_if_fail (source_ids != NULL);
	_tmp0_ = database_table_create_stmt ((DatabaseTable*) self, "UPDATE TagTable SET photo_id_list=? WHERE id=?");
	stmt = _tmp0_;
	_tmp1_ = tag_table_serialize_source_ids (self, source_ids);
	serialized = _tmp1_;
	_tmp2_ = serialized;
	if (_tmp2_ == NULL) {
		sqlite3_stmt* _tmp3_;
		_tmp3_ = stmt;
		database_table_bind_null (_tmp3_, 1);
	} else {
		sqlite3_stmt* _tmp4_;
		const gchar* _tmp5_;
		_tmp4_ = stmt;
		_tmp5_ = serialized;
		database_table_bind_text (_tmp4_, 1, _tmp5_);
	}
	_tmp6_ = stmt;
	_tmp7_ = *tag_id;
	database_table_bind_int64 (_tmp6_, 2, _tmp7_.id);
	_tmp8_ = stmt;
	res = sqlite3_step (_tmp8_);
	if (res != SQLITE_DONE) {
		database_table_throw_error ("TagTable.set_tagged_photos", res, &_inner_error0_);
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			if (_inner_error0_->domain == DATABASE_ERROR) {
				g_propagate_error (error, _inner_error0_);
				_g_free0 (serialized);
				_sqlite3_finalize0 (stmt);
				return;
			} else {
				_g_free0 (serialized);
				_sqlite3_finalize0 (stmt);
				g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
				g_clear_error (&_inner_error0_);
				return;
			}
		}
	}
	_g_free0 (serialized);
	_sqlite3_finalize0 (stmt);
}

static gchar*
tag_table_serialize_source_ids (TagTable* self,
                                GeeCollection* source_ids)
{
	GString* _result_ = NULL;
	GString* _tmp0_;
	const gchar* _tmp8_ = NULL;
	GString* _tmp9_;
	gchar* _tmp12_;
	gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	if (source_ids == NULL) {
		result = NULL;
		return result;
	}
	_tmp0_ = g_string_new ("");
	_result_ = _tmp0_;
	{
		GeeIterator* _source_id_it = NULL;
		GeeIterator* _tmp1_;
		_tmp1_ = gee_iterable_iterator ((GeeIterable*) source_ids);
		_source_id_it = _tmp1_;
		while (TRUE) {
			GeeIterator* _tmp2_;
			gchar* source_id = NULL;
			GeeIterator* _tmp3_;
			gpointer _tmp4_;
			GString* _tmp5_;
			const gchar* _tmp6_;
			GString* _tmp7_;
			_tmp2_ = _source_id_it;
			if (!gee_iterator_next (_tmp2_)) {
				break;
			}
			_tmp3_ = _source_id_it;
			_tmp4_ = gee_iterator_get (_tmp3_);
			source_id = (gchar*) _tmp4_;
			_tmp5_ = _result_;
			_tmp6_ = source_id;
			g_string_append (_tmp5_, _tmp6_);
			_tmp7_ = _result_;
			g_string_append (_tmp7_, ",");
			_g_free0 (source_id);
		}
		_g_object_unref0 (_source_id_it);
	}
	_tmp9_ = _result_;
	if (_tmp9_->len != ((gssize) 0)) {
		GString* _tmp10_;
		const gchar* _tmp11_;
		_tmp10_ = _result_;
		_tmp11_ = _tmp10_->str;
		_tmp8_ = _tmp11_;
	} else {
		_tmp8_ = NULL;
	}
	_tmp12_ = g_strdup (_tmp8_);
	result = _tmp12_;
	_g_string_free0 (_result_);
	return result;
}

static gchar
string_get (const gchar* self,
            glong index)
{
	gchar _tmp0_;
	gchar result;
	g_return_val_if_fail (self != NULL, '\0');
	_tmp0_ = ((gchar*) self)[index];
	result = _tmp0_;
	return result;
}

static GeeSet*
tag_table_unserialize_source_ids (TagTable* self,
                                  const gchar* text_list)
{
	GeeSet* _result_ = NULL;
	GeeHashSet* _tmp0_;
	gchar** split = NULL;
	gchar** _tmp1_;
	gchar** _tmp2_;
	gint split_length1;
	gint _split_size_;
	gchar** _tmp3_;
	gint _tmp3__length1;
	GeeSet* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = gee_hash_set_new (G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free, NULL, NULL, NULL, NULL, NULL, NULL);
	_result_ = (GeeSet*) _tmp0_;
	if (text_list == NULL) {
		result = _result_;
		return result;
	}
	_tmp2_ = _tmp1_ = g_strsplit (text_list, ",", 0);
	split = _tmp2_;
	split_length1 = _vala_array_length (_tmp1_);
	_split_size_ = split_length1;
	_tmp3_ = split;
	_tmp3__length1 = split_length1;
	{
		gchar** token_collection = NULL;
		gint token_collection_length1 = 0;
		gint _token_collection_size_ = 0;
		gint token_it = 0;
		token_collection = _tmp3_;
		token_collection_length1 = _tmp3__length1;
		for (token_it = 0; token_it < token_collection_length1; token_it = token_it + 1) {
			gchar* _tmp4_;
			gchar* token = NULL;
			_tmp4_ = g_strdup (token_collection[token_it]);
			token = _tmp4_;
			{
				const gchar* _tmp5_;
				const gchar* _tmp6_;
				_tmp5_ = token;
				if (is_string_empty (_tmp5_)) {
					_g_free0 (token);
					continue;
				}
				_tmp6_ = token;
				if (g_ascii_isdigit (string_get (_tmp6_, (glong) 0))) {
					GeeSet* _tmp7_;
					const gchar* _tmp8_;
					PhotoID _tmp9_ = {0};
					gchar* _tmp10_;
					gchar* _tmp11_;
					_tmp7_ = _result_;
					_tmp8_ = token;
					photo_id_init (&_tmp9_, parse_int64 (_tmp8_, 10));
					_tmp10_ = photo_id_upgrade_photo_id_to_source_id (&_tmp9_);
					_tmp11_ = _tmp10_;
					gee_collection_add ((GeeCollection*) _tmp7_, _tmp11_);
					_g_free0 (_tmp11_);
				} else {
					const gchar* _tmp12_;
					_tmp12_ = token;
					if (g_ascii_isalpha (string_get (_tmp12_, (glong) 0))) {
						GeeSet* _tmp13_;
						const gchar* _tmp14_;
						_tmp13_ = _result_;
						_tmp14_ = token;
						gee_collection_add ((GeeCollection*) _tmp13_, _tmp14_);
					}
				}
				_g_free0 (token);
			}
		}
	}
	result = _result_;
	split = (_vala_array_free (split, split_length1, (GDestroyNotify) g_free), NULL);
	return result;
}

static void
tag_table_class_init (TagTableClass * klass,
                      gpointer klass_data)
{
	tag_table_parent_class = g_type_class_peek_parent (klass);
	((DatabaseTableClass *) klass)->finalize = tag_table_finalize;
}

static void
tag_table_instance_init (TagTable * self,
                         gpointer klass)
{
}

static void
tag_table_finalize (DatabaseTable * obj)
{
	TagTable * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_TAG_TABLE, TagTable);
	DATABASE_TABLE_CLASS (tag_table_parent_class)->finalize (obj);
}

static GType
tag_table_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (TagTableClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) tag_table_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (TagTable), 0, (GInstanceInitFunc) tag_table_instance_init, NULL };
	GType tag_table_type_id;
	tag_table_type_id = g_type_register_static (TYPE_DATABASE_TABLE, "TagTable", &g_define_type_info, 0);
	return tag_table_type_id;
}

GType
tag_table_get_type (void)
{
	static volatile gsize tag_table_type_id__once = 0;
	if (g_once_init_enter (&tag_table_type_id__once)) {
		GType tag_table_type_id;
		tag_table_type_id = tag_table_get_type_once ();
		g_once_init_leave (&tag_table_type_id__once, tag_table_type_id);
	}
	return tag_table_type_id__once;
}

static void
_vala_array_destroy (gpointer array,
                     gssize array_length,
                     GDestroyNotify destroy_func)
{
	if ((array != NULL) && (destroy_func != NULL)) {
		gssize i;
		for (i = 0; i < array_length; i = i + 1) {
			if (((gpointer*) array)[i] != NULL) {
				destroy_func (((gpointer*) array)[i]);
			}
		}
	}
}

static void
_vala_array_free (gpointer array,
                  gssize array_length,
                  GDestroyNotify destroy_func)
{
	_vala_array_destroy (array, array_length, destroy_func);
	g_free (array);
}

static gssize
_vala_array_length (gpointer array)
{
	gssize length;
	length = 0;
	if (array) {
		while (((gpointer*) array)[length]) {
			length++;
		}
	}
	return length;
}

