/* nonblocking-batch.c generated by valac 0.56.3, the Vala compiler
 * generated from nonblocking-batch.vala, do not modify */

/* Copyright 2016 Software Freedom Conservancy Inc.
 *
 * This software is licensed under the GNU Lesser General Public License
 * (version 2.1 or later).  See the COPYING file in this distribution.
 */

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

#define GEARY_NONBLOCKING_BATCH_START_ID 1

enum  {
	GEARY_NONBLOCKING_BATCH_OPERATION_0_PROPERTY,
	GEARY_NONBLOCKING_BATCH_OPERATION_NUM_PROPERTIES
};
static GParamSpec* geary_nonblocking_batch_operation_properties[GEARY_NONBLOCKING_BATCH_OPERATION_NUM_PROPERTIES];

#define GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT (geary_nonblocking_batch_batch_context_get_type ())
#define GEARY_NONBLOCKING_BATCH_BATCH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT, GearyNonblockingBatchBatchContext))
#define GEARY_NONBLOCKING_BATCH_BATCH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT, GearyNonblockingBatchBatchContextClass))
#define GEARY_NONBLOCKING_BATCH_IS_BATCH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT))
#define GEARY_NONBLOCKING_BATCH_IS_BATCH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT))
#define GEARY_NONBLOCKING_BATCH_BATCH_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT, GearyNonblockingBatchBatchContextClass))

typedef struct _GearyNonblockingBatchBatchContext GearyNonblockingBatchBatchContext;
typedef struct _GearyNonblockingBatchBatchContextClass GearyNonblockingBatchBatchContextClass;
enum  {
	GEARY_NONBLOCKING_BATCH_0_PROPERTY,
	GEARY_NONBLOCKING_BATCH_SIZE_PROPERTY,
	GEARY_NONBLOCKING_BATCH_FIRST_EXCEPTION_PROPERTY,
	GEARY_NONBLOCKING_BATCH_NUM_PROPERTIES
};
static GParamSpec* geary_nonblocking_batch_properties[GEARY_NONBLOCKING_BATCH_NUM_PROPERTIES];
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
typedef struct _GearyNonblockingBatchExecuteAllAsyncData GearyNonblockingBatchExecuteAllAsyncData;
typedef struct _GearyNonblockingBatchBatchContextPrivate GearyNonblockingBatchBatchContextPrivate;
enum  {
	GEARY_NONBLOCKING_BATCH_BATCH_CONTEXT_0_PROPERTY,
	GEARY_NONBLOCKING_BATCH_BATCH_CONTEXT_NUM_PROPERTIES
};
static GParamSpec* geary_nonblocking_batch_batch_context_properties[GEARY_NONBLOCKING_BATCH_BATCH_CONTEXT_NUM_PROPERTIES];
enum  {
	GEARY_NONBLOCKING_BATCH_ADDED_SIGNAL,
	GEARY_NONBLOCKING_BATCH_STARTED_SIGNAL,
	GEARY_NONBLOCKING_BATCH_OPERATION_COMPLETED_SIGNAL,
	GEARY_NONBLOCKING_BATCH_COMPLETED_SIGNAL,
	GEARY_NONBLOCKING_BATCH_NUM_SIGNALS
};
static guint geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_NUM_SIGNALS] = {0};
#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);

struct _GearyNonblockingBatchPrivate {
	GError* _first_exception;
	GeeHashMap* contexts;
	GearyNonblockingSemaphore* sem;
	gint next_result_id;
	gboolean locked;
	gint completed_ops;
};

struct _GearyNonblockingBatchExecuteAllAsyncData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	GearyNonblockingBatch* self;
	GCancellable* cancellable;
	GError* _tmp0_;
	GeeHashMap* _tmp1_;
	gint _tmp2_;
	gint _tmp3_;
	gboolean _tmp4_;
	GError* _tmp5_;
	GeeHashMap* _tmp6_;
	gint _tmp7_;
	gint _tmp8_;
	gint count;
	gint id;
	gboolean _tmp9_;
	gint _tmp10_;
	GearyNonblockingBatchBatchContext* context;
	GeeHashMap* _tmp11_;
	gpointer _tmp12_;
	GearyNonblockingBatchBatchContext* _tmp13_;
	GearyNonblockingBatchBatchContext* _tmp14_;
	gint _tmp15_;
	GeeHashMap* _tmp16_;
	gint _tmp17_;
	gint _tmp18_;
	GearyNonblockingSemaphore* _tmp19_;
	GError* _inner_error0_;
};

struct _GearyNonblockingBatchBatchContext {
	GearyBaseObject parent_instance;
	gint id;
	GearyNonblockingBatchOperation* op;
	GearyNonblockingBatch* owner;
	gboolean completed;
	GObject* returned;
	GError* threw;
	GearyNonblockingBatchBatchContextPrivate * priv;
};

struct _GearyNonblockingBatchBatchContextClass {
	GearyBaseObjectClass parent_class;
};

static gpointer geary_nonblocking_batch_operation_parent_class = NULL;
static gint GearyNonblockingBatch_private_offset;
static gpointer geary_nonblocking_batch_parent_class = NULL;
static gpointer geary_nonblocking_batch_batch_context_parent_class = NULL;

static GType geary_nonblocking_batch_operation_get_type_once (void);
static GType geary_nonblocking_batch_batch_context_get_type (void) G_GNUC_CONST  G_GNUC_UNUSED ;
static void geary_nonblocking_batch_set_first_exception (GearyNonblockingBatch* self,
                                                  GError* value);
static void g_cclosure_user_marshal_VOID__OBJECT_INT (GClosure * closure,
                                               GValue * return_value,
                                               guint n_param_values,
                                               const GValue * param_values,
                                               gpointer invocation_hint,
                                               gpointer marshal_data);
static void g_cclosure_user_marshal_VOID__OBJECT_OBJECT_POINTER (GClosure * closure,
                                                          GValue * return_value,
                                                          guint n_param_values,
                                                          const GValue * param_values,
                                                          gpointer invocation_hint,
                                                          gpointer marshal_data);
static void g_cclosure_user_marshal_VOID__INT_POINTER (GClosure * closure,
                                                GValue * return_value,
                                                guint n_param_values,
                                                const GValue * param_values,
                                                gpointer invocation_hint,
                                                gpointer marshal_data);
static GearyNonblockingBatchBatchContext* geary_nonblocking_batch_batch_context_new (gint id,
                                                                              GearyNonblockingBatchOperation* op);
static GearyNonblockingBatchBatchContext* geary_nonblocking_batch_batch_context_construct (GType object_type,
                                                                                    gint id,
                                                                                    GearyNonblockingBatchOperation* op);
static void geary_nonblocking_batch_execute_all_async_data_free (gpointer _data);
static gboolean geary_nonblocking_batch_execute_all_async_co (GearyNonblockingBatchExecuteAllAsyncData* _data_);
static void geary_nonblocking_batch_batch_context_schedule (GearyNonblockingBatchBatchContext* self,
                                                     GearyNonblockingBatch* owner,
                                                     GCancellable* cancellable);
static void geary_nonblocking_batch_execute_all_async_ready (GObject* source_object,
                                                      GAsyncResult* _res_,
                                                      gpointer _user_data_);
static void geary_nonblocking_batch_on_context_completed (GearyNonblockingBatch* self,
                                                   GearyNonblockingBatchBatchContext* context);
static void geary_nonblocking_batch_batch_context_on_op_completed (GearyNonblockingBatchBatchContext* self,
                                                            GObject* source,
                                                            GAsyncResult* _result_);
static void _geary_nonblocking_batch_batch_context_on_op_completed_gasync_ready_callback (GObject* source_object,
                                                                                   GAsyncResult* res,
                                                                                   gpointer self);
static void geary_nonblocking_batch_batch_context_finalize (GObject * obj);
static GType geary_nonblocking_batch_batch_context_get_type_once (void);
static void geary_nonblocking_batch_finalize (GObject * obj);
static GType geary_nonblocking_batch_get_type_once (void);
static void _vala_geary_nonblocking_batch_get_property (GObject * object,
                                                 guint property_id,
                                                 GValue * value,
                                                 GParamSpec * pspec);
static void _vala_geary_nonblocking_batch_set_property (GObject * object,
                                                 guint property_id,
                                                 const GValue * value,
                                                 GParamSpec * pspec);

void
geary_nonblocking_batch_operation_execute_async (GearyNonblockingBatchOperation* self,
                                                 GCancellable* cancellable,
                                                 GAsyncReadyCallback _callback_,
                                                 gpointer _user_data_)
{
	GearyNonblockingBatchOperationClass* _klass_;
	_klass_ = GEARY_NONBLOCKING_BATCH_OPERATION_GET_CLASS (self);
	if (_klass_->execute_async) {
		_klass_->execute_async (self, cancellable, _callback_, _user_data_);
	}
}

GObject*
geary_nonblocking_batch_operation_execute_finish (GearyNonblockingBatchOperation* self,
                                                  GAsyncResult* _res_,
                                                  GError** error)
{
	GearyNonblockingBatchOperationClass* _klass_;
	_klass_ = GEARY_NONBLOCKING_BATCH_OPERATION_GET_CLASS (self);
	if (_klass_->execute_finish) {
		return _klass_->execute_finish (self, _res_, error);
	}
	return NULL;
}

GearyNonblockingBatchOperation*
geary_nonblocking_batch_operation_construct (GType object_type)
{
	GearyNonblockingBatchOperation * self = NULL;
	self = (GearyNonblockingBatchOperation*) geary_base_object_construct (object_type);
	return self;
}

static void
geary_nonblocking_batch_operation_class_init (GearyNonblockingBatchOperationClass * klass,
                                              gpointer klass_data)
{
	geary_nonblocking_batch_operation_parent_class = g_type_class_peek_parent (klass);
}

static void
geary_nonblocking_batch_operation_instance_init (GearyNonblockingBatchOperation * self,
                                                 gpointer klass)
{
}

/**
 * An abstract base class representing a single task of asynchronous work.
 */
 G_GNUC_NO_INLINE static GType
geary_nonblocking_batch_operation_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyNonblockingBatchOperationClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_nonblocking_batch_operation_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyNonblockingBatchOperation), 0, (GInstanceInitFunc) geary_nonblocking_batch_operation_instance_init, NULL };
	GType geary_nonblocking_batch_operation_type_id;
	geary_nonblocking_batch_operation_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearyNonblockingBatchOperation", &g_define_type_info, G_TYPE_FLAG_ABSTRACT);
	return geary_nonblocking_batch_operation_type_id;
}

GType
geary_nonblocking_batch_operation_get_type (void)
{
	static gsize geary_nonblocking_batch_operation_type_id__once = 0;
	if (g_once_init_enter (&geary_nonblocking_batch_operation_type_id__once)) {
		GType geary_nonblocking_batch_operation_type_id;
		geary_nonblocking_batch_operation_type_id = geary_nonblocking_batch_operation_get_type_once ();
		g_once_init_leave (&geary_nonblocking_batch_operation_type_id__once, geary_nonblocking_batch_operation_type_id);
	}
	return geary_nonblocking_batch_operation_type_id__once;
}

static inline gpointer
geary_nonblocking_batch_get_instance_private (GearyNonblockingBatch* self)
{
	return G_STRUCT_MEMBER_P (self, GearyNonblockingBatch_private_offset);
}

gint
geary_nonblocking_batch_get_size (GearyNonblockingBatch* self)
{
	gint result;
	GeeHashMap* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), 0);
	_tmp0_ = self->priv->contexts;
	_tmp1_ = gee_abstract_map_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_tmp2_ = _tmp1_;
	result = _tmp2_;
	return result;
}

GError*
geary_nonblocking_batch_get_first_exception (GearyNonblockingBatch* self)
{
	GError* result;
	GError* _tmp0_;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), NULL);
	_tmp0_ = self->priv->_first_exception;
	result = _tmp0_;
	return result;
}

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

static void
geary_nonblocking_batch_set_first_exception (GearyNonblockingBatch* self,
                                             GError* value)
{
	GError* old_value;
	g_return_if_fail (GEARY_NONBLOCKING_IS_BATCH (self));
	old_value = geary_nonblocking_batch_get_first_exception (self);
	if (old_value != value) {
		GError* _tmp0_;
		_tmp0_ = _g_error_copy0 (value);
		_g_error_free0 (self->priv->_first_exception);
		self->priv->_first_exception = _tmp0_;
		g_object_notify_by_pspec ((GObject *) self, geary_nonblocking_batch_properties[GEARY_NONBLOCKING_BATCH_FIRST_EXCEPTION_PROPERTY]);
	}
}

static void
g_cclosure_user_marshal_VOID__OBJECT_INT (GClosure * closure,
                                          GValue * return_value,
                                          guint n_param_values,
                                          const GValue * param_values,
                                          gpointer invocation_hint,
                                          gpointer marshal_data)
{
	typedef void (*GMarshalFunc_VOID__OBJECT_INT) (gpointer data1, gpointer arg_1, gint arg_2, gpointer data2);
	register GMarshalFunc_VOID__OBJECT_INT 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_INT) (marshal_data ? marshal_data : cc->callback);
	callback (data1, g_value_get_object (param_values + 1), g_value_get_int (param_values + 2), data2);
}

static void
g_cclosure_user_marshal_VOID__OBJECT_OBJECT_POINTER (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_POINTER) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer arg_3, gpointer data2);
	register GMarshalFunc_VOID__OBJECT_OBJECT_POINTER callback;
	register GCClosure * cc;
	register gpointer data1;
	register gpointer data2;
	cc = (GCClosure *) closure;
	g_return_if_fail (n_param_values == 4);
	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_POINTER) (marshal_data ? marshal_data : cc->callback);
	callback (data1, g_value_get_object (param_values + 1), g_value_get_object (param_values + 2), g_value_get_pointer (param_values + 3), data2);
}

static void
g_cclosure_user_marshal_VOID__INT_POINTER (GClosure * closure,
                                           GValue * return_value,
                                           guint n_param_values,
                                           const GValue * param_values,
                                           gpointer invocation_hint,
                                           gpointer marshal_data)
{
	typedef void (*GMarshalFunc_VOID__INT_POINTER) (gpointer data1, gint arg_1, gpointer arg_2, gpointer data2);
	register GMarshalFunc_VOID__INT_POINTER 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__INT_POINTER) (marshal_data ? marshal_data : cc->callback);
	callback (data1, g_value_get_int (param_values + 1), g_value_get_pointer (param_values + 2), data2);
}

GearyNonblockingBatch*
geary_nonblocking_batch_construct (GType object_type)
{
	GearyNonblockingBatch * self = NULL;
	self = (GearyNonblockingBatch*) geary_base_object_construct (object_type);
	return self;
}

GearyNonblockingBatch*
geary_nonblocking_batch_new (void)
{
	return geary_nonblocking_batch_construct (GEARY_NONBLOCKING_TYPE_BATCH);
}

/**
     * Adds a {@link BatchOperation} for later execution.
     *
     * {@link INVALID_ID} is returned if the batch is executing or has already executed.  Otherwise,
     * returns an ID that can be used to fetch results of this particular BatchOperation after
     * {@link execute_all_async} completes.
     *
     * The returned ID is only good for this {@link Batch}.  Since each instance uses the
     * same algorithm, different instances will likely return the same ID, so they must be
     * associated with the Batch they originated from.
     */
gint
geary_nonblocking_batch_add (GearyNonblockingBatch* self,
                             GearyNonblockingBatchOperation* op)
{
	gint id = 0;
	gint _tmp0_;
	GeeHashMap* _tmp1_;
	GearyNonblockingBatchBatchContext* _tmp2_;
	GearyNonblockingBatchBatchContext* _tmp3_;
	gint result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), 0);
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH_OPERATION (op), 0);
	if (self->priv->locked) {
		g_warning ("nonblocking-batch.vala:153: NonblockingBatch already executed or execu" \
"ting");
		result = GEARY_NONBLOCKING_BATCH_INVALID_ID;
		return result;
	}
	_tmp0_ = self->priv->next_result_id;
	self->priv->next_result_id = _tmp0_ + 1;
	id = _tmp0_;
	_tmp1_ = self->priv->contexts;
	_tmp2_ = geary_nonblocking_batch_batch_context_new (id, op);
	_tmp3_ = _tmp2_;
	gee_abstract_map_set (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap), (gpointer) ((gintptr) id), _tmp3_);
	_g_object_unref0 (_tmp3_);
	g_signal_emit (self, geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_ADDED_SIGNAL], 0, op, id);
	result = id;
	return result;
}

static void
geary_nonblocking_batch_execute_all_async_data_free (gpointer _data)
{
	GearyNonblockingBatchExecuteAllAsyncData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->cancellable);
	_g_object_unref0 (_data_->self);
	g_slice_free (GearyNonblockingBatchExecuteAllAsyncData, _data_);
}

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

void
geary_nonblocking_batch_execute_all_async (GearyNonblockingBatch* self,
                                           GCancellable* cancellable,
                                           GAsyncReadyCallback _callback_,
                                           gpointer _user_data_)
{
	GearyNonblockingBatchExecuteAllAsyncData* _data_;
	GearyNonblockingBatch* _tmp0_;
	GCancellable* _tmp1_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_BATCH (self));
	g_return_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()));
	_data_ = g_slice_new0 (GearyNonblockingBatchExecuteAllAsyncData);
	_data_->_async_result = g_task_new (G_OBJECT (self), cancellable, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, geary_nonblocking_batch_execute_all_async_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	_tmp1_ = _g_object_ref0 (cancellable);
	_g_object_unref0 (_data_->cancellable);
	_data_->cancellable = _tmp1_;
	geary_nonblocking_batch_execute_all_async_co (_data_);
}

void
geary_nonblocking_batch_execute_all_finish (GearyNonblockingBatch* self,
                                            GAsyncResult* _res_,
                                            GError** error)
{
	GearyNonblockingBatchExecuteAllAsyncData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return;
	}
}

/**
     * Executes all the {@link BatchOperation}s added to the batch.
     *
     * The supplied Cancellable will be passed to each {@link BatchOperation.execute_async}.
     *
     * If the batch is executing or already executed, IOError.PENDING will be thrown.  If the
     * Cancellable is already cancelled, IOError.CANCELLED is thrown.  Other errors may be thrown
     * as well; see {@link Lock.wait_async}.
     *
     * Batch will launch each BatchOperation in the order added.  Depending on the BatchOperation,
     * this does not guarantee that they'll complete in any particular order.
     *
     * If there are no operations added to the batch, the method quietly exits.
     */
static void
geary_nonblocking_batch_execute_all_async_ready (GObject* source_object,
                                                 GAsyncResult* _res_,
                                                 gpointer _user_data_)
{
	GearyNonblockingBatchExecuteAllAsyncData* _data_;
	_data_ = _user_data_;
	_data_->_source_object_ = source_object;
	_data_->_res_ = _res_;
	geary_nonblocking_batch_execute_all_async_co (_data_);
}

static gboolean
geary_nonblocking_batch_execute_all_async_co (GearyNonblockingBatchExecuteAllAsyncData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		case 1:
		goto _state_1;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	if (_data_->self->priv->locked) {
		_data_->_tmp0_ = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_PENDING, "NonblockingBatch already executed or executing");
		_data_->_inner_error0_ = _data_->_tmp0_;
		g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
		g_object_unref (_data_->_async_result);
		return FALSE;
	}
	_data_->self->priv->locked = TRUE;
	_data_->_tmp1_ = _data_->self->priv->contexts;
	_data_->_tmp2_ = gee_abstract_map_get_size (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp1_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_data_->_tmp3_ = _data_->_tmp2_;
	if (_data_->_tmp3_ == 0) {
		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;
	}
	if (_data_->cancellable != NULL) {
		_data_->_tmp4_ = g_cancellable_is_cancelled (_data_->cancellable);
	} else {
		_data_->_tmp4_ = FALSE;
	}
	if (_data_->_tmp4_) {
		_data_->_tmp5_ = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "NonblockingBatch cancelled before executing");
		_data_->_inner_error0_ = _data_->_tmp5_;
		g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
		g_object_unref (_data_->_async_result);
		return FALSE;
	}
	_data_->_tmp6_ = _data_->self->priv->contexts;
	_data_->_tmp7_ = gee_abstract_map_get_size (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp6_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_data_->_tmp8_ = _data_->_tmp7_;
	g_signal_emit (_data_->self, geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_STARTED_SIGNAL], 0, _data_->_tmp8_);
	_data_->count = 0;
	{
		_data_->id = GEARY_NONBLOCKING_BATCH_START_ID;
		{
			_data_->_tmp9_ = TRUE;
			while (TRUE) {
				if (!_data_->_tmp9_) {
					_data_->_tmp10_ = _data_->id;
					_data_->id = _data_->_tmp10_ + 1;
				}
				_data_->_tmp9_ = FALSE;
				if (!(_data_->id < _data_->self->priv->next_result_id)) {
					break;
				}
				_data_->_tmp11_ = _data_->self->priv->contexts;
				_data_->_tmp12_ = gee_abstract_map_get (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp11_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap), (gpointer) ((gintptr) _data_->id));
				_data_->context = (GearyNonblockingBatchBatchContext*) _data_->_tmp12_;
				_data_->_tmp13_ = _data_->context;
				_vala_assert (_data_->_tmp13_ != NULL, "context != null");
				_data_->_tmp14_ = _data_->context;
				geary_nonblocking_batch_batch_context_schedule (_data_->_tmp14_, _data_->self, _data_->cancellable);
				_data_->_tmp15_ = _data_->count;
				_data_->count = _data_->_tmp15_ + 1;
				_g_object_unref0 (_data_->context);
			}
		}
	}
	_data_->_tmp16_ = _data_->self->priv->contexts;
	_data_->_tmp17_ = gee_abstract_map_get_size (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp16_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_data_->_tmp18_ = _data_->_tmp17_;
	_vala_assert (_data_->count == _data_->_tmp18_, "count == contexts.size");
	_data_->_tmp19_ = _data_->self->priv->sem;
	_data_->_state_ = 1;
	geary_nonblocking_lock_wait_async (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp19_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), _data_->cancellable, geary_nonblocking_batch_execute_all_async_ready, _data_);
	return FALSE;
	_state_1:
	geary_nonblocking_lock_wait_finish (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp19_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), _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;
}

/**
     * Returns a Set of identifiers for all added {@link BatchOperation}s.
     */
GeeSet*
geary_nonblocking_batch_get_ids (GearyNonblockingBatch* self)
{
	GeeHashMap* _tmp0_;
	GeeSet* _tmp1_;
	GeeSet* _tmp2_;
	GeeSet* result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), NULL);
	_tmp0_ = self->priv->contexts;
	_tmp1_ = gee_abstract_map_get_keys (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_tmp2_ = _tmp1_;
	result = _tmp2_;
	return result;
}

/**
     * Returns the NonblockingBatchOperation for the supplied identifier.
     *
     * @return null if the identifier is invalid or unknown.
     */
GearyNonblockingBatchOperation*
geary_nonblocking_batch_get_operation (GearyNonblockingBatch* self,
                                       gint id)
{
	GearyNonblockingBatchBatchContext* context = NULL;
	GeeHashMap* _tmp0_;
	gpointer _tmp1_;
	GearyNonblockingBatchOperation* _tmp2_ = NULL;
	GearyNonblockingBatchBatchContext* _tmp3_;
	GearyNonblockingBatchOperation* _tmp6_;
	GearyNonblockingBatchOperation* result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), NULL);
	_tmp0_ = self->priv->contexts;
	_tmp1_ = gee_abstract_map_get (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap), (gpointer) ((gintptr) id));
	context = (GearyNonblockingBatchBatchContext*) _tmp1_;
	_tmp3_ = context;
	if (_tmp3_ != NULL) {
		GearyNonblockingBatchBatchContext* _tmp4_;
		GearyNonblockingBatchOperation* _tmp5_;
		_tmp4_ = context;
		_tmp5_ = _tmp4_->op;
		_tmp2_ = _tmp5_;
	} else {
		_tmp2_ = NULL;
	}
	_tmp6_ = _g_object_ref0 (_tmp2_);
	result = _tmp6_;
	_g_object_unref0 (context);
	return result;
}

/**
     * Returns the resulting Object from the operation for the supplied identifier.
     *
     * If the operation threw an exception, it will be thrown here.  If all the operations' results
     * are examined with this method, there is no need to call throw_first_exception().
     *
     * If the operation has not completed, IOError.BUSY will be thrown.  It is legal to query
     * the result of a completed operation while others are executing.
     *
     * @return The resulting Object for the executed {@link BatchOperation}, which may be null.
     */
GObject*
geary_nonblocking_batch_get_result (GearyNonblockingBatch* self,
                                    gint id,
                                    GError** error)
{
	GearyNonblockingBatchBatchContext* context = NULL;
	GeeHashMap* _tmp0_;
	gpointer _tmp1_;
	GearyNonblockingBatchBatchContext* _tmp2_;
	GearyNonblockingBatchBatchContext* _tmp3_;
	GearyNonblockingBatchBatchContext* _tmp5_;
	GError* _tmp6_;
	GearyNonblockingBatchBatchContext* _tmp10_;
	GObject* _tmp11_;
	GObject* _tmp12_;
	GError* _inner_error0_ = NULL;
	GObject* result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), NULL);
	_tmp0_ = self->priv->contexts;
	_tmp1_ = gee_abstract_map_get (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap), (gpointer) ((gintptr) id));
	context = (GearyNonblockingBatchBatchContext*) _tmp1_;
	_tmp2_ = context;
	if (_tmp2_ == NULL) {
		result = NULL;
		_g_object_unref0 (context);
		return result;
	}
	_tmp3_ = context;
	if (!_tmp3_->completed) {
		GError* _tmp4_;
		_tmp4_ = g_error_new (G_IO_ERROR, G_IO_ERROR_BUSY, "NonblockingBatchOperation %d not completed", id);
		_inner_error0_ = _tmp4_;
		g_propagate_error (error, _inner_error0_);
		_g_object_unref0 (context);
		return NULL;
	}
	_tmp5_ = context;
	_tmp6_ = _tmp5_->threw;
	if (_tmp6_ != NULL) {
		GearyNonblockingBatchBatchContext* _tmp7_;
		GError* _tmp8_;
		GError* _tmp9_;
		_tmp7_ = context;
		_tmp8_ = _tmp7_->threw;
		_tmp9_ = _g_error_copy0 (_tmp8_);
		_inner_error0_ = _tmp9_;
		g_propagate_error (error, _inner_error0_);
		_g_object_unref0 (context);
		return NULL;
	}
	_tmp10_ = context;
	_tmp11_ = _tmp10_->returned;
	_tmp12_ = _g_object_ref0 (_tmp11_);
	result = _tmp12_;
	_g_object_unref0 (context);
	return result;
}

/**
     * If no results are examined via {@link get_result}, this method can be used to manually throw
     * the first seen Error from the operations.
     */
void
geary_nonblocking_batch_throw_first_exception (GearyNonblockingBatch* self,
                                               GError** error)
{
	GError* _tmp0_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (GEARY_NONBLOCKING_IS_BATCH (self));
	_tmp0_ = self->priv->_first_exception;
	if (_tmp0_ != NULL) {
		GError* _tmp1_;
		GError* _tmp2_;
		_tmp1_ = self->priv->_first_exception;
		_tmp2_ = _g_error_copy0 (_tmp1_);
		_inner_error0_ = _tmp2_;
		g_propagate_error (error, _inner_error0_);
		return;
	}
}

/**
     * Returns the Error message if an exception was encountered, null otherwise.
     */
gchar*
geary_nonblocking_batch_get_first_exception_message (GearyNonblockingBatch* self)
{
	const gchar* _tmp0_ = NULL;
	GError* _tmp1_;
	gchar* _tmp4_;
	gchar* result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH (self), NULL);
	_tmp1_ = self->priv->_first_exception;
	if (_tmp1_ != NULL) {
		GError* _tmp2_;
		const gchar* _tmp3_;
		_tmp2_ = self->priv->_first_exception;
		_tmp3_ = _tmp2_->message;
		_tmp0_ = _tmp3_;
	} else {
		_tmp0_ = NULL;
	}
	_tmp4_ = g_strdup (_tmp0_);
	result = _tmp4_;
	return result;
}

static void
geary_nonblocking_batch_on_context_completed (GearyNonblockingBatch* self,
                                              GearyNonblockingBatchBatchContext* context)
{
	gboolean _tmp0_ = FALSE;
	GError* _tmp1_;
	GearyNonblockingBatchOperation* _tmp4_;
	GObject* _tmp5_;
	GError* _tmp6_;
	GeeHashMap* _tmp7_;
	gint _tmp8_;
	gint _tmp9_;
	gint _tmp10_;
	GeeHashMap* _tmp11_;
	gint _tmp12_;
	gint _tmp13_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (GEARY_NONBLOCKING_IS_BATCH (self));
	g_return_if_fail (GEARY_NONBLOCKING_BATCH_IS_BATCH_CONTEXT (context));
	_tmp1_ = self->priv->_first_exception;
	if (_tmp1_ == NULL) {
		GError* _tmp2_;
		_tmp2_ = context->threw;
		_tmp0_ = _tmp2_ != NULL;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		GError* _tmp3_;
		_tmp3_ = context->threw;
		geary_nonblocking_batch_set_first_exception (self, _tmp3_);
	}
	_tmp4_ = context->op;
	_tmp5_ = context->returned;
	_tmp6_ = context->threw;
	g_signal_emit (self, geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_OPERATION_COMPLETED_SIGNAL], 0, _tmp4_, _tmp5_, _tmp6_);
	_tmp7_ = self->priv->contexts;
	_tmp8_ = gee_abstract_map_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp7_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_tmp9_ = _tmp8_;
	_vala_assert (self->priv->completed_ops < _tmp9_, "completed_ops < contexts.size");
	self->priv->completed_ops = self->priv->completed_ops + 1;
	_tmp10_ = self->priv->completed_ops;
	_tmp11_ = self->priv->contexts;
	_tmp12_ = gee_abstract_map_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp11_, GEE_TYPE_ABSTRACT_MAP, GeeAbstractMap));
	_tmp13_ = _tmp12_;
	if (_tmp10_ == _tmp13_) {
		GError* _tmp17_;
		{
			GearyNonblockingSemaphore* _tmp14_;
			_tmp14_ = self->priv->sem;
			geary_nonblocking_lock_notify (G_TYPE_CHECK_INSTANCE_CAST (_tmp14_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), &_inner_error0_);
			if (G_UNLIKELY (_inner_error0_ != NULL)) {
				goto __catch0_g_error;
			}
		}
		goto __finally0;
		__catch0_g_error:
		{
			GError* err = NULL;
			GError* _tmp15_;
			const gchar* _tmp16_;
			err = _inner_error0_;
			_inner_error0_ = NULL;
			_tmp15_ = err;
			_tmp16_ = _tmp15_->message;
			g_debug ("nonblocking-batch.vala:282: Unable to notify NonblockingBatch semaphor" \
"e: %s", _tmp16_);
			_g_error_free0 (err);
		}
		__finally0:
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
			g_clear_error (&_inner_error0_);
			return;
		}
		_tmp17_ = self->priv->_first_exception;
		g_signal_emit (self, geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_COMPLETED_SIGNAL], 0, self->priv->completed_ops, _tmp17_);
	}
}

static GearyNonblockingBatchBatchContext*
geary_nonblocking_batch_batch_context_construct (GType object_type,
                                                 gint id,
                                                 GearyNonblockingBatchOperation* op)
{
	GearyNonblockingBatchBatchContext * self = NULL;
	GearyNonblockingBatchOperation* _tmp0_;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_BATCH_OPERATION (op), NULL);
	self = (GearyNonblockingBatchBatchContext*) geary_base_object_construct (object_type);
	self->id = id;
	_tmp0_ = _g_object_ref0 (op);
	_g_object_unref0 (self->op);
	self->op = _tmp0_;
	return self;
}

static GearyNonblockingBatchBatchContext*
geary_nonblocking_batch_batch_context_new (gint id,
                                           GearyNonblockingBatchOperation* op)
{
	return geary_nonblocking_batch_batch_context_construct (GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT, id, op);
}

static void
_geary_nonblocking_batch_batch_context_on_op_completed_gasync_ready_callback (GObject* source_object,
                                                                              GAsyncResult* res,
                                                                              gpointer self)
{
	geary_nonblocking_batch_batch_context_on_op_completed ((GearyNonblockingBatchBatchContext*) self, source_object, res);
	g_object_unref (self);
}

static void
geary_nonblocking_batch_batch_context_schedule (GearyNonblockingBatchBatchContext* self,
                                                GearyNonblockingBatch* owner,
                                                GCancellable* cancellable)
{
	GearyNonblockingBatch* _tmp0_;
	GearyNonblockingBatchOperation* _tmp1_;
	g_return_if_fail (GEARY_NONBLOCKING_BATCH_IS_BATCH_CONTEXT (self));
	g_return_if_fail (GEARY_NONBLOCKING_IS_BATCH (owner));
	g_return_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()));
	_tmp0_ = _g_object_ref0 (owner);
	_g_object_unref0 (self->owner);
	self->owner = _tmp0_;
	_tmp1_ = self->op;
	geary_nonblocking_batch_operation_execute_async (_tmp1_, cancellable, _geary_nonblocking_batch_batch_context_on_op_completed_gasync_ready_callback, g_object_ref (self));
}

static void
geary_nonblocking_batch_batch_context_on_op_completed (GearyNonblockingBatchBatchContext* self,
                                                       GObject* source,
                                                       GAsyncResult* _result_)
{
	GearyNonblockingBatch* _tmp6_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (GEARY_NONBLOCKING_BATCH_IS_BATCH_CONTEXT (self));
	g_return_if_fail ((source == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (source, G_TYPE_OBJECT));
	g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (_result_, g_async_result_get_type ()));
	self->completed = TRUE;
	{
		GObject* _tmp0_ = NULL;
		GearyNonblockingBatchOperation* _tmp1_;
		GObject* _tmp2_;
		GObject* _tmp3_;
		_tmp1_ = self->op;
		_tmp2_ = geary_nonblocking_batch_operation_execute_finish (_tmp1_, _result_, &_inner_error0_);
		_tmp0_ = _tmp2_;
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			goto __catch0_g_error;
		}
		_tmp3_ = _tmp0_;
		_tmp0_ = NULL;
		_g_object_unref0 (self->returned);
		self->returned = _tmp3_;
		_g_object_unref0 (_tmp0_);
	}
	goto __finally0;
	__catch0_g_error:
	{
		GError* err = NULL;
		GError* _tmp4_;
		GError* _tmp5_;
		err = _inner_error0_;
		_inner_error0_ = NULL;
		_tmp4_ = err;
		_tmp5_ = _g_error_copy0 (_tmp4_);
		_g_error_free0 (self->threw);
		self->threw = _tmp5_;
		_g_error_free0 (err);
	}
	__finally0:
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
		g_clear_error (&_inner_error0_);
		return;
	}
	_tmp6_ = self->owner;
	geary_nonblocking_batch_on_context_completed (_tmp6_, self);
	_g_object_unref0 (self->owner);
	self->owner = NULL;
}

static void
geary_nonblocking_batch_batch_context_class_init (GearyNonblockingBatchBatchContextClass * klass,
                                                  gpointer klass_data)
{
	geary_nonblocking_batch_batch_context_parent_class = g_type_class_peek_parent (klass);
	G_OBJECT_CLASS (klass)->finalize = geary_nonblocking_batch_batch_context_finalize;
}

static void
geary_nonblocking_batch_batch_context_instance_init (GearyNonblockingBatchBatchContext * self,
                                                     gpointer klass)
{
	self->owner = NULL;
	self->completed = FALSE;
	self->returned = NULL;
	self->threw = NULL;
}

static void
geary_nonblocking_batch_batch_context_finalize (GObject * obj)
{
	GearyNonblockingBatchBatchContext * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT, GearyNonblockingBatchBatchContext);
	_g_object_unref0 (self->op);
	_g_object_unref0 (self->owner);
	_g_object_unref0 (self->returned);
	_g_error_free0 (self->threw);
	G_OBJECT_CLASS (geary_nonblocking_batch_batch_context_parent_class)->finalize (obj);
}

 G_GNUC_NO_INLINE static GType
geary_nonblocking_batch_batch_context_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyNonblockingBatchBatchContextClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_nonblocking_batch_batch_context_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyNonblockingBatchBatchContext), 0, (GInstanceInitFunc) geary_nonblocking_batch_batch_context_instance_init, NULL };
	GType geary_nonblocking_batch_batch_context_type_id;
	geary_nonblocking_batch_batch_context_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearyNonblockingBatchBatchContext", &g_define_type_info, 0);
	return geary_nonblocking_batch_batch_context_type_id;
}

static GType
geary_nonblocking_batch_batch_context_get_type (void)
{
	static gsize geary_nonblocking_batch_batch_context_type_id__once = 0;
	if (g_once_init_enter (&geary_nonblocking_batch_batch_context_type_id__once)) {
		GType geary_nonblocking_batch_batch_context_type_id;
		geary_nonblocking_batch_batch_context_type_id = geary_nonblocking_batch_batch_context_get_type_once ();
		g_once_init_leave (&geary_nonblocking_batch_batch_context_type_id__once, geary_nonblocking_batch_batch_context_type_id);
	}
	return geary_nonblocking_batch_batch_context_type_id__once;
}

static void
geary_nonblocking_batch_class_init (GearyNonblockingBatchClass * klass,
                                    gpointer klass_data)
{
	geary_nonblocking_batch_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GearyNonblockingBatch_private_offset);
	G_OBJECT_CLASS (klass)->get_property = _vala_geary_nonblocking_batch_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_geary_nonblocking_batch_set_property;
	G_OBJECT_CLASS (klass)->finalize = geary_nonblocking_batch_finalize;
	/**
	     * Returns the number of {@link BatchOperation}s added to the batch.
	     */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_BATCH_SIZE_PROPERTY, geary_nonblocking_batch_properties[GEARY_NONBLOCKING_BATCH_SIZE_PROPERTY] = g_param_spec_int ("size", "size", "size", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	     * Returns the first exception encountered after completing {@link execute_all_async}.
	     */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_BATCH_FIRST_EXCEPTION_PROPERTY, geary_nonblocking_batch_properties[GEARY_NONBLOCKING_BATCH_FIRST_EXCEPTION_PROPERTY] = g_param_spec_boxed ("first-exception", "first-exception", "first-exception", G_TYPE_ERROR, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	     * Fired when a {@link BatchOperation} is added to the batch.
	     */
	geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_ADDED_SIGNAL] = g_signal_new ("added", GEARY_NONBLOCKING_TYPE_BATCH, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__OBJECT_INT, G_TYPE_NONE, 2, GEARY_NONBLOCKING_TYPE_BATCH_OPERATION, G_TYPE_INT);
	/**
	     * Fired when batch execution has started.
	     */
	geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_STARTED_SIGNAL] = g_signal_new ("started", GEARY_NONBLOCKING_TYPE_BATCH, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
	/**
	     * Fired when a {@link BatchOperation} has completed.
	     */
	geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_OPERATION_COMPLETED_SIGNAL] = g_signal_new ("operation-completed", GEARY_NONBLOCKING_TYPE_BATCH, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__OBJECT_OBJECT_POINTER, G_TYPE_NONE, 3, GEARY_NONBLOCKING_TYPE_BATCH_OPERATION, G_TYPE_OBJECT, G_TYPE_POINTER);
	/**
	     * Fired when all {@link BatchOperation}s have completed.
	     */
	geary_nonblocking_batch_signals[GEARY_NONBLOCKING_BATCH_COMPLETED_SIGNAL] = g_signal_new ("completed", GEARY_NONBLOCKING_TYPE_BATCH, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__INT_POINTER, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
}

static void
geary_nonblocking_batch_instance_init (GearyNonblockingBatch * self,
                                       gpointer klass)
{
	GeeHashMap* _tmp0_;
	GearyNonblockingSemaphore* _tmp1_;
	self->priv = geary_nonblocking_batch_get_instance_private (self);
	self->priv->_first_exception = NULL;
	_tmp0_ = gee_hash_map_new (G_TYPE_INT, NULL, NULL, GEARY_NONBLOCKING_BATCH_TYPE_BATCH_CONTEXT, (GBoxedCopyFunc) g_object_ref, (GDestroyNotify) g_object_unref, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
	self->priv->contexts = _tmp0_;
	_tmp1_ = geary_nonblocking_semaphore_new (NULL);
	self->priv->sem = _tmp1_;
	self->priv->next_result_id = GEARY_NONBLOCKING_BATCH_START_ID;
	self->priv->locked = FALSE;
	self->priv->completed_ops = 0;
}

static void
geary_nonblocking_batch_finalize (GObject * obj)
{
	GearyNonblockingBatch * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_NONBLOCKING_TYPE_BATCH, GearyNonblockingBatch);
	_g_error_free0 (self->priv->_first_exception);
	_g_object_unref0 (self->priv->contexts);
	_g_object_unref0 (self->priv->sem);
	G_OBJECT_CLASS (geary_nonblocking_batch_parent_class)->finalize (obj);
}

/**
 * Allows for multiple asynchronous tasks to be executed in parallel and for their results to be
 * examined after all have completed.
 *
 * Nonblocking.Batch is designed specifically with Vala's async keyword in mind.
 * Although the yield keyword allows for async tasks to execute, it only allows them to performed
 * in serial.  In a loop, for example, the next task in the loop won't execute until the current
 * one has completed.  The thread of execution won't block waiting for it, but this can be
 * suboptiminal and certain cases.
 *
 * Nonblocking.Batch allows for multiple async tasks to be gathered (via the {@link add} method)
 * into a single batch.  Each task must subclass from {@link BatchOperation}.  It's expected that
 * the subclass will maintain state particular to the operation, although Nonblocking.Batch does
 * gather two types of a results the task may generate: a result object (which descends from Object)
 * or a thrown exception.  Other results should be stored by the subclass.
 *
 * To use, create a Nonblocking.Batch and populate it via the add() method.  When all
 * {@link BatchOperation}s have been added, call {@link execute_all_async}.  NonblockingBatch will
 * execute all BatchOperations at once and only complete their execute_all_async when all have
 * finished.  As mentioned earlier, it's also gather their returned objects and thrown exceptions
 * while they run.  See {@link get_result} and {@link throw_first_exception} for more information.
 *
 * The caller will want to call either get_result or throw_first_exception to ensure that
 * errors are propagated.  It's not necessary to call both.
 *
 * After execute_all_async has completed, the results may be examined.  The Nonblocking.Batch
 * object can ''not'' be reused.
 *
 * Nonblocking.Batch will fire off all operations at once and let them complete.  It does
 * not attempt to stop the others if one throws exception.  Also, there's no algorithm to submit the
 * operations in smaller chunks (to avoid flooding the thread's MainLoop).  These may be added in
 * the future.
 */
 G_GNUC_NO_INLINE static GType
geary_nonblocking_batch_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyNonblockingBatchClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_nonblocking_batch_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyNonblockingBatch), 0, (GInstanceInitFunc) geary_nonblocking_batch_instance_init, NULL };
	GType geary_nonblocking_batch_type_id;
	geary_nonblocking_batch_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearyNonblockingBatch", &g_define_type_info, 0);
	GearyNonblockingBatch_private_offset = g_type_add_instance_private (geary_nonblocking_batch_type_id, sizeof (GearyNonblockingBatchPrivate));
	return geary_nonblocking_batch_type_id;
}

GType
geary_nonblocking_batch_get_type (void)
{
	static gsize geary_nonblocking_batch_type_id__once = 0;
	if (g_once_init_enter (&geary_nonblocking_batch_type_id__once)) {
		GType geary_nonblocking_batch_type_id;
		geary_nonblocking_batch_type_id = geary_nonblocking_batch_get_type_once ();
		g_once_init_leave (&geary_nonblocking_batch_type_id__once, geary_nonblocking_batch_type_id);
	}
	return geary_nonblocking_batch_type_id__once;
}

static void
_vala_geary_nonblocking_batch_get_property (GObject * object,
                                            guint property_id,
                                            GValue * value,
                                            GParamSpec * pspec)
{
	GearyNonblockingBatch * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_NONBLOCKING_TYPE_BATCH, GearyNonblockingBatch);
	switch (property_id) {
		case GEARY_NONBLOCKING_BATCH_SIZE_PROPERTY:
		g_value_set_int (value, geary_nonblocking_batch_get_size (self));
		break;
		case GEARY_NONBLOCKING_BATCH_FIRST_EXCEPTION_PROPERTY:
		g_value_set_pointer (value, geary_nonblocking_batch_get_first_exception (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_geary_nonblocking_batch_set_property (GObject * object,
                                            guint property_id,
                                            const GValue * value,
                                            GParamSpec * pspec)
{
	GearyNonblockingBatch * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_NONBLOCKING_TYPE_BATCH, GearyNonblockingBatch);
	switch (property_id) {
		case GEARY_NONBLOCKING_BATCH_FIRST_EXCEPTION_PROPERTY:
		geary_nonblocking_batch_set_first_exception (self, g_value_get_pointer (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

