/**
 * gdata_calendar_service_query_events:
 * @self: a #GDataCalendarService
 * @calendar: a #GDataCalendarCalendar
 * @query: a #GDataQuery with the query parameters, or %NULL
 * @cancellable: optional #GCancellable object, or %NULL
 * @progress_callback: a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
 * @progress_user_data: data to pass to the @progress_callback function
 * @error: a #GError, or %NULL
 *
 * Queries the service to return a list of events in the given @calendar, which match @query.
 *
 * For more details, see gdata_service_query().
 *
 * Return value: a #GDataFeed of query results; unref with g_object_unref()
 **/
GDataFeed *
gdata_calendar_service_query_events (GDataCalendarService *self, GDataCalendarCalendar *calendar, GDataQuery *query, GCancellable *cancellable,
				     GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
{
	/* TODO: Async variant */
	const gchar *uri;

	/* Ensure we're authenticated first */
	if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
				     _("You must be authenticated to query your own calendars."));
		return NULL;
	}

	/* Use the calendar's content src */
	uri = gdata_entry_get_content (GDATA_ENTRY (calendar));
	if (uri == NULL) {
		/* Erroring out is probably the safest thing to do */
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
				     _("The calendar did not have a content source."));
		return NULL;
	}

	/* Execute the query */
	return gdata_service_query (GDATA_SERVICE (self), uri, query, GDATA_TYPE_CALENDAR_EVENT, cancellable,
				    progress_callback, progress_user_data, error);
}
/**
 * picasaweb_upload_cb:
 *
 * This checks that we are authenticated (popping up the login window
 * if we're not) and, if we are, moves on to upload the files.
 **/
static void
picasaweb_upload_cb (GtkAction	*action,
		     XviewerPostasaPlugin *plugin)
{
	XviewerPostasaPluginPrivate *priv;

	g_return_if_fail (XVIEWER_IS_POSTASA_PLUGIN (plugin));

	priv = plugin->priv;

#ifdef HAVE_LIBGDATA_0_9
	if (gdata_service_is_authorized (GDATA_SERVICE (priv->service)) == TRUE)
#else
	if (gdata_service_is_authenticated (GDATA_SERVICE (priv->service)) == TRUE)
#endif
	{
		picasaweb_upload_files (plugin);
	} else {
		/* when the dialog closes, it checks if this is set to see if it should upload anything */
		priv->uploads_pending = TRUE;

		login_get_dialog (plugin);
		gtk_label_set_text (priv->login_message, _("Please log in to continue upload."));
		gtk_window_present (GTK_WINDOW (priv->login_dialog));
	}
}
/**
 * gdata_calendar_service_query_all_calendars:
 * @self: a #GDataCalendarService
 * @query: a #GDataQuery with the query parameters, or %NULL
 * @cancellable: optional #GCancellable object, or %NULL
 * @progress_callback: a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
 * @progress_user_data: data to pass to the @progress_callback function
 * @error: a #GError, or %NULL
 *
 * Queries the service to return a list of all calendars from the authenticated account which match the given
 * @query. It will return all calendars the user has read access to, including primary, secondary and imported
 * calendars.
 *
 * For more details, see gdata_service_query().
 *
 * Return value: a #GDataFeed of query results; unref with g_object_unref()
 **/
GDataFeed *
gdata_calendar_service_query_all_calendars (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
					    GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
{
	/* Ensure we're authenticated first */
	if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
				     _("You must be authenticated to query all calendars."));
		return NULL;
	}

	return gdata_service_query (GDATA_SERVICE (self), "http://www.google.com/calendar/feeds/default/allcalendars/full", query,
				    GDATA_TYPE_CALENDAR_CALENDAR, cancellable, progress_callback, progress_user_data, error);
}
/**
 * gdata_calendar_service_query_own_calendars_async:
 * @self: a #GDataCalendarService
 * @query: a #GDataQuery with the query parameters, or %NULL
 * @cancellable: optional #GCancellable object, or %NULL
 * @progress_callback: a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
 * @progress_user_data: data to pass to the @progress_callback function
 * @callback: a #GAsyncReadyCallback to call when authentication is finished
 * @user_data: data to pass to the @callback function
 *
 * Queries the service to return a list of calendars from the authenticated account which match the given
 * @query, and the authenticated user owns. @self and @query are all reffed when this function is called,
 * so can safely be unreffed after this function returns.
 *
 * For more details, see gdata_calendar_service_query_own_calendars(), which is the synchronous version of
 * this function, and gdata_service_query_async(), which is the base asynchronous query function.
 **/
void
gdata_calendar_service_query_own_calendars_async (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
						  GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
						  GAsyncReadyCallback callback, gpointer user_data)
{
	/* Ensure we're authenticated first */
	if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
		g_simple_async_report_error_in_idle (G_OBJECT (self), callback, user_data,
						     GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
						     _("You must be authenticated to query your own calendars."));
		return;
	}

	gdata_service_query_async (GDATA_SERVICE (self), "http://www.google.com/calendar/feeds/default/owncalendars/full", query,
				   GDATA_TYPE_CALENDAR_CALENDAR, cancellable, progress_callback, progress_user_data, callback, user_data);
}
/**
 * login_get_dialog:
 *
 * Retrieves the login dialog.  If it has not yet been constructed, it
 * does so.  If the user is already authenticated, it populates the
 * username and password boxes with the relevant values.
 **/
static GtkWidget *
login_get_dialog (XviewerPostasaPlugin *plugin)
{
	GtkBuilder *builder;
	GError *error = NULL;

	if (plugin->priv->login_dialog == NULL) {
		builder = gtk_builder_new ();
		gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
		gtk_builder_add_from_resource (builder, GTKBUILDER_CONFIG_FILE,
		                               &error);
		if (error != NULL) {
			g_warning ("Couldn't load Postasa configuration UI file:%d:%s", error->code, error->message);
			g_error_free (error);
		}

		/* do not unref gtk_builder_get_object() returns */
		plugin->priv->username_entry = GTK_ENTRY  (gtk_builder_get_object (builder, "username_entry"));
		plugin->priv->password_entry = GTK_ENTRY  (gtk_builder_get_object (builder, "password_entry"));
		plugin->priv->login_dialog   = GTK_DIALOG (gtk_builder_get_object (builder, "postasa_login_dialog"));
		plugin->priv->cancel_button  = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button"));
		plugin->priv->login_button   = GTK_BUTTON (gtk_builder_get_object (builder, "login_button"));
		plugin->priv->login_message  = GTK_LABEL  (gtk_builder_get_object (builder, "login_message"));

		g_object_unref (builder);

		g_signal_connect (G_OBJECT (plugin->priv->login_button),  "clicked", G_CALLBACK (picasaweb_login_cb),     plugin);
		g_signal_connect (G_OBJECT (plugin->priv->cancel_button), "clicked", G_CALLBACK (login_dialog_cancel_button_cb), plugin);
		g_signal_connect (G_OBJECT (plugin->priv->login_dialog), "delete-event", G_CALLBACK (login_dialog_delete_event_cb), plugin);

#ifdef HAVE_LIBGDATA_0_9
		if (gdata_service_is_authorized (GDATA_SERVICE (plugin->priv->service))) {
			gtk_entry_set_text (plugin->priv->username_entry, gdata_client_login_authorizer_get_username (plugin->priv->authorizer));
			gtk_entry_set_text (plugin->priv->password_entry, gdata_client_login_authorizer_get_password (plugin->priv->authorizer));
#else
		if (gdata_service_is_authenticated (GDATA_SERVICE (plugin->priv->service))) {
			gtk_entry_set_text (plugin->priv->username_entry, gdata_service_get_username (GDATA_SERVICE (plugin->priv->service)));
			gtk_entry_set_text (plugin->priv->password_entry, gdata_service_get_password (GDATA_SERVICE (plugin->priv->service)));
#endif
		}
	}

	return GTK_WIDGET (plugin->priv->login_dialog);
}


/*** XviewerPlugin Functions ***/

/**
 * impl_activate:
 *
 * Plugin hook for plugin activation.  Creates #WindowData for the
 * #XviewerPostasaPlugin that gets associated with the window and defines
 * some UI.
 **/
static void
impl_activate (XviewerWindowActivatable *activatable)
{
	XviewerPostasaPlugin *plugin = XVIEWER_POSTASA_PLUGIN (activatable);
	XviewerPostasaPluginPrivate *priv = plugin->priv;
	GtkUIManager *manager;
	XviewerWindow *window;

	xviewer_debug (DEBUG_PLUGINS);

	window = priv->xviewer_window;

	priv->ui_action_group = gtk_action_group_new ("XviewerPostasaPluginActions");
	gtk_action_group_set_translation_domain (priv->ui_action_group,
						 GETTEXT_PACKAGE);
	gtk_action_group_add_actions (priv->ui_action_group,
				      action_entries,
				      G_N_ELEMENTS (action_entries), plugin);

	manager = xviewer_window_get_ui_manager (window); /* do not unref */
	gtk_ui_manager_insert_action_group (manager, priv->ui_action_group, -1);
	priv->ui_id = gtk_ui_manager_add_ui_from_string (manager,
							 ui_definition,
							 -1, NULL);
	g_warn_if_fail (priv->ui_id != 0);
}
/**
 * picasaweb_upload_files:
 *
 * This obtains the list of selected images in XVIEWER (selected in the
 * thumbview), sets up asynchronous uploads through
 * tmp_picasaweb_upload_async() in their own thread and instigates
 * them.

 * This attempts to upload the selected files.  It provides a message
 * near the end indicating the number successfully uploaded, and any
 * error messages encountered along the way.
 *
 * TODO: once gdata_picasaweb_service_upload_file_async() is available
 * from libgdata, simplify this as possible.
 **/
static void
picasaweb_upload_files (XviewerPostasaPlugin *plugin)
{
	XviewerWindow *window;
	GtkWidget *thumbview;
	GList *images, *node;
	XviewerImage *image;
	GFile *imgfile;
	GCancellable *cancellable;
	GSimpleAsyncResult *result;
	PicasaWebUploadFileAsyncData *data;

#ifdef HAVE_LIBGDATA_0_9
	if (gdata_service_is_authorized (GDATA_SERVICE (plugin->priv->service)) == FALSE) {
#else
	if (gdata_service_is_authenticated (GDATA_SERVICE (plugin->priv->service)) == FALSE) {
#endif
		g_warning ("PicasaWeb could not be authenticated.  Aborting upload.");
		return;
	}

	window = plugin->priv->xviewer_window;
	thumbview = xviewer_window_get_thumb_view (window); /* do not unref */
	images = xviewer_thumb_view_get_selected_images (XVIEWER_THUMB_VIEW (thumbview)); /* need to use g_list_free() */

	for (node = g_list_first (images); node != NULL; node = node->next) {
		image = (XviewerImage *) node->data;
		cancellable = g_cancellable_new (); /* TODO: this gets attached to the image's list row; free with row */

		imgfile = xviewer_image_get_file (image); /* unref this */

		data = g_slice_new0(PicasaWebUploadFileAsyncData); /* freed by picasaweb_upload_async_cb() or below */
		data->imgfile = g_file_dup (imgfile); /* unref'd in free_picasaweb_upload_file_async_data() */
		data->iter = uploads_add_entry (plugin, image, cancellable); /* freed with data */

		if (g_file_query_exists (imgfile, cancellable)) {
			/* TODO: want to replace much of this with gdata_picasaweb_service_upload_file_async when that's avail */
			result = g_simple_async_result_new (G_OBJECT (plugin), (GAsyncReadyCallback)picasaweb_upload_async_cb,
							    data, tmp_picasaweb_upload_async); /* TODO: should this be freed? where? */
			g_simple_async_result_run_in_thread (result, tmp_picasaweb_upload_async, 0, cancellable);
		} else {
			/* TODO: consider setting a proper error and passing it in the data through GSimpleAsyncResult's thread */
			gtk_list_store_set (plugin->priv->uploads_store, data->iter, 3, -1, 5, "File not found", -1);
			free_picasaweb_upload_file_async_data (data);
		}
		g_object_unref (imgfile);
	}
	g_list_free (images);
}

/**
 * picasaweb_login_async_cb:
 *
 * Handles the result of the asynchronous
 * gdata_service_authenticate_async() operation, called by our
 * picasaweb_login_cb().  Upon success, it switches "Cancel" to
 * "Close".  Regardless of the response, it re-enables the Login
 * button (which is desensitised during the login attempt).
 **/
#ifdef HAVE_LIBGDATA_0_9
static void
picasaweb_login_async_cb (GDataClientLoginAuthorizer *authorizer, GAsyncResult *result, XviewerPostasaPlugin *plugin)
#else
static void
picasaweb_login_async_cb (GDataPicasaWebService *service, GAsyncResult *result, XviewerPostasaPlugin *plugin)
#endif
{
	GError *error = NULL;
	gchar *message;
	gboolean success = FALSE;

#ifdef HAVE_LIBGDATA_0_9
	success = gdata_client_login_authorizer_authenticate_finish (authorizer,
								     result,
								     &error);
#else
	success = gdata_service_authenticate_finish (GDATA_SERVICE (service), result, &error);
#endif

	gtk_widget_set_sensitive (GTK_WIDGET (plugin->priv->login_button), TRUE);
	gtk_widget_set_sensitive (GTK_WIDGET (plugin->priv->username_entry), TRUE);
	gtk_widget_set_sensitive (GTK_WIDGET (plugin->priv->password_entry), TRUE);

	if (success == FALSE || error != NULL) {
		message = g_strdup_printf (_("Login failed. %s"), error->message);
		gtk_label_set_text (plugin->priv->login_message, message);
		g_free (message);
	} else {
		gtk_label_set_text (plugin->priv->login_message, _("Logged in successully."));
		gtk_button_set_label (plugin->priv->cancel_button, _("Close"));
		login_dialog_close (plugin);
	}
}