/* search-view.c generated by valac 0.56.0, the Vala compiler
 * generated from search-view.vala, do not modify */

/*
 * Copyright (C) 2011, 2015 Collabora Ltd.
 *
 * 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:
 *       Travis Reitter <travis.reitter@collabora.co.uk>
 *       Philip Withnall <philip.withnall@collabora.co.uk>
 */

#include "folks/folks.h"
#include <glib.h>
#include <gee.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <stdlib.h>
#include <string.h>

enum  {
	FOLKS_SEARCH_VIEW_0_PROPERTY,
	FOLKS_SEARCH_VIEW_AGGREGATOR_PROPERTY,
	FOLKS_SEARCH_VIEW_QUERY_PROPERTY,
	FOLKS_SEARCH_VIEW_INDIVIDUALS_PROPERTY,
	FOLKS_SEARCH_VIEW_IS_PREPARED_PROPERTY,
	FOLKS_SEARCH_VIEW_IS_QUIESCENT_PROPERTY,
	FOLKS_SEARCH_VIEW_NUM_PROPERTIES
};
static GParamSpec* folks_search_view_properties[FOLKS_SEARCH_VIEW_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
typedef struct _FolksSearchViewPrepareData FolksSearchViewPrepareData;
typedef struct _FolksSearchViewUnprepareData FolksSearchViewUnprepareData;
typedef struct _FolksSearchViewRefreshData FolksSearchViewRefreshData;
#define _g_free0(var) (var = (g_free (var), NULL))
enum  {
	FOLKS_SEARCH_VIEW_INDIVIDUALS_CHANGED_DETAILED_SIGNAL,
	FOLKS_SEARCH_VIEW_NUM_SIGNALS
};
static guint folks_search_view_signals[FOLKS_SEARCH_VIEW_NUM_SIGNALS] = {0};

struct _FolksSearchViewPrivate {
	gboolean _prepare_pending;
	FolksIndividualAggregator* _aggregator;
	FolksQuery* _query;
	GeeSortedSet* _individuals;
	GeeSortedSet* _individuals_ro;
	gboolean _is_prepared;
};

struct _FolksSearchViewPrepareData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	FolksSearchView* self;
	gboolean _tmp0_;
	FolksIndividualAggregator* _tmp1_;
	FolksIndividualAggregator* _tmp2_;
	GError* e;
	FolksIndividualAggregator* _tmp3_;
	guint _tmp4_;
	GError* _tmp5_;
	GError* _tmp6_;
	GError* _inner_error0_;
};

struct _FolksSearchViewUnprepareData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	FolksSearchView* self;
	gboolean _tmp0_;
};

struct _FolksSearchViewRefreshData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	FolksSearchView* self;
};

static gint FolksSearchView_private_offset;
static gpointer folks_search_view_parent_class = NULL;

static void _folks_search_view_aggregator_is_quiescent_cb (FolksSearchView* self);
static void __folks_search_view_aggregator_is_quiescent_cb_g_object_notify (GObject* _sender,
                                                                     GParamSpec* pspec,
                                                                     gpointer self);
static GeeSortedSet* _folks_search_view_create_empty_sorted_set (FolksSearchView* self);
static void folks_search_view_prepare_data_free (gpointer _data);
static gboolean folks_search_view_prepare_co (FolksSearchViewPrepareData* _data_);
static void _folks_search_view_aggregator_individuals_changed_detailed_cb (FolksSearchView* self,
                                                                    GeeMultiMap* changes);
static void __folks_search_view_aggregator_individuals_changed_detailed_cb_folks_individual_aggregator_individuals_changed_detailed (FolksIndividualAggregator* _sender,
                                                                                                                              GeeMultiMap* changes,
                                                                                                                              gpointer self);
static void folks_search_view_prepare_ready (GObject* source_object,
                                      GAsyncResult* _res_,
                                      gpointer _user_data_);
static void folks_search_view_unprepare_data_free (gpointer _data);
static gboolean folks_search_view_unprepare_co (FolksSearchViewUnprepareData* _data_);
static void folks_search_view_refresh_data_free (gpointer _data);
static gboolean folks_search_view_refresh_co (FolksSearchViewRefreshData* _data_);
static void _folks_search_view_evaluate_all_aggregator_individuals (FolksSearchView* self);
static void _folks_search_view_evaluate_individuals (FolksSearchView* self,
                                              GeeMultiMap* changes,
                                              GeeSet* evaluates);
static gchar* _folks_search_view_build_match_strength_key (FolksSearchView* self);
static gint _folks_search_view_compare_individual_matches (FolksSearchView* self,
                                                    FolksIndividual* a,
                                                    FolksIndividual* b);
static gint __folks_search_view_compare_individual_matches_gcompare_data_func (gconstpointer a,
                                                                        gconstpointer b,
                                                                        gpointer self);
static gboolean _folks_search_view_check_match (FolksSearchView* self,
                                         FolksIndividual* individual);
static inline gboolean _folks_search_view_remove_individual (FolksSearchView* self,
                                               FolksIndividual* individual);
static inline gboolean _folks_search_view_add_individual (FolksSearchView* self,
                                            FolksIndividual* individual);
static void _folks_search_view_individual_notify_cb (FolksSearchView* self,
                                              GObject* obj,
                                              GParamSpec* ps);
static void __folks_search_view_individual_notify_cb_g_object_notify (GObject* _sender,
                                                               GParamSpec* pspec,
                                                               gpointer self);
static gboolean _folks_search_view_evaluate_match (FolksSearchView* self,
                                            FolksIndividual* individual);
static void _folks_search_view_query_notify_cb (FolksSearchView* self,
                                         GObject* obj,
                                         GParamSpec* ps);
static void __folks_search_view_query_notify_cb_g_object_notify (GObject* _sender,
                                                          GParamSpec* pspec,
                                                          gpointer self);
static void g_cclosure_user_marshal_VOID__OBJECT_OBJECT (GClosure * closure,
                                                  GValue * return_value,
                                                  guint n_param_values,
                                                  const GValue * param_values,
                                                  gpointer invocation_hint,
                                                  gpointer marshal_data);
static void folks_search_view_finalize (GObject * obj);
static GType folks_search_view_get_type_once (void);
static void _vala_folks_search_view_get_property (GObject * object,
                                           guint property_id,
                                           GValue * value,
                                           GParamSpec * pspec);
static void _vala_folks_search_view_set_property (GObject * object,
                                           guint property_id,
                                           const GValue * value,
                                           GParamSpec * pspec);
static inline gpointer _vala_memdup2 (gconstpointer mem,
                        gsize byte_size);

static inline gpointer
folks_search_view_get_instance_private (FolksSearchView* self)
{
	return G_STRUCT_MEMBER_P (self, FolksSearchView_private_offset);
}

static void
__folks_search_view_aggregator_is_quiescent_cb_g_object_notify (GObject* _sender,
                                                                GParamSpec* pspec,
                                                                gpointer self)
{
	_folks_search_view_aggregator_is_quiescent_cb ((FolksSearchView*) self);
}

static void
_folks_search_view_aggregator_is_quiescent_cb (FolksSearchView* self)
{
	g_return_if_fail (self != NULL);
	g_object_notify ((GObject*) self, "is-quiescent");
}

/**
   * Create a new view of Individuals matching a given query.
   *
   * This view will be kept up-to-date as individuals change (which may change
   * their membership in the results).
   *
   * @param query query to match upon
   * @param aggregator the {@link IndividualAggregator} to match within
   *
   * @since 0.11.0
   */
static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

FolksSearchView*
folks_search_view_construct (GType object_type,
                             FolksIndividualAggregator* aggregator,
                             FolksQuery* query)
{
	FolksSearchView * self = NULL;
	FolksIndividualAggregator* _tmp0_;
	FolksIndividualAggregator* _tmp1_;
	GeeSortedSet* _tmp2_;
	GeeSortedSet* _tmp3_;
	GeeSortedSet* _tmp4_;
	GeeSortedSet* _tmp5_;
	FolksQuery* _tmp6_;
	g_return_val_if_fail (aggregator != NULL, NULL);
	g_return_val_if_fail (query != NULL, NULL);
	self = (FolksSearchView*) g_object_new (object_type, NULL);
	g_debug ("search-view.vala:194: Constructing SearchView %p", self);
	_tmp0_ = _g_object_ref0 (aggregator);
	_g_object_unref0 (self->priv->_aggregator);
	self->priv->_aggregator = _tmp0_;
	_tmp1_ = self->priv->_aggregator;
	g_signal_connect_object ((GObject*) _tmp1_, "notify::is-quiescent", (GCallback) __folks_search_view_aggregator_is_quiescent_cb_g_object_notify, self, 0);
	_tmp2_ = _folks_search_view_create_empty_sorted_set (self);
	_g_object_unref0 (self->priv->_individuals);
	self->priv->_individuals = _tmp2_;
	_tmp3_ = self->priv->_individuals;
	_tmp4_ = gee_sorted_set_get_read_only_view (_tmp3_);
	_tmp5_ = _tmp4_;
	_g_object_unref0 (self->priv->_individuals_ro);
	self->priv->_individuals_ro = _tmp5_;
	self->priv->_is_prepared = FALSE;
	self->priv->_prepare_pending = FALSE;
	_tmp6_ = _g_object_ref0 (query);
	_g_object_unref0 (self->priv->_query);
	self->priv->_query = _tmp6_;
	return self;
}

FolksSearchView*
folks_search_view_new (FolksIndividualAggregator* aggregator,
                       FolksQuery* query)
{
	return folks_search_view_construct (FOLKS_TYPE_SEARCH_VIEW, aggregator, query);
}

static void
folks_search_view_prepare_data_free (gpointer _data)
{
	FolksSearchViewPrepareData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->self);
	g_slice_free (FolksSearchViewPrepareData, _data_);
}

void
folks_search_view_prepare (FolksSearchView* self,
                           GAsyncReadyCallback _callback_,
                           gpointer _user_data_)
{
	FolksSearchViewPrepareData* _data_;
	FolksSearchView* _tmp0_;
	g_return_if_fail (self != NULL);
	_data_ = g_slice_new0 (FolksSearchViewPrepareData);
	_data_->_async_result = g_task_new (G_OBJECT (self), NULL, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, folks_search_view_prepare_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	folks_search_view_prepare_co (_data_);
}

void
folks_search_view_prepare_finish (FolksSearchView* self,
                                  GAsyncResult* _res_,
                                  GError** error)
{
	FolksSearchViewPrepareData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return;
	}
}

/**
   * Prepare the view for use.
   *
   * This calls {@link IndividualAggregator.prepare} as necessary to start
   * aggregating all {@link Individual}s.
   *
   * This function is guaranteed to be idempotent, so multiple search views may
   * share a single aggregator; {@link SearchView.prepare} must be called on all
   * of the views.
   *
   * For any clients only interested in a snapshot of search results,
   * {@link SearchView.individuals} is valid once this async function is
   * finished.
   *
   * @throws GLib.Error if preparation failed
   *
   * @since 0.11.0
   */
static void
__folks_search_view_aggregator_individuals_changed_detailed_cb_folks_individual_aggregator_individuals_changed_detailed (FolksIndividualAggregator* _sender,
                                                                                                                         GeeMultiMap* changes,
                                                                                                                         gpointer self)
{
	_folks_search_view_aggregator_individuals_changed_detailed_cb ((FolksSearchView*) self, changes);
}

static void
folks_search_view_prepare_ready (GObject* source_object,
                                 GAsyncResult* _res_,
                                 gpointer _user_data_)
{
	FolksSearchViewPrepareData* _data_;
	_data_ = _user_data_;
	_data_->_source_object_ = source_object;
	_data_->_res_ = _res_;
	folks_search_view_prepare_co (_data_);
}

static gpointer
_g_error_copy0 (gpointer self)
{
	return self ? g_error_copy (self) : NULL;
}

static gboolean
folks_search_view_prepare_co (FolksSearchViewPrepareData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		case 1:
		goto _state_1;
		case 2:
		goto _state_2;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	if (!_data_->self->priv->_is_prepared) {
		_data_->_tmp0_ = !_data_->self->priv->_prepare_pending;
	} else {
		_data_->_tmp0_ = FALSE;
	}
	if (_data_->_tmp0_) {
		_data_->self->priv->_prepare_pending = TRUE;
		_data_->_tmp1_ = _data_->self->priv->_aggregator;
		g_signal_connect_object (_data_->_tmp1_, "individuals-changed-detailed", (GCallback) __folks_search_view_aggregator_individuals_changed_detailed_cb_folks_individual_aggregator_individuals_changed_detailed, _data_->self, 0);
		{
			_data_->_tmp2_ = _data_->self->priv->_aggregator;
			_data_->_state_ = 1;
			folks_individual_aggregator_prepare (_data_->_tmp2_, folks_search_view_prepare_ready, _data_);
			return FALSE;
			_state_1:
			folks_individual_aggregator_prepare_finish (_data_->_tmp2_, _data_->_res_, &_data_->_inner_error0_);
			if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) {
				goto __catch0_g_error;
			}
		}
		goto __finally0;
		__catch0_g_error:
		{
			_data_->e = _data_->_inner_error0_;
			_data_->_inner_error0_ = NULL;
			_data_->self->priv->_prepare_pending = FALSE;
			_data_->_tmp3_ = _data_->self->priv->_aggregator;
			g_signal_parse_name ("individuals-changed-detailed", FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, &_data_->_tmp4_, NULL, FALSE);
			g_signal_handlers_disconnect_matched (_data_->_tmp3_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _data_->_tmp4_, 0, NULL, (GCallback) __folks_search_view_aggregator_individuals_changed_detailed_cb_folks_individual_aggregator_individuals_changed_detailed, _data_->self);
			_data_->_tmp5_ = _data_->e;
			_data_->_tmp6_ = _g_error_copy0 (_data_->_tmp5_);
			_data_->_inner_error0_ = _data_->_tmp6_;
			_g_error_free0 (_data_->e);
			goto __finally0;
		}
		__finally0:
		if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) {
			g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
			g_object_unref (_data_->_async_result);
			return FALSE;
		}
		_data_->self->priv->_is_prepared = TRUE;
		_data_->self->priv->_prepare_pending = FALSE;
		g_object_notify ((GObject*) _data_->self, "is-prepared");
		_data_->_state_ = 2;
		folks_search_view_refresh (_data_->self, folks_search_view_prepare_ready, _data_);
		return FALSE;
		_state_2:
		folks_search_view_refresh_finish (_data_->self, _data_->_res_, &_data_->_inner_error0_);
		if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) {
			g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
			g_object_unref (_data_->_async_result);
			return FALSE;
		}
	}
	g_task_return_pointer (_data_->_async_result, _data_, NULL);
	if (_data_->_state_ != 0) {
		while (!g_task_get_completed (_data_->_async_result)) {
			g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
		}
	}
	g_object_unref (_data_->_async_result);
	return FALSE;
}

static void
folks_search_view_unprepare_data_free (gpointer _data)
{
	FolksSearchViewUnprepareData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->self);
	g_slice_free (FolksSearchViewUnprepareData, _data_);
}

void
folks_search_view_unprepare (FolksSearchView* self,
                             GAsyncReadyCallback _callback_,
                             gpointer _user_data_)
{
	FolksSearchViewUnprepareData* _data_;
	FolksSearchView* _tmp0_;
	g_return_if_fail (self != NULL);
	_data_ = g_slice_new0 (FolksSearchViewUnprepareData);
	_data_->_async_result = g_task_new (G_OBJECT (self), NULL, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, folks_search_view_unprepare_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	folks_search_view_unprepare_co (_data_);
}

void
folks_search_view_unprepare_finish (FolksSearchView* self,
                                    GAsyncResult* _res_,
                                    GError** error)
{
	FolksSearchViewUnprepareData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return;
	}
}

/**
   * Clean up and release resources used by the search view.
   *
   * This will disconnect the aggregator cleanly from any resources it is using.
   * It is recommended to call this method before finalising the search view,
   * but calling it is not required.
   *
   * Note that this will not unprepare the underlying aggregator: call
   * {@link IndividualAggregator.unprepare} to do that. This allows multiple
   * search views to use a single aggregator and unprepare at different times.
   *
   * Concurrent calls to this function from different threads will block until
   * preparation has completed. However, concurrent calls to this function from
   * a single thread might not, i.e. the first call will block but subsequent
   * calls might return before the first one. (Though they will be safe in every
   * other respect.)
   *
   * @since 0.11.0
   * @throws GLib.Error if unpreparing the backend-specific services failed —
   * this will be a backend-specific error
   */
static gboolean
folks_search_view_unprepare_co (FolksSearchViewUnprepareData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	if (!_data_->self->priv->_is_prepared) {
		_data_->_tmp0_ = TRUE;
	} else {
		_data_->_tmp0_ = _data_->self->priv->_prepare_pending;
	}
	if (_data_->_tmp0_) {
		g_task_return_pointer (_data_->_async_result, _data_, NULL);
		if (_data_->_state_ != 0) {
			while (!g_task_get_completed (_data_->_async_result)) {
				g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
			}
		}
		g_object_unref (_data_->_async_result);
		return FALSE;
	}
	_data_->self->priv->_prepare_pending = FALSE;
	g_task_return_pointer (_data_->_async_result, _data_, NULL);
	if (_data_->_state_ != 0) {
		while (!g_task_get_completed (_data_->_async_result)) {
			g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
		}
	}
	g_object_unref (_data_->_async_result);
	return FALSE;
}

static void
folks_search_view_refresh_data_free (gpointer _data)
{
	FolksSearchViewRefreshData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->self);
	g_slice_free (FolksSearchViewRefreshData, _data_);
}

void
folks_search_view_refresh (FolksSearchView* self,
                           GAsyncReadyCallback _callback_,
                           gpointer _user_data_)
{
	FolksSearchViewRefreshData* _data_;
	FolksSearchView* _tmp0_;
	g_return_if_fail (self != NULL);
	_data_ = g_slice_new0 (FolksSearchViewRefreshData);
	_data_->_async_result = g_task_new (G_OBJECT (self), NULL, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, folks_search_view_refresh_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	folks_search_view_refresh_co (_data_);
}

void
folks_search_view_refresh_finish (FolksSearchView* self,
                                  GAsyncResult* _res_,
                                  GError** error)
{
	FolksSearchViewRefreshData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return;
	}
}

/**
   * Refresh the view’s results.
   *
   * Explicitly re-match all the view’s results to ensure matches are up to
   * date. For a normal {@link IndividualAggregator}, this is explicitly not
   * necessary, as the view will watch signal emissions from the aggregator and
   * keep itself up to date.
   *
   * However, for search-only persona stores, which do not support notification
   * of changes to personas, this method is the only way to update the set of
   * matches against the store.
   *
   * This method should be called whenever an explicit update is needed to the
   * search results, e.g. if the user requests a refresh.
   *
   * @throws GLib.Error if matching failed
   * @since 0.11.0
   */
static gboolean
folks_search_view_refresh_co (FolksSearchViewRefreshData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	if (_data_->self->priv->_is_prepared) {
		_folks_search_view_evaluate_all_aggregator_individuals (_data_->self);
	}
	g_task_return_pointer (_data_->_async_result, _data_, NULL);
	if (_data_->_state_ != 0) {
		while (!g_task_get_completed (_data_->_async_result)) {
			g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
		}
	}
	g_object_unref (_data_->_async_result);
	return FALSE;
}

static void
_folks_search_view_aggregator_individuals_changed_detailed_cb (FolksSearchView* self,
                                                               GeeMultiMap* changes)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (changes != NULL);
	_folks_search_view_evaluate_individuals (self, changes, NULL);
}

static gchar*
_folks_search_view_build_match_strength_key (FolksSearchView* self)
{
	gchar* _tmp0_;
	gchar* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = g_strdup_printf ("folks-match-strength-%p", self);
	result = _tmp0_;
	return result;
}

static gint
_folks_search_view_compare_individual_matches (FolksSearchView* self,
                                               FolksIndividual* a,
                                               FolksIndividual* b)
{
	gchar* key = NULL;
	gchar* _tmp0_;
	guint match_strength_a = 0U;
	const gchar* _tmp1_;
	gconstpointer _tmp2_;
	guint match_strength_b = 0U;
	const gchar* _tmp3_;
	gconstpointer _tmp4_;
	gint display_name = 0;
	const gchar* _tmp5_;
	const gchar* _tmp6_;
	const gchar* _tmp7_;
	const gchar* _tmp8_;
	const gchar* _tmp9_;
	const gchar* _tmp10_;
	const gchar* _tmp11_;
	const gchar* _tmp12_;
	gint result;
	g_return_val_if_fail (self != NULL, 0);
	g_return_val_if_fail (a != NULL, 0);
	g_return_val_if_fail (b != NULL, 0);
	if (a == b) {
		result = 0;
		return result;
	}
	_tmp0_ = _folks_search_view_build_match_strength_key (self);
	key = _tmp0_;
	_tmp1_ = key;
	_tmp2_ = g_object_get_data ((GObject*) a, _tmp1_);
	match_strength_a = (guint) ((guintptr) _tmp2_);
	_tmp3_ = key;
	_tmp4_ = g_object_get_data ((GObject*) b, _tmp3_);
	match_strength_b = (guint) ((guintptr) _tmp4_);
	if (match_strength_a != match_strength_b) {
		result = ((gint) match_strength_b) - ((gint) match_strength_a);
		_g_free0 (key);
		return result;
	}
	_tmp5_ = folks_individual_get_display_name (a);
	_tmp6_ = _tmp5_;
	_tmp7_ = folks_individual_get_display_name (b);
	_tmp8_ = _tmp7_;
	display_name = g_utf8_collate (_tmp6_, _tmp8_);
	if (display_name != 0) {
		result = display_name;
		_g_free0 (key);
		return result;
	}
	_tmp9_ = folks_individual_get_id (a);
	_tmp10_ = _tmp9_;
	_tmp11_ = folks_individual_get_id (b);
	_tmp12_ = _tmp11_;
	result = g_utf8_collate (_tmp10_, _tmp12_);
	_g_free0 (key);
	return result;
}

static gint
__folks_search_view_compare_individual_matches_gcompare_data_func (gconstpointer a,
                                                                   gconstpointer b,
                                                                   gpointer self)
{
	gint result;
	result = _folks_search_view_compare_individual_matches ((FolksSearchView*) self, (FolksIndividual*) a, (FolksIndividual*) b);
	return result;
}

static GeeSortedSet*
_folks_search_view_create_empty_sorted_set (FolksSearchView* self)
{
	GeeTreeSet* _tmp0_;
	GeeSortedSet* result;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = gee_tree_set_new (FOLKS_TYPE_INDIVIDUAL, (GBoxedCopyFunc) g_object_ref, (GDestroyNotify) g_object_unref, __folks_search_view_compare_individual_matches_gcompare_data_func, g_object_ref (self), g_object_unref);
	result = (GeeSortedSet*) _tmp0_;
	return result;
}

static void
_folks_search_view_evaluate_individuals (FolksSearchView* self,
                                         GeeMultiMap* changes,
                                         GeeSet* evaluates)
{
	GeeSortedSet* view_added = NULL;
	GeeSortedSet* _tmp0_;
	GeeSortedSet* view_removed = NULL;
	GeeSortedSet* _tmp1_;
	GeeIterator* iter = NULL;
	GeeSortedSet* _tmp26_;
	GeeIterator* _tmp27_;
	GeeSortedSet* _tmp35_;
	GeeIterator* _tmp36_;
	gboolean _tmp44_ = FALSE;
	GeeSortedSet* _tmp45_;
	gint _tmp46_;
	gint _tmp47_;
	g_return_if_fail (self != NULL);
	_tmp0_ = _folks_search_view_create_empty_sorted_set (self);
	view_added = _tmp0_;
	_tmp1_ = _folks_search_view_create_empty_sorted_set (self);
	view_removed = _tmp1_;
	if (evaluates != NULL) {
		{
			GeeIterator* _evaluate_it = NULL;
			GeeIterator* _tmp2_;
			_tmp2_ = gee_iterable_iterator ((GeeIterable*) evaluates);
			_evaluate_it = _tmp2_;
			while (TRUE) {
				GeeIterator* _tmp3_;
				FolksIndividual* evaluate = NULL;
				GeeIterator* _tmp4_;
				gpointer _tmp5_;
				FolksIndividual* _tmp6_;
				FolksIndividual* _tmp7_;
				_tmp3_ = _evaluate_it;
				if (!gee_iterator_next (_tmp3_)) {
					break;
				}
				_tmp4_ = _evaluate_it;
				_tmp5_ = gee_iterator_get (_tmp4_);
				evaluate = (FolksIndividual*) _tmp5_;
				_tmp6_ = evaluate;
				if (_tmp6_ == NULL) {
					_g_object_unref0 (evaluate);
					continue;
				}
				_tmp7_ = evaluate;
				if (_folks_search_view_check_match (self, _tmp7_)) {
					GeeSortedSet* _tmp8_;
					FolksIndividual* _tmp9_;
					_tmp8_ = view_added;
					_tmp9_ = evaluate;
					gee_collection_add ((GeeCollection*) _tmp8_, _tmp9_);
				} else {
					GeeSortedSet* _tmp10_;
					FolksIndividual* _tmp11_;
					_tmp10_ = view_removed;
					_tmp11_ = evaluate;
					gee_collection_add ((GeeCollection*) _tmp10_, _tmp11_);
				}
				_g_object_unref0 (evaluate);
			}
			_g_object_unref0 (_evaluate_it);
		}
	}
	if (changes != NULL) {
		GeeMapIterator* iter = NULL;
		GeeMapIterator* _tmp12_;
		_tmp12_ = gee_multi_map_map_iterator (changes);
		iter = _tmp12_;
		while (TRUE) {
			GeeMapIterator* _tmp13_;
			FolksIndividual* individual_old = NULL;
			GeeMapIterator* _tmp14_;
			gpointer _tmp15_;
			FolksIndividual* individual_new = NULL;
			GeeMapIterator* _tmp16_;
			gpointer _tmp17_;
			gboolean _tmp18_ = FALSE;
			FolksIndividual* _tmp19_;
			FolksIndividual* _tmp23_;
			_tmp13_ = iter;
			if (!gee_map_iterator_next (_tmp13_)) {
				break;
			}
			_tmp14_ = iter;
			_tmp15_ = gee_map_iterator_get_key (_tmp14_);
			individual_old = (FolksIndividual*) _tmp15_;
			_tmp16_ = iter;
			_tmp17_ = gee_map_iterator_get_value (_tmp16_);
			individual_new = (FolksIndividual*) _tmp17_;
			_tmp19_ = individual_new;
			if (_tmp19_ != NULL) {
				FolksIndividual* _tmp20_;
				_tmp20_ = individual_new;
				_tmp18_ = _folks_search_view_check_match (self, _tmp20_);
			} else {
				_tmp18_ = FALSE;
			}
			if (_tmp18_) {
				GeeSortedSet* _tmp21_;
				FolksIndividual* _tmp22_;
				_tmp21_ = view_added;
				_tmp22_ = individual_new;
				gee_collection_add ((GeeCollection*) _tmp21_, _tmp22_);
			}
			_tmp23_ = individual_old;
			if (_tmp23_ != NULL) {
				GeeSortedSet* _tmp24_;
				FolksIndividual* _tmp25_;
				_tmp24_ = view_removed;
				_tmp25_ = individual_old;
				gee_collection_add ((GeeCollection*) _tmp24_, _tmp25_);
			}
			_g_object_unref0 (individual_new);
			_g_object_unref0 (individual_old);
		}
		_g_object_unref0 (iter);
	}
	_tmp26_ = view_removed;
	_tmp27_ = gee_iterable_iterator ((GeeIterable*) _tmp26_);
	iter = _tmp27_;
	while (TRUE) {
		GeeIterator* _tmp28_;
		FolksIndividual* individual_old = NULL;
		GeeIterator* _tmp29_;
		gpointer _tmp30_;
		gboolean _tmp31_ = FALSE;
		FolksIndividual* _tmp32_;
		_tmp28_ = iter;
		if (!gee_iterator_next (_tmp28_)) {
			break;
		}
		_tmp29_ = iter;
		_tmp30_ = gee_iterator_get (_tmp29_);
		individual_old = (FolksIndividual*) _tmp30_;
		_tmp32_ = individual_old;
		if (_tmp32_ != NULL) {
			FolksIndividual* _tmp33_;
			_tmp33_ = individual_old;
			_tmp31_ = !_folks_search_view_remove_individual (self, _tmp33_);
		} else {
			_tmp31_ = FALSE;
		}
		if (_tmp31_) {
			GeeIterator* _tmp34_;
			_tmp34_ = iter;
			gee_iterator_remove (_tmp34_);
		}
		_g_object_unref0 (individual_old);
	}
	_tmp35_ = view_added;
	_tmp36_ = gee_iterable_iterator ((GeeIterable*) _tmp35_);
	_g_object_unref0 (iter);
	iter = _tmp36_;
	while (TRUE) {
		GeeIterator* _tmp37_;
		FolksIndividual* individual_new = NULL;
		GeeIterator* _tmp38_;
		gpointer _tmp39_;
		gboolean _tmp40_ = FALSE;
		FolksIndividual* _tmp41_;
		_tmp37_ = iter;
		if (!gee_iterator_next (_tmp37_)) {
			break;
		}
		_tmp38_ = iter;
		_tmp39_ = gee_iterator_get (_tmp38_);
		individual_new = (FolksIndividual*) _tmp39_;
		_tmp41_ = individual_new;
		if (_tmp41_ != NULL) {
			FolksIndividual* _tmp42_;
			_tmp42_ = individual_new;
			_tmp40_ = !_folks_search_view_add_individual (self, _tmp42_);
		} else {
			_tmp40_ = FALSE;
		}
		if (_tmp40_) {
			GeeIterator* _tmp43_;
			_tmp43_ = iter;
			gee_iterator_remove (_tmp43_);
		}
		_g_object_unref0 (individual_new);
	}
	_tmp45_ = view_added;
	_tmp46_ = gee_collection_get_size ((GeeCollection*) _tmp45_);
	_tmp47_ = _tmp46_;
	if (_tmp47_ > 0) {
		_tmp44_ = TRUE;
	} else {
		GeeSortedSet* _tmp48_;
		gint _tmp49_;
		gint _tmp50_;
		_tmp48_ = view_removed;
		_tmp49_ = gee_collection_get_size ((GeeCollection*) _tmp48_);
		_tmp50_ = _tmp49_;
		_tmp44_ = _tmp50_ > 0;
	}
	if (_tmp44_) {
		GeeSortedSet* _tmp51_;
		GeeSortedSet* _tmp52_;
		_tmp51_ = view_added;
		_tmp52_ = view_removed;
		g_signal_emit (self, folks_search_view_signals[FOLKS_SEARCH_VIEW_INDIVIDUALS_CHANGED_DETAILED_SIGNAL], 0, _tmp51_, _tmp52_);
	}
	_g_object_unref0 (iter);
	_g_object_unref0 (view_removed);
	_g_object_unref0 (view_added);
}

static void
__folks_search_view_individual_notify_cb_g_object_notify (GObject* _sender,
                                                          GParamSpec* pspec,
                                                          gpointer self)
{
	_folks_search_view_individual_notify_cb ((FolksSearchView*) self, _sender, pspec);
}

static inline gboolean
_folks_search_view_add_individual (FolksSearchView* self,
                                   FolksIndividual* individual)
{
	GeeSortedSet* _tmp0_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = self->priv->_individuals;
	if (gee_collection_add ((GeeCollection*) _tmp0_, individual)) {
		g_signal_connect_object ((GObject*) individual, "notify", (GCallback) __folks_search_view_individual_notify_cb_g_object_notify, self, 0);
		result = TRUE;
		return result;
	}
	result = FALSE;
	return result;
}

static inline gboolean
_folks_search_view_remove_individual (FolksSearchView* self,
                                      FolksIndividual* individual)
{
	GeeSortedSet* _tmp0_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = self->priv->_individuals;
	if (gee_collection_remove ((GeeCollection*) _tmp0_, individual)) {
		guint _tmp1_;
		g_signal_parse_name ("notify", G_TYPE_OBJECT, &_tmp1_, NULL, FALSE);
		g_signal_handlers_disconnect_matched ((GObject*) individual, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp1_, 0, NULL, (GCallback) __folks_search_view_individual_notify_cb_g_object_notify, self);
		result = TRUE;
		return result;
	}
	result = FALSE;
	return result;
}

static void
_folks_search_view_evaluate_all_aggregator_individuals (FolksSearchView* self)
{
	GeeHashSet* individuals = NULL;
	GeeHashSet* _tmp0_;
	FolksIndividualAggregator* _tmp1_;
	GeeMap* _tmp2_;
	GeeMap* _tmp3_;
	GeeCollection* _tmp4_;
	GeeCollection* _tmp5_;
	GeeCollection* _tmp6_;
	g_return_if_fail (self != NULL);
	_tmp0_ = gee_hash_set_new (FOLKS_TYPE_INDIVIDUAL, (GBoxedCopyFunc) g_object_ref, (GDestroyNotify) g_object_unref, NULL, NULL, NULL, NULL, NULL, NULL);
	individuals = _tmp0_;
	_tmp1_ = self->priv->_aggregator;
	_tmp2_ = folks_individual_aggregator_get_individuals (_tmp1_);
	_tmp3_ = _tmp2_;
	_tmp4_ = gee_map_get_values (_tmp3_);
	_tmp5_ = _tmp4_;
	_tmp6_ = _tmp5_;
	gee_collection_add_all ((GeeCollection*) individuals, _tmp6_);
	_g_object_unref0 (_tmp6_);
	_folks_search_view_evaluate_individuals (self, NULL, (GeeSet*) individuals);
	_g_object_unref0 (individuals);
}

static gboolean
_folks_search_view_check_match (FolksSearchView* self,
                                FolksIndividual* individual)
{
	guint match_score = 0U;
	FolksQuery* _tmp0_;
	gchar* key = NULL;
	gchar* _tmp1_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = self->priv->_query;
	match_score = folks_query_is_match (_tmp0_, individual);
	_tmp1_ = _folks_search_view_build_match_strength_key (self);
	key = _tmp1_;
	g_object_set_data_full ((GObject*) individual, key, (gpointer) ((guintptr) match_score), NULL);
	result = match_score != ((guint) 0);
	_g_free0 (key);
	return result;
}

static gboolean
_folks_search_view_evaluate_match (FolksSearchView* self,
                                   FolksIndividual* individual)
{
	gboolean match = FALSE;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	match = _folks_search_view_check_match (self, individual);
	if (match) {
		_folks_search_view_add_individual (self, individual);
	} else {
		_folks_search_view_remove_individual (self, individual);
	}
	result = match;
	return result;
}

static void
_folks_search_view_individual_notify_cb (FolksSearchView* self,
                                         GObject* obj,
                                         GParamSpec* ps)
{
	FolksIndividual* individual = NULL;
	FolksIndividual* _tmp0_;
	FolksIndividual* _tmp1_;
	gboolean had_individual = FALSE;
	GeeSortedSet* _tmp2_;
	FolksIndividual* _tmp3_;
	gboolean have_individual = FALSE;
	FolksIndividual* _tmp4_;
	gboolean _tmp5_ = FALSE;
	gboolean added = FALSE;
	gboolean _tmp6_ = FALSE;
	gboolean removed = FALSE;
	GeeSortedSet* view_added = NULL;
	GeeSortedSet* _tmp7_;
	GeeSortedSet* view_removed = NULL;
	GeeSortedSet* _tmp8_;
	gboolean _tmp13_ = FALSE;
	GeeSortedSet* _tmp14_;
	gint _tmp15_;
	gint _tmp16_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (obj != NULL);
	g_return_if_fail (ps != NULL);
	_tmp0_ = _g_object_ref0 (FOLKS_IS_INDIVIDUAL (obj) ? ((FolksIndividual*) obj) : NULL);
	individual = _tmp0_;
	_tmp1_ = individual;
	if (_tmp1_ == NULL) {
		_g_object_unref0 (individual);
		return;
	}
	_tmp2_ = self->priv->_individuals;
	_tmp3_ = individual;
	had_individual = gee_collection_contains ((GeeCollection*) _tmp2_, _tmp3_);
	_tmp4_ = individual;
	have_individual = _folks_search_view_evaluate_match (self, _tmp4_);
	if (!had_individual) {
		_tmp5_ = have_individual;
	} else {
		_tmp5_ = FALSE;
	}
	added = _tmp5_;
	if (had_individual) {
		_tmp6_ = !have_individual;
	} else {
		_tmp6_ = FALSE;
	}
	removed = _tmp6_;
	_tmp7_ = _folks_search_view_create_empty_sorted_set (self);
	view_added = _tmp7_;
	_tmp8_ = _folks_search_view_create_empty_sorted_set (self);
	view_removed = _tmp8_;
	if (added) {
		GeeSortedSet* _tmp9_;
		FolksIndividual* _tmp10_;
		_tmp9_ = view_added;
		_tmp10_ = individual;
		gee_collection_add ((GeeCollection*) _tmp9_, _tmp10_);
	} else {
		if (removed) {
			GeeSortedSet* _tmp11_;
			FolksIndividual* _tmp12_;
			_tmp11_ = view_removed;
			_tmp12_ = individual;
			gee_collection_add ((GeeCollection*) _tmp11_, _tmp12_);
		}
	}
	_tmp14_ = view_added;
	_tmp15_ = gee_collection_get_size ((GeeCollection*) _tmp14_);
	_tmp16_ = _tmp15_;
	if (_tmp16_ > 0) {
		_tmp13_ = TRUE;
	} else {
		GeeSortedSet* _tmp17_;
		gint _tmp18_;
		gint _tmp19_;
		_tmp17_ = view_removed;
		_tmp18_ = gee_collection_get_size ((GeeCollection*) _tmp17_);
		_tmp19_ = _tmp18_;
		_tmp13_ = _tmp19_ > 0;
	}
	if (_tmp13_) {
		GeeSortedSet* _tmp20_;
		GeeSortedSet* _tmp21_;
		_tmp20_ = view_added;
		_tmp21_ = view_removed;
		g_signal_emit (self, folks_search_view_signals[FOLKS_SEARCH_VIEW_INDIVIDUALS_CHANGED_DETAILED_SIGNAL], 0, _tmp20_, _tmp21_);
	}
	_g_object_unref0 (view_removed);
	_g_object_unref0 (view_added);
	_g_object_unref0 (individual);
}

static void
_folks_search_view_query_notify_cb (FolksSearchView* self,
                                    GObject* obj,
                                    GParamSpec* ps)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (obj != NULL);
	g_return_if_fail (ps != NULL);
	g_debug ("search-view.vala:534: %s", "SearchView's Query changed, forcing re-evaluation of all " "Individuals");
	folks_search_view_refresh (self, NULL, NULL);
}

FolksIndividualAggregator*
folks_search_view_get_aggregator (FolksSearchView* self)
{
	FolksIndividualAggregator* result;
	FolksIndividualAggregator* _tmp0_;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->priv->_aggregator;
	result = _tmp0_;
	return result;
}

FolksQuery*
folks_search_view_get_query (FolksSearchView* self)
{
	FolksQuery* result;
	FolksQuery* _tmp0_;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->priv->_query;
	result = _tmp0_;
	return result;
}

static void
__folks_search_view_query_notify_cb_g_object_notify (GObject* _sender,
                                                     GParamSpec* pspec,
                                                     gpointer self)
{
	_folks_search_view_query_notify_cb ((FolksSearchView*) self, _sender, pspec);
}

void
folks_search_view_set_query (FolksSearchView* self,
                             FolksQuery* value)
{
	FolksQuery* _tmp0_;
	FolksQuery* _tmp1_;
	FolksQuery* _tmp2_;
	guint _tmp3_;
	FolksQuery* _tmp4_;
	FolksQuery* _tmp5_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_query;
	if (_tmp0_ == value) {
		return;
	}
	_tmp1_ = self->priv->_query;
	if (_tmp1_ != NULL) {
		g_debug ("search-view.vala:84: %s", "SearchView's query replaced, forcing re-evaluation of " "all Individuals.");
	}
	_tmp2_ = self->priv->_query;
	g_signal_parse_name ("notify", G_TYPE_OBJECT, &_tmp3_, NULL, FALSE);
	g_signal_handlers_disconnect_matched ((GObject*) _tmp2_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp3_, 0, NULL, (GCallback) __folks_search_view_query_notify_cb_g_object_notify, self);
	_tmp4_ = _g_object_ref0 (value);
	_g_object_unref0 (self->priv->_query);
	self->priv->_query = _tmp4_;
	_tmp5_ = self->priv->_query;
	g_signal_connect_object ((GObject*) _tmp5_, "notify", (GCallback) __folks_search_view_query_notify_cb_g_object_notify, self, 0);
	folks_search_view_refresh (self, NULL, NULL);
	g_object_notify_by_pspec ((GObject *) self, folks_search_view_properties[FOLKS_SEARCH_VIEW_QUERY_PROPERTY]);
}

GeeSortedSet*
folks_search_view_get_individuals (FolksSearchView* self)
{
	GeeSortedSet* result;
	GeeSortedSet* _tmp0_;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->priv->_individuals_ro;
	result = _tmp0_;
	return result;
}

gboolean
folks_search_view_get_is_prepared (FolksSearchView* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_is_prepared;
	return result;
}

gboolean
folks_search_view_get_is_quiescent (FolksSearchView* self)
{
	gboolean result;
	FolksIndividualAggregator* _tmp0_;
	FolksIndividualAggregator* _tmp1_;
	gboolean _tmp2_;
	gboolean _tmp3_;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = folks_search_view_get_aggregator (self);
	_tmp1_ = _tmp0_;
	_tmp2_ = folks_individual_aggregator_get_is_quiescent (_tmp1_);
	_tmp3_ = _tmp2_;
	result = _tmp3_;
	return result;
}

static void
g_cclosure_user_marshal_VOID__OBJECT_OBJECT (GClosure * closure,
                                             GValue * return_value,
                                             guint n_param_values,
                                             const GValue * param_values,
                                             gpointer invocation_hint,
                                             gpointer marshal_data)
{
	typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2);
	register GMarshalFunc_VOID__OBJECT_OBJECT callback;
	register GCClosure * cc;
	register gpointer data1;
	register gpointer data2;
	cc = (GCClosure *) closure;
	g_return_if_fail (n_param_values == 3);
	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__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
	callback (data1, g_value_get_object (param_values + 1), g_value_get_object (param_values + 2), data2);
}

static void
folks_search_view_class_init (FolksSearchViewClass * klass,
                              gpointer klass_data)
{
	folks_search_view_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &FolksSearchView_private_offset);
	G_OBJECT_CLASS (klass)->get_property = _vala_folks_search_view_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_folks_search_view_set_property;
	G_OBJECT_CLASS (klass)->finalize = folks_search_view_finalize;
	/**
	   * The {@link IndividualAggregator} that this view is based upon.
	   *
	   * @since 0.11.0
	   */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FOLKS_SEARCH_VIEW_AGGREGATOR_PROPERTY, folks_search_view_properties[FOLKS_SEARCH_VIEW_AGGREGATOR_PROPERTY] = g_param_spec_object ("aggregator", "aggregator", "aggregator", FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	   * The {@link Query} that this view is based upon.
	   *
	   * If this {@link SearchView} has already been prepared, setting this will
	   * force a re-evaluation of all {@link Individual}s in the
	   * {@link IndividualAggregator} which can be an expensive operation.
	   *
	   * This re-evaluates the query immediately, so most clients should implement
	   * de-bouncing to ensure re-evaluation only happens when (for example) the
	   * user has stopped typing a new query.
	   *
	   * @since 0.11.0
	   */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FOLKS_SEARCH_VIEW_QUERY_PROPERTY, folks_search_view_properties[FOLKS_SEARCH_VIEW_QUERY_PROPERTY] = g_param_spec_object ("query", "query", "query", FOLKS_TYPE_QUERY, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	/**
	   * A sorted set of {@link Individual}s which match the search query.
	   *
	   * This is the canonical set of {@link Individual}s provided by this
	   * view. It is sorted by match strength, with the individual who is the best
	   * match to the search query as the {@link Gee.SortedSet.first} element of
	   * the set.
	   *
	   * Match strengths are not publicly exposed, as they are on an arbitrary
	   * scale. To compare two matching individuals for match strength, check for
	   * membership of one of them in the {@link Gee.SortedSet.head_set} of the
	   * other.
	   *
	   * For clients who only wish to have a snapshot of search results, this
	   * property is valid once {@link SearchView.prepare} is finished and this
	   * {@link SearchView} may be unreferenced and ignored afterward.
	   *
	   * @since 0.11.0
	   */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FOLKS_SEARCH_VIEW_INDIVIDUALS_PROPERTY, folks_search_view_properties[FOLKS_SEARCH_VIEW_INDIVIDUALS_PROPERTY] = g_param_spec_object ("individuals", "individuals", "individuals", GEE_TYPE_SORTED_SET, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	   * Whether {@link IndividualAggregator.prepare} has successfully completed for
	   * this view's aggregator.
	   *
	   * @since 0.11.0
	   */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FOLKS_SEARCH_VIEW_IS_PREPARED_PROPERTY, folks_search_view_properties[FOLKS_SEARCH_VIEW_IS_PREPARED_PROPERTY] = g_param_spec_boolean ("is-prepared", "is-prepared", "is-prepared", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	   * Whether the search view has reached a quiescent state. This will happen at
	   * some point after {@link IndividualAggregator.prepare} has successfully
	   * completed for its aggregator.
	   *
	   * It's guaranteed that this property's value will only ever change after
	   * {@link SearchView.is_prepared} has changed to ``true``.
	   *
	   * @since 0.11.0
	   */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FOLKS_SEARCH_VIEW_IS_QUIESCENT_PROPERTY, folks_search_view_properties[FOLKS_SEARCH_VIEW_IS_QUIESCENT_PROPERTY] = g_param_spec_boolean ("is-quiescent", "is-quiescent", "is-quiescent", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	   * Emitted when one or more {@link Individual}s are added to or removed from
	   * the view.
	   *
	   * The sets of `added` and `removed` individuals are sorted by descending
	   * match strength. Using the {@link Gee.SortedSet.lower} and
	   * {@link Gee.SortedSet.higher} APIs with {@link SearchView.individuals}, the
	   * `added` individuals can be inserted at the correct positions in a UI
	   * representation of the search view.
	   *
	   * The match strengths are on the same scale as in
	   * {@link SearchView.individuals}, so orderings between the two sorted sets
	   * are valid. See {@link SearchView.individuals} for more information about
	   * match strengths.
	   *
	   * @param added a set of {@link Individual}s added to the search view
	   * @param removed a set of {@link Individual}s removed from the search view
	   *
	   * @see IndividualAggregator.individuals_changed_detailed
	   * @since 0.11.0
	   */
	folks_search_view_signals[FOLKS_SEARCH_VIEW_INDIVIDUALS_CHANGED_DETAILED_SIGNAL] = g_signal_new ("individuals-changed-detailed", FOLKS_TYPE_SEARCH_VIEW, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, GEE_TYPE_SORTED_SET, GEE_TYPE_SORTED_SET);
}

static void
folks_search_view_instance_init (FolksSearchView * self,
                                 gpointer klass)
{
	self->priv = folks_search_view_get_instance_private (self);
	self->priv->_prepare_pending = FALSE;
	self->priv->_is_prepared = FALSE;
}

static void
folks_search_view_finalize (GObject * obj)
{
	FolksSearchView * self;
	FolksIndividualAggregator* _tmp0_;
	guint _tmp1_;
	GQuark _tmp2_;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, FOLKS_TYPE_SEARCH_VIEW, FolksSearchView);
	g_debug ("search-view.vala:208: Destroying SearchView %p", self);
	_tmp0_ = self->priv->_aggregator;
	g_signal_parse_name ("notify::is-quiescent", G_TYPE_OBJECT, &_tmp1_, &_tmp2_, TRUE);
	g_signal_handlers_disconnect_matched ((GObject*) _tmp0_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp1_, _tmp2_, NULL, (GCallback) __folks_search_view_aggregator_is_quiescent_cb_g_object_notify, self);
	_g_object_unref0 (self->priv->_aggregator);
	_g_object_unref0 (self->priv->_query);
	_g_object_unref0 (self->priv->_individuals);
	_g_object_unref0 (self->priv->_individuals_ro);
	G_OBJECT_CLASS (folks_search_view_parent_class)->finalize (obj);
}

/**
 * A view of {@link Individual}s which match a given {@link Query}.
 *
 * The search view supports ‘live’ and ‘snapshot’ search results. Live results
 * will continue to update over a long period of time as persona stores go
 * online and offline or individuals are edited so they start or stop matching
 * the {@link Query}.
 *
 * For a shell search provider, for example, snapshot results are appropriate.
 * For a search in a contacts UI, live results are more appropriate as they will
 * update over time as other edits are made in the application.
 *
 * In both cases, {@link SearchView.individuals} is guaranteed to be correct
 * after {@link SearchView.prepare} finishes.
 *
 * For live results, continue listening to the
 * {@link SearchView.individuals_changed_detailed} signal.
 *
 * @since 0.11.0
 */
static GType
folks_search_view_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (FolksSearchViewClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) folks_search_view_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (FolksSearchView), 0, (GInstanceInitFunc) folks_search_view_instance_init, NULL };
	GType folks_search_view_type_id;
	folks_search_view_type_id = g_type_register_static (G_TYPE_OBJECT, "FolksSearchView", &g_define_type_info, 0);
	FolksSearchView_private_offset = g_type_add_instance_private (folks_search_view_type_id, sizeof (FolksSearchViewPrivate));
	return folks_search_view_type_id;
}

GType
folks_search_view_get_type (void)
{
	static volatile gsize folks_search_view_type_id__once = 0;
	if (g_once_init_enter (&folks_search_view_type_id__once)) {
		GType folks_search_view_type_id;
		folks_search_view_type_id = folks_search_view_get_type_once ();
		g_once_init_leave (&folks_search_view_type_id__once, folks_search_view_type_id);
	}
	return folks_search_view_type_id__once;
}

static void
_vala_folks_search_view_get_property (GObject * object,
                                      guint property_id,
                                      GValue * value,
                                      GParamSpec * pspec)
{
	FolksSearchView * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, FOLKS_TYPE_SEARCH_VIEW, FolksSearchView);
	switch (property_id) {
		case FOLKS_SEARCH_VIEW_AGGREGATOR_PROPERTY:
		g_value_set_object (value, folks_search_view_get_aggregator (self));
		break;
		case FOLKS_SEARCH_VIEW_QUERY_PROPERTY:
		g_value_set_object (value, folks_search_view_get_query (self));
		break;
		case FOLKS_SEARCH_VIEW_INDIVIDUALS_PROPERTY:
		g_value_set_object (value, folks_search_view_get_individuals (self));
		break;
		case FOLKS_SEARCH_VIEW_IS_PREPARED_PROPERTY:
		g_value_set_boolean (value, folks_search_view_get_is_prepared (self));
		break;
		case FOLKS_SEARCH_VIEW_IS_QUIESCENT_PROPERTY:
		g_value_set_boolean (value, folks_search_view_get_is_quiescent (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_folks_search_view_set_property (GObject * object,
                                      guint property_id,
                                      const GValue * value,
                                      GParamSpec * pspec)
{
	FolksSearchView * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, FOLKS_TYPE_SEARCH_VIEW, FolksSearchView);
	switch (property_id) {
		case FOLKS_SEARCH_VIEW_QUERY_PROPERTY:
		folks_search_view_set_query (self, g_value_get_object (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static inline gpointer
_vala_memdup2 (gconstpointer mem,
               gsize byte_size)
{
	gpointer new_mem;
	if (mem && byte_size != 0) {
		new_mem = g_malloc (byte_size);
		memcpy (new_mem, mem, byte_size);
	} else {
		new_mem = NULL;
	}
	return new_mem;
}

