/* search-view.c generated by valac 0.34.0.3-63fa6, 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 <glib.h>
#include <glib-object.h>
#include <gee.h>
#include <gio/gio.h>
#include <stdlib.h>
#include <string.h>


#define FOLKS_TYPE_SEARCH_VIEW (folks_search_view_get_type ())
#define FOLKS_SEARCH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOLKS_TYPE_SEARCH_VIEW, FolksSearchView))
#define FOLKS_SEARCH_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOLKS_TYPE_SEARCH_VIEW, FolksSearchViewClass))
#define FOLKS_IS_SEARCH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOLKS_TYPE_SEARCH_VIEW))
#define FOLKS_IS_SEARCH_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOLKS_TYPE_SEARCH_VIEW))
#define FOLKS_SEARCH_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOLKS_TYPE_SEARCH_VIEW, FolksSearchViewClass))

typedef struct _FolksSearchView FolksSearchView;
typedef struct _FolksSearchViewClass FolksSearchViewClass;
typedef struct _FolksSearchViewPrivate FolksSearchViewPrivate;

#define FOLKS_TYPE_INDIVIDUAL_AGGREGATOR (folks_individual_aggregator_get_type ())
#define FOLKS_INDIVIDUAL_AGGREGATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, FolksIndividualAggregator))
#define FOLKS_INDIVIDUAL_AGGREGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, FolksIndividualAggregatorClass))
#define FOLKS_IS_INDIVIDUAL_AGGREGATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOLKS_TYPE_INDIVIDUAL_AGGREGATOR))
#define FOLKS_IS_INDIVIDUAL_AGGREGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOLKS_TYPE_INDIVIDUAL_AGGREGATOR))
#define FOLKS_INDIVIDUAL_AGGREGATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, FolksIndividualAggregatorClass))

typedef struct _FolksIndividualAggregator FolksIndividualAggregator;
typedef struct _FolksIndividualAggregatorClass FolksIndividualAggregatorClass;

#define FOLKS_TYPE_QUERY (folks_query_get_type ())
#define FOLKS_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOLKS_TYPE_QUERY, FolksQuery))
#define FOLKS_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOLKS_TYPE_QUERY, FolksQueryClass))
#define FOLKS_IS_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOLKS_TYPE_QUERY))
#define FOLKS_IS_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOLKS_TYPE_QUERY))
#define FOLKS_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOLKS_TYPE_QUERY, FolksQueryClass))

typedef struct _FolksQuery FolksQuery;
typedef struct _FolksQueryClass FolksQueryClass;

#define FOLKS_TYPE_INDIVIDUAL (folks_individual_get_type ())
#define FOLKS_INDIVIDUAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOLKS_TYPE_INDIVIDUAL, FolksIndividual))
#define FOLKS_INDIVIDUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOLKS_TYPE_INDIVIDUAL, FolksIndividualClass))
#define FOLKS_IS_INDIVIDUAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOLKS_TYPE_INDIVIDUAL))
#define FOLKS_IS_INDIVIDUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOLKS_TYPE_INDIVIDUAL))
#define FOLKS_INDIVIDUAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOLKS_TYPE_INDIVIDUAL, FolksIndividualClass))

typedef struct _FolksIndividual FolksIndividual;
typedef struct _FolksIndividualClass FolksIndividualClass;
#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))

struct _FolksSearchView {
	GObject parent_instance;
	FolksSearchViewPrivate * priv;
};

struct _FolksSearchViewClass {
	GObjectClass parent_class;
};

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_;
	GSimpleAsyncResult* _async_result;
	FolksSearchView* self;
	gboolean _tmp0_;
	gboolean _tmp1_;
	gboolean _tmp2_;
	FolksIndividualAggregator* _tmp3_;
	FolksIndividualAggregator* _tmp4_;
	GError* e;
	FolksIndividualAggregator* _tmp5_;
	guint _tmp6_;
	GError* _tmp7_;
	GError* _tmp8_;
	GError * _inner_error_;
};

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

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


static gpointer folks_search_view_parent_class = NULL;

GType folks_search_view_get_type (void) G_GNUC_CONST;
GType folks_individual_aggregator_get_type (void) G_GNUC_CONST;
GType folks_query_get_type (void) G_GNUC_CONST;
GType folks_individual_get_type (void) G_GNUC_CONST;
#define FOLKS_SEARCH_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), FOLKS_TYPE_SEARCH_VIEW, FolksSearchViewPrivate))
enum  {
	FOLKS_SEARCH_VIEW_DUMMY_PROPERTY,
	FOLKS_SEARCH_VIEW_AGGREGATOR,
	FOLKS_SEARCH_VIEW_QUERY,
	FOLKS_SEARCH_VIEW_INDIVIDUALS,
	FOLKS_SEARCH_VIEW_IS_PREPARED,
	FOLKS_SEARCH_VIEW_IS_QUIESCENT
};
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);
FolksSearchView* folks_search_view_new (FolksIndividualAggregator* aggregator, FolksQuery* query);
FolksSearchView* folks_search_view_construct (GType object_type, FolksIndividualAggregator* aggregator, FolksQuery* query);
static GeeSortedSet* _folks_search_view_create_empty_sorted_set (FolksSearchView* self);
static void folks_search_view_prepare_data_free (gpointer _data);
void folks_search_view_prepare (FolksSearchView* self, GAsyncReadyCallback _callback_, gpointer _user_data_);
void folks_search_view_prepare_finish (FolksSearchView* self, GAsyncResult* _res_, GError** error);
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);
void folks_individual_aggregator_prepare (FolksIndividualAggregator* self, GAsyncReadyCallback _callback_, gpointer _user_data_);
void folks_individual_aggregator_prepare_finish (FolksIndividualAggregator* self, GAsyncResult* _res_, GError** error);
static void folks_search_view_prepare_ready (GObject* source_object, GAsyncResult* _res_, gpointer _user_data_);
void folks_search_view_refresh (FolksSearchView* self, GAsyncReadyCallback _callback_, gpointer _user_data_);
void folks_search_view_refresh_finish (FolksSearchView* self, GAsyncResult* _res_, GError** error);
static void folks_search_view_unprepare_data_free (gpointer _data);
void folks_search_view_unprepare (FolksSearchView* self, GAsyncReadyCallback _callback_, gpointer _user_data_);
void folks_search_view_unprepare_finish (FolksSearchView* self, GAsyncResult* _res_, GError** error);
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);
const gchar* folks_individual_get_display_name (FolksIndividual* self);
const gchar* folks_individual_get_id (FolksIndividual* self);
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);
GeeMap* folks_individual_aggregator_get_individuals (FolksIndividualAggregator* self);
guint folks_query_is_match (FolksQuery* self, FolksIndividual* individual);
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);
FolksIndividualAggregator* folks_search_view_get_aggregator (FolksSearchView* self);
FolksQuery* folks_search_view_get_query (FolksSearchView* self);
void folks_search_view_set_query (FolksSearchView* self, FolksQuery* value);
static void __folks_search_view_query_notify_cb_g_object_notify (GObject* _sender, GParamSpec* pspec, gpointer self);
GeeSortedSet* folks_search_view_get_individuals (FolksSearchView* self);
gboolean folks_search_view_get_is_prepared (FolksSearchView* self);
gboolean folks_search_view_get_is_quiescent (FolksSearchView* self);
gboolean folks_individual_aggregator_get_is_quiescent (FolksIndividualAggregator* 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 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 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_ = NULL;
	FolksIndividualAggregator* _tmp1_ = NULL;
	FolksIndividualAggregator* _tmp2_ = NULL;
	GeeSortedSet* _tmp3_ = NULL;
	GeeSortedSet* _tmp4_ = NULL;
	GeeSortedSet* _tmp5_ = NULL;
	GeeSortedSet* _tmp6_ = NULL;
	FolksQuery* _tmp7_ = NULL;
	FolksQuery* _tmp8_ = NULL;
	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_ = aggregator;
	_tmp1_ = _g_object_ref0 (_tmp0_);
	_g_object_unref0 (self->priv->_aggregator);
	self->priv->_aggregator = _tmp1_;
	_tmp2_ = self->priv->_aggregator;
	g_signal_connect_object ((GObject*) _tmp2_, "notify::is-quiescent", (GCallback) __folks_search_view_aggregator_is_quiescent_cb_g_object_notify, self, 0);
	_tmp3_ = _folks_search_view_create_empty_sorted_set (self);
	_g_object_unref0 (self->priv->_individuals);
	self->priv->_individuals = _tmp3_;
	_tmp4_ = self->priv->_individuals;
	_tmp5_ = gee_sorted_set_get_read_only_view (_tmp4_);
	_tmp6_ = _tmp5_;
	_g_object_unref0 (self->priv->_individuals_ro);
	self->priv->_individuals_ro = _tmp6_;
	self->priv->_is_prepared = FALSE;
	self->priv->_prepare_pending = FALSE;
	_tmp7_ = query;
	_tmp8_ = _g_object_ref0 (_tmp7_);
	_g_object_unref0 (self->priv->_query);
	self->priv->_query = _tmp8_;
	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_ = NULL;
	_data_ = g_slice_new0 (FolksSearchViewPrepareData);
	_data_->_async_result = g_simple_async_result_new (G_OBJECT (self), _callback_, _user_data_, folks_search_view_prepare);
	g_simple_async_result_set_op_res_gpointer (_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_;
	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (_res_), error)) {
		return;
	}
	_data_ = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (_res_));
}


/**
   * 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:
	_data_->_tmp1_ = FALSE;
	_data_->_tmp1_ = _data_->self->priv->_is_prepared;
	if (!_data_->_tmp1_) {
		_data_->_tmp2_ = FALSE;
		_data_->_tmp2_ = _data_->self->priv->_prepare_pending;
		_data_->_tmp0_ = !_data_->_tmp2_;
	} else {
		_data_->_tmp0_ = FALSE;
	}
	if (_data_->_tmp0_) {
		_data_->self->priv->_prepare_pending = TRUE;
		_data_->_tmp3_ = NULL;
		_data_->_tmp3_ = _data_->self->priv->_aggregator;
		g_signal_connect_object (_data_->_tmp3_, "individuals-changed-detailed", (GCallback) __folks_search_view_aggregator_individuals_changed_detailed_cb_folks_individual_aggregator_individuals_changed_detailed, _data_->self, 0);
		{
			_data_->_tmp4_ = NULL;
			_data_->_tmp4_ = _data_->self->priv->_aggregator;
			_data_->_state_ = 1;
			folks_individual_aggregator_prepare (_data_->_tmp4_, folks_search_view_prepare_ready, _data_);
			return FALSE;
			_state_1:
			folks_individual_aggregator_prepare_finish (_data_->_tmp4_, _data_->_res_, &_data_->_inner_error_);
			if (G_UNLIKELY (_data_->_inner_error_ != NULL)) {
				goto __catch49_g_error;
			}
		}
		goto __finally49;
		__catch49_g_error:
		{
			_data_->e = _data_->_inner_error_;
			_data_->_inner_error_ = NULL;
			_data_->self->priv->_prepare_pending = FALSE;
			_data_->_tmp5_ = NULL;
			_data_->_tmp5_ = _data_->self->priv->_aggregator;
			_data_->_tmp6_ = 0U;
			g_signal_parse_name ("individuals-changed-detailed", FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, &_data_->_tmp6_, NULL, FALSE);
			g_signal_handlers_disconnect_matched (_data_->_tmp5_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _data_->_tmp6_, 0, NULL, (GCallback) __folks_search_view_aggregator_individuals_changed_detailed_cb_folks_individual_aggregator_individuals_changed_detailed, _data_->self);
			_data_->_tmp7_ = NULL;
			_data_->_tmp7_ = _data_->e;
			_data_->_tmp8_ = NULL;
			_data_->_tmp8_ = _g_error_copy0 (_data_->_tmp7_);
			_data_->_inner_error_ = _data_->_tmp8_;
			_g_error_free0 (_data_->e);
			goto __finally49;
		}
		__finally49:
		if (G_UNLIKELY (_data_->_inner_error_ != NULL)) {
			g_simple_async_result_set_from_error (_data_->_async_result, _data_->_inner_error_);
			g_error_free (_data_->_inner_error_);
			if (_data_->_state_ == 0) {
				g_simple_async_result_complete_in_idle (_data_->_async_result);
			} else {
				g_simple_async_result_complete (_data_->_async_result);
			}
			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_error_);
		if (G_UNLIKELY (_data_->_inner_error_ != NULL)) {
			g_simple_async_result_set_from_error (_data_->_async_result, _data_->_inner_error_);
			g_error_free (_data_->_inner_error_);
			if (_data_->_state_ == 0) {
				g_simple_async_result_complete_in_idle (_data_->_async_result);
			} else {
				g_simple_async_result_complete (_data_->_async_result);
			}
			g_object_unref (_data_->_async_result);
			return FALSE;
		}
	}
	if (_data_->_state_ == 0) {
		g_simple_async_result_complete_in_idle (_data_->_async_result);
	} else {
		g_simple_async_result_complete (_data_->_async_result);
	}
	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_ = NULL;
	_data_ = g_slice_new0 (FolksSearchViewUnprepareData);
	_data_->_async_result = g_simple_async_result_new (G_OBJECT (self), _callback_, _user_data_, folks_search_view_unprepare);
	g_simple_async_result_set_op_res_gpointer (_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_;
	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (_res_), error)) {
		return;
	}
	_data_ = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (_res_));
}


/**
   * 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:
	_data_->_tmp1_ = FALSE;
	_data_->_tmp1_ = _data_->self->priv->_is_prepared;
	if (!_data_->_tmp1_) {
		_data_->_tmp0_ = TRUE;
	} else {
		_data_->_tmp2_ = FALSE;
		_data_->_tmp2_ = _data_->self->priv->_prepare_pending;
		_data_->_tmp0_ = _data_->_tmp2_;
	}
	if (_data_->_tmp0_) {
		if (_data_->_state_ == 0) {
			g_simple_async_result_complete_in_idle (_data_->_async_result);
		} else {
			g_simple_async_result_complete (_data_->_async_result);
		}
		g_object_unref (_data_->_async_result);
		return FALSE;
	}
	_data_->self->priv->_prepare_pending = FALSE;
	if (_data_->_state_ == 0) {
		g_simple_async_result_complete_in_idle (_data_->_async_result);
	} else {
		g_simple_async_result_complete (_data_->_async_result);
	}
	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_ = NULL;
	_data_ = g_slice_new0 (FolksSearchViewRefreshData);
	_data_->_async_result = g_simple_async_result_new (G_OBJECT (self), _callback_, _user_data_, folks_search_view_refresh);
	g_simple_async_result_set_op_res_gpointer (_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_;
	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (_res_), error)) {
		return;
	}
	_data_ = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (_res_));
}


/**
   * 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:
	_data_->_tmp0_ = FALSE;
	_data_->_tmp0_ = _data_->self->priv->_is_prepared;
	if (_data_->_tmp0_) {
		_folks_search_view_evaluate_all_aggregator_individuals (_data_->self);
	}
	if (_data_->_state_ == 0) {
		g_simple_async_result_complete_in_idle (_data_->_async_result);
	} else {
		g_simple_async_result_complete (_data_->_async_result);
	}
	g_object_unref (_data_->_async_result);
	return FALSE;
}


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


static gchar* _folks_search_view_build_match_strength_key (FolksSearchView* self) {
	gchar* result = NULL;
	gchar* _tmp0_ = NULL;
	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) {
	gint result = 0;
	FolksIndividual* _tmp0_ = NULL;
	FolksIndividual* _tmp1_ = NULL;
	gchar* key = NULL;
	gchar* _tmp2_ = NULL;
	guint match_strength_a = 0U;
	FolksIndividual* _tmp3_ = NULL;
	const gchar* _tmp4_ = NULL;
	gconstpointer _tmp5_ = NULL;
	guint match_strength_b = 0U;
	FolksIndividual* _tmp6_ = NULL;
	const gchar* _tmp7_ = NULL;
	gconstpointer _tmp8_ = NULL;
	guint _tmp9_ = 0U;
	guint _tmp10_ = 0U;
	gint display_name = 0;
	FolksIndividual* _tmp13_ = NULL;
	const gchar* _tmp14_ = NULL;
	const gchar* _tmp15_ = NULL;
	FolksIndividual* _tmp16_ = NULL;
	const gchar* _tmp17_ = NULL;
	const gchar* _tmp18_ = NULL;
	gint _tmp19_ = 0;
	gint _tmp20_ = 0;
	FolksIndividual* _tmp21_ = NULL;
	const gchar* _tmp22_ = NULL;
	const gchar* _tmp23_ = NULL;
	FolksIndividual* _tmp24_ = NULL;
	const gchar* _tmp25_ = NULL;
	const gchar* _tmp26_ = NULL;
	gint _tmp27_ = 0;
	g_return_val_if_fail (self != NULL, 0);
	g_return_val_if_fail (a != NULL, 0);
	g_return_val_if_fail (b != NULL, 0);
	_tmp0_ = a;
	_tmp1_ = b;
	if (_tmp0_ == _tmp1_) {
		result = 0;
		return result;
	}
	_tmp2_ = _folks_search_view_build_match_strength_key (self);
	key = _tmp2_;
	_tmp3_ = a;
	_tmp4_ = key;
	_tmp5_ = g_object_get_data ((GObject*) _tmp3_, _tmp4_);
	match_strength_a = (guint) ((guintptr) _tmp5_);
	_tmp6_ = b;
	_tmp7_ = key;
	_tmp8_ = g_object_get_data ((GObject*) _tmp6_, _tmp7_);
	match_strength_b = (guint) ((guintptr) _tmp8_);
	_tmp9_ = match_strength_a;
	_tmp10_ = match_strength_b;
	if (_tmp9_ != _tmp10_) {
		guint _tmp11_ = 0U;
		guint _tmp12_ = 0U;
		_tmp11_ = match_strength_b;
		_tmp12_ = match_strength_a;
		result = ((gint) _tmp11_) - ((gint) _tmp12_);
		_g_free0 (key);
		return result;
	}
	_tmp13_ = a;
	_tmp14_ = folks_individual_get_display_name (_tmp13_);
	_tmp15_ = _tmp14_;
	_tmp16_ = b;
	_tmp17_ = folks_individual_get_display_name (_tmp16_);
	_tmp18_ = _tmp17_;
	_tmp19_ = g_utf8_collate (_tmp15_, _tmp18_);
	display_name = _tmp19_;
	_tmp20_ = display_name;
	if (_tmp20_ != 0) {
		result = display_name;
		_g_free0 (key);
		return result;
	}
	_tmp21_ = a;
	_tmp22_ = folks_individual_get_id (_tmp21_);
	_tmp23_ = _tmp22_;
	_tmp24_ = b;
	_tmp25_ = folks_individual_get_id (_tmp24_);
	_tmp26_ = _tmp25_;
	_tmp27_ = g_utf8_collate (_tmp23_, _tmp26_);
	result = _tmp27_;
	_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) {
	GeeSortedSet* result = NULL;
	GeeTreeSet* _tmp0_ = NULL;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = gee_tree_set_new (FOLKS_TYPE_INDIVIDUAL, (GBoxedCopyFunc) g_object_ref, 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_ = NULL;
	GeeSortedSet* view_removed = NULL;
	GeeSortedSet* _tmp1_ = NULL;
	GeeSet* _tmp2_ = NULL;
	GeeMultiMap* _tmp16_ = NULL;
	GeeIterator* iter = NULL;
	GeeSortedSet* _tmp34_ = NULL;
	GeeIterator* _tmp35_ = NULL;
	GeeSortedSet* _tmp45_ = NULL;
	GeeIterator* _tmp46_ = NULL;
	gboolean _tmp56_ = FALSE;
	GeeSortedSet* _tmp57_ = NULL;
	gint _tmp58_ = 0;
	gint _tmp59_ = 0;
	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_;
	_tmp2_ = evaluates;
	if (_tmp2_ != NULL) {
		{
			GeeIterator* _evaluate_it = NULL;
			GeeSet* _tmp3_ = NULL;
			GeeIterator* _tmp4_ = NULL;
			_tmp3_ = evaluates;
			_tmp4_ = gee_iterable_iterator ((GeeIterable*) _tmp3_);
			_evaluate_it = _tmp4_;
			while (TRUE) {
				GeeIterator* _tmp5_ = NULL;
				gboolean _tmp6_ = FALSE;
				FolksIndividual* evaluate = NULL;
				GeeIterator* _tmp7_ = NULL;
				gpointer _tmp8_ = NULL;
				FolksIndividual* _tmp9_ = NULL;
				FolksIndividual* _tmp10_ = NULL;
				gboolean _tmp11_ = FALSE;
				_tmp5_ = _evaluate_it;
				_tmp6_ = gee_iterator_next (_tmp5_);
				if (!_tmp6_) {
					break;
				}
				_tmp7_ = _evaluate_it;
				_tmp8_ = gee_iterator_get (_tmp7_);
				evaluate = (FolksIndividual*) _tmp8_;
				_tmp9_ = evaluate;
				if (_tmp9_ == NULL) {
					_g_object_unref0 (evaluate);
					continue;
				}
				_tmp10_ = evaluate;
				_tmp11_ = _folks_search_view_check_match (self, _tmp10_);
				if (_tmp11_) {
					GeeSortedSet* _tmp12_ = NULL;
					FolksIndividual* _tmp13_ = NULL;
					_tmp12_ = view_added;
					_tmp13_ = evaluate;
					gee_collection_add ((GeeCollection*) _tmp12_, _tmp13_);
				} else {
					GeeSortedSet* _tmp14_ = NULL;
					FolksIndividual* _tmp15_ = NULL;
					_tmp14_ = view_removed;
					_tmp15_ = evaluate;
					gee_collection_add ((GeeCollection*) _tmp14_, _tmp15_);
				}
				_g_object_unref0 (evaluate);
			}
			_g_object_unref0 (_evaluate_it);
		}
	}
	_tmp16_ = changes;
	if (_tmp16_ != NULL) {
		GeeMapIterator* iter = NULL;
		GeeMultiMap* _tmp17_ = NULL;
		GeeMapIterator* _tmp18_ = NULL;
		_tmp17_ = changes;
		_tmp18_ = gee_multi_map_map_iterator (_tmp17_);
		iter = _tmp18_;
		while (TRUE) {
			GeeMapIterator* _tmp19_ = NULL;
			gboolean _tmp20_ = FALSE;
			FolksIndividual* individual_old = NULL;
			GeeMapIterator* _tmp21_ = NULL;
			gpointer _tmp22_ = NULL;
			FolksIndividual* individual_new = NULL;
			GeeMapIterator* _tmp23_ = NULL;
			gpointer _tmp24_ = NULL;
			gboolean _tmp25_ = FALSE;
			FolksIndividual* _tmp26_ = NULL;
			FolksIndividual* _tmp31_ = NULL;
			_tmp19_ = iter;
			_tmp20_ = gee_map_iterator_next (_tmp19_);
			if (!_tmp20_) {
				break;
			}
			_tmp21_ = iter;
			_tmp22_ = gee_map_iterator_get_key (_tmp21_);
			individual_old = (FolksIndividual*) _tmp22_;
			_tmp23_ = iter;
			_tmp24_ = gee_map_iterator_get_value (_tmp23_);
			individual_new = (FolksIndividual*) _tmp24_;
			_tmp26_ = individual_new;
			if (_tmp26_ != NULL) {
				FolksIndividual* _tmp27_ = NULL;
				gboolean _tmp28_ = FALSE;
				_tmp27_ = individual_new;
				_tmp28_ = _folks_search_view_check_match (self, _tmp27_);
				_tmp25_ = _tmp28_;
			} else {
				_tmp25_ = FALSE;
			}
			if (_tmp25_) {
				GeeSortedSet* _tmp29_ = NULL;
				FolksIndividual* _tmp30_ = NULL;
				_tmp29_ = view_added;
				_tmp30_ = individual_new;
				gee_collection_add ((GeeCollection*) _tmp29_, _tmp30_);
			}
			_tmp31_ = individual_old;
			if (_tmp31_ != NULL) {
				GeeSortedSet* _tmp32_ = NULL;
				FolksIndividual* _tmp33_ = NULL;
				_tmp32_ = view_removed;
				_tmp33_ = individual_old;
				gee_collection_add ((GeeCollection*) _tmp32_, _tmp33_);
			}
			_g_object_unref0 (individual_new);
			_g_object_unref0 (individual_old);
		}
		_g_object_unref0 (iter);
	}
	_tmp34_ = view_removed;
	_tmp35_ = gee_iterable_iterator ((GeeIterable*) _tmp34_);
	iter = _tmp35_;
	while (TRUE) {
		GeeIterator* _tmp36_ = NULL;
		gboolean _tmp37_ = FALSE;
		FolksIndividual* individual_old = NULL;
		GeeIterator* _tmp38_ = NULL;
		gpointer _tmp39_ = NULL;
		gboolean _tmp40_ = FALSE;
		FolksIndividual* _tmp41_ = NULL;
		_tmp36_ = iter;
		_tmp37_ = gee_iterator_next (_tmp36_);
		if (!_tmp37_) {
			break;
		}
		_tmp38_ = iter;
		_tmp39_ = gee_iterator_get (_tmp38_);
		individual_old = (FolksIndividual*) _tmp39_;
		_tmp41_ = individual_old;
		if (_tmp41_ != NULL) {
			FolksIndividual* _tmp42_ = NULL;
			gboolean _tmp43_ = FALSE;
			_tmp42_ = individual_old;
			_tmp43_ = _folks_search_view_remove_individual (self, _tmp42_);
			_tmp40_ = !_tmp43_;
		} else {
			_tmp40_ = FALSE;
		}
		if (_tmp40_) {
			GeeIterator* _tmp44_ = NULL;
			_tmp44_ = iter;
			gee_iterator_remove (_tmp44_);
		}
		_g_object_unref0 (individual_old);
	}
	_tmp45_ = view_added;
	_tmp46_ = gee_iterable_iterator ((GeeIterable*) _tmp45_);
	_g_object_unref0 (iter);
	iter = _tmp46_;
	while (TRUE) {
		GeeIterator* _tmp47_ = NULL;
		gboolean _tmp48_ = FALSE;
		FolksIndividual* individual_new = NULL;
		GeeIterator* _tmp49_ = NULL;
		gpointer _tmp50_ = NULL;
		gboolean _tmp51_ = FALSE;
		FolksIndividual* _tmp52_ = NULL;
		_tmp47_ = iter;
		_tmp48_ = gee_iterator_next (_tmp47_);
		if (!_tmp48_) {
			break;
		}
		_tmp49_ = iter;
		_tmp50_ = gee_iterator_get (_tmp49_);
		individual_new = (FolksIndividual*) _tmp50_;
		_tmp52_ = individual_new;
		if (_tmp52_ != NULL) {
			FolksIndividual* _tmp53_ = NULL;
			gboolean _tmp54_ = FALSE;
			_tmp53_ = individual_new;
			_tmp54_ = _folks_search_view_add_individual (self, _tmp53_);
			_tmp51_ = !_tmp54_;
		} else {
			_tmp51_ = FALSE;
		}
		if (_tmp51_) {
			GeeIterator* _tmp55_ = NULL;
			_tmp55_ = iter;
			gee_iterator_remove (_tmp55_);
		}
		_g_object_unref0 (individual_new);
	}
	_tmp57_ = view_added;
	_tmp58_ = gee_collection_get_size ((GeeCollection*) _tmp57_);
	_tmp59_ = _tmp58_;
	if (_tmp59_ > 0) {
		_tmp56_ = TRUE;
	} else {
		GeeSortedSet* _tmp60_ = NULL;
		gint _tmp61_ = 0;
		gint _tmp62_ = 0;
		_tmp60_ = view_removed;
		_tmp61_ = gee_collection_get_size ((GeeCollection*) _tmp60_);
		_tmp62_ = _tmp61_;
		_tmp56_ = _tmp62_ > 0;
	}
	if (_tmp56_) {
		GeeSortedSet* _tmp63_ = NULL;
		GeeSortedSet* _tmp64_ = NULL;
		_tmp63_ = view_added;
		_tmp64_ = view_removed;
		g_signal_emit_by_name (self, "individuals-changed-detailed", _tmp63_, _tmp64_);
	}
	_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) {
	gboolean result = FALSE;
	GeeSortedSet* _tmp0_ = NULL;
	FolksIndividual* _tmp1_ = NULL;
	gboolean _tmp2_ = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = self->priv->_individuals;
	_tmp1_ = individual;
	_tmp2_ = gee_collection_add ((GeeCollection*) _tmp0_, _tmp1_);
	if (_tmp2_) {
		FolksIndividual* _tmp3_ = NULL;
		_tmp3_ = individual;
		g_signal_connect_object ((GObject*) _tmp3_, "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) {
	gboolean result = FALSE;
	GeeSortedSet* _tmp0_ = NULL;
	FolksIndividual* _tmp1_ = NULL;
	gboolean _tmp2_ = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = self->priv->_individuals;
	_tmp1_ = individual;
	_tmp2_ = gee_collection_remove ((GeeCollection*) _tmp0_, _tmp1_);
	if (_tmp2_) {
		FolksIndividual* _tmp3_ = NULL;
		guint _tmp4_ = 0U;
		_tmp3_ = individual;
		g_signal_parse_name ("notify", G_TYPE_OBJECT, &_tmp4_, NULL, FALSE);
		g_signal_handlers_disconnect_matched ((GObject*) _tmp3_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp4_, 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_ = NULL;
	FolksIndividualAggregator* _tmp1_ = NULL;
	GeeMap* _tmp2_ = NULL;
	GeeMap* _tmp3_ = NULL;
	GeeCollection* _tmp4_ = NULL;
	GeeCollection* _tmp5_ = NULL;
	GeeCollection* _tmp6_ = NULL;
	g_return_if_fail (self != NULL);
	_tmp0_ = gee_hash_set_new (FOLKS_TYPE_INDIVIDUAL, (GBoxedCopyFunc) g_object_ref, 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) {
	gboolean result = FALSE;
	guint match_score = 0U;
	FolksQuery* _tmp0_ = NULL;
	FolksIndividual* _tmp1_ = NULL;
	guint _tmp2_ = 0U;
	gchar* key = NULL;
	gchar* _tmp3_ = NULL;
	FolksIndividual* _tmp4_ = NULL;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = self->priv->_query;
	_tmp1_ = individual;
	_tmp2_ = folks_query_is_match (_tmp0_, _tmp1_);
	match_score = _tmp2_;
	_tmp3_ = _folks_search_view_build_match_strength_key (self);
	key = _tmp3_;
	_tmp4_ = individual;
	g_object_set_data_full ((GObject*) _tmp4_, 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 result = FALSE;
	gboolean match = FALSE;
	FolksIndividual* _tmp0_ = NULL;
	gboolean _tmp1_ = FALSE;
	gboolean _tmp2_ = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (individual != NULL, FALSE);
	_tmp0_ = individual;
	_tmp1_ = _folks_search_view_check_match (self, _tmp0_);
	match = _tmp1_;
	_tmp2_ = match;
	if (_tmp2_) {
		FolksIndividual* _tmp3_ = NULL;
		_tmp3_ = individual;
		_folks_search_view_add_individual (self, _tmp3_);
	} else {
		FolksIndividual* _tmp4_ = NULL;
		_tmp4_ = individual;
		_folks_search_view_remove_individual (self, _tmp4_);
	}
	result = match;
	return result;
}


static void _folks_search_view_individual_notify_cb (FolksSearchView* self, GObject* obj, GParamSpec* ps) {
	FolksIndividual* individual = NULL;
	GObject* _tmp0_ = NULL;
	FolksIndividual* _tmp1_ = NULL;
	FolksIndividual* _tmp2_ = NULL;
	gboolean had_individual = FALSE;
	GeeSortedSet* _tmp3_ = NULL;
	FolksIndividual* _tmp4_ = NULL;
	gboolean _tmp5_ = FALSE;
	gboolean have_individual = FALSE;
	FolksIndividual* _tmp6_ = NULL;
	gboolean _tmp7_ = FALSE;
	gboolean _tmp8_ = FALSE;
	gboolean _tmp9_ = FALSE;
	gboolean added = FALSE;
	gboolean _tmp11_ = FALSE;
	gboolean _tmp12_ = FALSE;
	gboolean removed = FALSE;
	GeeSortedSet* view_added = NULL;
	GeeSortedSet* _tmp14_ = NULL;
	GeeSortedSet* view_removed = NULL;
	GeeSortedSet* _tmp15_ = NULL;
	gboolean _tmp16_ = FALSE;
	gboolean _tmp22_ = FALSE;
	GeeSortedSet* _tmp23_ = NULL;
	gint _tmp24_ = 0;
	gint _tmp25_ = 0;
	g_return_if_fail (self != NULL);
	g_return_if_fail (obj != NULL);
	g_return_if_fail (ps != NULL);
	_tmp0_ = obj;
	_tmp1_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_TYPE (_tmp0_, FOLKS_TYPE_INDIVIDUAL) ? ((FolksIndividual*) _tmp0_) : NULL);
	individual = _tmp1_;
	_tmp2_ = individual;
	if (_tmp2_ == NULL) {
		_g_object_unref0 (individual);
		return;
	}
	_tmp3_ = self->priv->_individuals;
	_tmp4_ = individual;
	_tmp5_ = gee_collection_contains ((GeeCollection*) _tmp3_, _tmp4_);
	had_individual = _tmp5_;
	_tmp6_ = individual;
	_tmp7_ = _folks_search_view_evaluate_match (self, _tmp6_);
	have_individual = _tmp7_;
	_tmp9_ = had_individual;
	if (!_tmp9_) {
		gboolean _tmp10_ = FALSE;
		_tmp10_ = have_individual;
		_tmp8_ = _tmp10_;
	} else {
		_tmp8_ = FALSE;
	}
	added = _tmp8_;
	_tmp12_ = had_individual;
	if (_tmp12_) {
		gboolean _tmp13_ = FALSE;
		_tmp13_ = have_individual;
		_tmp11_ = !_tmp13_;
	} else {
		_tmp11_ = FALSE;
	}
	removed = _tmp11_;
	_tmp14_ = _folks_search_view_create_empty_sorted_set (self);
	view_added = _tmp14_;
	_tmp15_ = _folks_search_view_create_empty_sorted_set (self);
	view_removed = _tmp15_;
	_tmp16_ = added;
	if (_tmp16_) {
		GeeSortedSet* _tmp17_ = NULL;
		FolksIndividual* _tmp18_ = NULL;
		_tmp17_ = view_added;
		_tmp18_ = individual;
		gee_collection_add ((GeeCollection*) _tmp17_, _tmp18_);
	} else {
		gboolean _tmp19_ = FALSE;
		_tmp19_ = removed;
		if (_tmp19_) {
			GeeSortedSet* _tmp20_ = NULL;
			FolksIndividual* _tmp21_ = NULL;
			_tmp20_ = view_removed;
			_tmp21_ = individual;
			gee_collection_add ((GeeCollection*) _tmp20_, _tmp21_);
		}
	}
	_tmp23_ = view_added;
	_tmp24_ = gee_collection_get_size ((GeeCollection*) _tmp23_);
	_tmp25_ = _tmp24_;
	if (_tmp25_ > 0) {
		_tmp22_ = TRUE;
	} else {
		GeeSortedSet* _tmp26_ = NULL;
		gint _tmp27_ = 0;
		gint _tmp28_ = 0;
		_tmp26_ = view_removed;
		_tmp27_ = gee_collection_get_size ((GeeCollection*) _tmp26_);
		_tmp28_ = _tmp27_;
		_tmp22_ = _tmp28_ > 0;
	}
	if (_tmp22_) {
		GeeSortedSet* _tmp29_ = NULL;
		GeeSortedSet* _tmp30_ = NULL;
		_tmp29_ = view_added;
		_tmp30_ = view_removed;
		g_signal_emit_by_name (self, "individuals-changed-detailed", _tmp29_, _tmp30_);
	}
	_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_ = NULL;
	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_ = NULL;
	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_ = NULL;
	FolksQuery* _tmp1_ = NULL;
	FolksQuery* _tmp2_ = NULL;
	FolksQuery* _tmp3_ = NULL;
	guint _tmp4_ = 0U;
	FolksQuery* _tmp5_ = NULL;
	FolksQuery* _tmp6_ = NULL;
	FolksQuery* _tmp7_ = NULL;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_query;
	_tmp1_ = value;
	if (_tmp0_ == _tmp1_) {
		return;
	}
	_tmp2_ = self->priv->_query;
	if (_tmp2_ != NULL) {
		g_debug ("search-view.vala:84: %s", "SearchView's query replaced, forcing re-evaluation of " "all Individuals.");
	}
	_tmp3_ = self->priv->_query;
	g_signal_parse_name ("notify", G_TYPE_OBJECT, &_tmp4_, NULL, FALSE);
	g_signal_handlers_disconnect_matched ((GObject*) _tmp3_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp4_, 0, NULL, (GCallback) __folks_search_view_query_notify_cb_g_object_notify, self);
	_tmp5_ = value;
	_tmp6_ = _g_object_ref0 (_tmp5_);
	_g_object_unref0 (self->priv->_query);
	self->priv->_query = _tmp6_;
	_tmp7_ = self->priv->_query;
	g_signal_connect_object ((GObject*) _tmp7_, "notify", (GCallback) __folks_search_view_query_notify_cb_g_object_notify, self, 0);
	folks_search_view_refresh (self, NULL, NULL);
	g_object_notify ((GObject *) self, "query");
}


GeeSortedSet* folks_search_view_get_individuals (FolksSearchView* self) {
	GeeSortedSet* result;
	GeeSortedSet* _tmp0_ = NULL;
	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;
	gboolean _tmp0_ = FALSE;
	g_return_val_if_fail (self != NULL, FALSE);
	_tmp0_ = self->priv->_is_prepared;
	result = _tmp0_;
	return result;
}


gboolean folks_search_view_get_is_quiescent (FolksSearchView* self) {
	gboolean result;
	FolksIndividualAggregator* _tmp0_ = NULL;
	FolksIndividualAggregator* _tmp1_ = NULL;
	gboolean _tmp2_ = FALSE;
	gboolean _tmp3_ = FALSE;
	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) {
	folks_search_view_parent_class = g_type_class_peek_parent (klass);
	g_type_class_add_private (klass, sizeof (FolksSearchViewPrivate));
	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, g_param_spec_object ("aggregator", "aggregator", "aggregator", FOLKS_TYPE_INDIVIDUAL_AGGREGATOR, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | 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, g_param_spec_object ("query", "query", "query", FOLKS_TYPE_QUERY, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | 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, g_param_spec_object ("individuals", "individuals", "individuals", GEE_TYPE_SORTED_SET, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | 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, g_param_spec_boolean ("is-prepared", "is-prepared", "is-prepared", FALSE, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | 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, g_param_spec_boolean ("is-quiescent", "is-quiescent", "is-quiescent", FALSE, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | 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
	   */
	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) {
	self->priv = FOLKS_SEARCH_VIEW_GET_PRIVATE (self);
	self->priv->_prepare_pending = FALSE;
	self->priv->_is_prepared = FALSE;
}


static void folks_search_view_finalize (GObject* obj) {
	FolksSearchView * self;
	FolksIndividualAggregator* _tmp0_ = NULL;
	guint _tmp1_ = 0U;
	GQuark _tmp2_ = 0U;
	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
 */
GType folks_search_view_get_type (void) {
	static volatile gsize folks_search_view_type_id__volatile = 0;
	if (g_once_init_enter (&folks_search_view_type_id__volatile)) {
		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);
		g_once_init_leave (&folks_search_view_type_id__volatile, folks_search_view_type_id);
	}
	return folks_search_view_type_id__volatile;
}


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:
		g_value_set_object (value, folks_search_view_get_aggregator (self));
		break;
		case FOLKS_SEARCH_VIEW_QUERY:
		g_value_set_object (value, folks_search_view_get_query (self));
		break;
		case FOLKS_SEARCH_VIEW_INDIVIDUALS:
		g_value_set_object (value, folks_search_view_get_individuals (self));
		break;
		case FOLKS_SEARCH_VIEW_IS_PREPARED:
		g_value_set_boolean (value, folks_search_view_get_is_prepared (self));
		break;
		case FOLKS_SEARCH_VIEW_IS_QUIESCENT:
		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:
		folks_search_view_set_query (self, g_value_get_object (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}



