/*
 * Mail Notification
 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

%headertop{
#include <libnotify/notify.h>
#include "mn-message.h"
%}

%{
#include <glib/gi18n.h>
#include "mn-conf.h"
#include "mn-shell.h"
#include "mn-util.h"
%}

class MN:Popup from Notify:Notification
{
  private MNMessage *message unrefwith g_object_unref;
  property OBJECT message (flags = CONSTRUCT_ONLY, link, object_type = MN:Message, type = MNMessage *);

  public gboolean visible;
  public GTimeVal show_timestamp;

  constructor (self)
  {
    GString *body;

    body = g_string_new(NULL);
    self_append_row(body, _("Mailbox:"), selfp->message->mailbox->runtime_name);
    self_append_row(body, _("From:"), selfp->message->from);
    self_append_row(body, _("Subject:"), selfp->message->subject);

    g_object_set(self,
		 "body", body->str,
		 "icon-name", "stock_mail",
		 NULL);

#if !NOTIFY_CHECK_VERSION(0,7,0)
    if (mn_conf_get_enum_value(MN_TYPE_POPUP_POSITION, MN_CONF_POPUPS_POSITION) == MN_POPUP_POSITION_ATTACHED) {
      self_wait_for_icon_to_become_ready(self);
      g_object_set(self, "attach-widget", mn_shell->icon, NULL);
    }
#endif

    g_string_free(body, TRUE);

    self_add_actions(self);

    notify_notification_set_timeout(NOTIFY_NOTIFICATION(self), self_get_conf_timeout());

    g_signal_connect(self, "closed", G_CALLBACK(self_closed_h), NULL);
  }

  private void wait_for_icon_to_become_ready(self) {
    int x, y;
    int count = 0;

    /* When the tray icon is created, it can still take some time before
     * it has arrived at the correct position. This is especially the case
     * on KDE environments. To work around this, add a little delay of at
     * most 2 seconds before showing a popup which is attached to the notification */
    do {
        gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET(mn_shell->icon)), &x, &y);

        if (x != 0 || y != 0) {
            break;
        }

        g_usleep(G_USEC_PER_SEC / 10);
        count++;
    } while (count < 20);
  }

  private void
    add_actions (self)
  {
    GSList *actions;
    GSList *l;

    /*
     * Note that notification-daemon currently assigns icons to
     * actions by prepending "stock_" to the action ID.
     */

    actions = mn_conf_get_string_list(MN_CONF_POPUPS_ACTIONS);

    MN_LIST_FOREACH(l, actions)
      {
	char *name = l->data;
	MNMessageAction *action;

	action = mn_message_get_action(name);
	if (action)
	  {
	    if (mn_message_can_perform_action(selfp->message, action))
	      notify_notification_add_action(NOTIFY_NOTIFICATION(self),
					     action->icon,
					     _(action->label),
					     self_action_cb,
					     action,
					     NULL);
	  }
	else
	  g_warning(_("configuration key %s: there is no action named \"%s\""), MN_CONF_POPUPS_ACTIONS, name);
      }

    mn_g_slist_free_deep(actions);
  }

  private void
    action_cb (NotifyNotification *notification, char *id, gpointer user_data)
  {
    Self *self = SELF(notification);
    MNMessageAction *action = user_data;

    GDK_THREADS_ENTER();

    mn_message_perform_action(selfp->message, action, self_action_done_cb, self);

    GDK_THREADS_LEAVE();
  }

  private void
    action_done_cb (MNMessageAction *action, GError *err, gpointer data)
  {
    if (err && ! g_error_matches(err, MN_MESSAGE_ACTION_ERROR, MN_MESSAGE_ACTION_ERROR_CANCELLED))
      mn_show_error_dialog(NULL, _(action->error_message), "%s", err->message);
  }

  private void
    closed_h (NotifyNotification *notification, gpointer user_data)
  {
    Self *self = SELF(notification);
    self->visible = FALSE;
  }

  private void
    append_row (GString *body (check null),
		const char *name (check null),
		const char *value (check null))
    {
      char *escaped;

      if (*body->str)
	g_string_append_c(body, '\n');

      g_string_append_printf(body, "<b>%s</b>", name);

      escaped = g_markup_escape_text(value, -1);
      g_string_append_printf(body, " %s", escaped);
      g_free(escaped);
    }

  private int
    get_conf_timeout (void)
  {
    switch (mn_conf_get_enum_value(MN_TYPE_EXPIRATION_ENABLED, MN_CONF_POPUPS_EXPIRATION_ENABLED))
      {
      case MN_EXPIRATION_ENABLED_DEFAULT:
	return NOTIFY_EXPIRES_DEFAULT;

      case MN_EXPIRATION_ENABLED_FALSE:
	return NOTIFY_EXPIRES_NEVER;

      case MN_EXPIRATION_ENABLED_TRUE:
	return mn_conf_get_int(MN_CONF_POPUPS_EXPIRATION_DELAY) * 1000;

      default:
	g_assert_not_reached();
	return 0;
      }
  }

  public void
    show (self)
  {
    GError *err = NULL;

    if (self->visible)
      return;

    if (! notify_notification_show(NOTIFY_NOTIFICATION(self), &err))
      {
	g_warning(_("unable to show popup: %s"), err->message);
	g_error_free(err);
      }

    self->visible = TRUE;
    g_get_current_time(&self->show_timestamp);
  }

  public void
    close (self)
  {
    GError *err = NULL;

    if (! self->visible)
      return;

    if (! notify_notification_close(NOTIFY_NOTIFICATION(self), &err))
      {
	g_warning(_("unable to close popup: %s"), err->message);
	g_error_free(err);
      }
  }

  public MNPopup *
    new (MN:Message *message (check null type))
  {
    /* we set the summary here because libnotify requires it */

    /* translators: header capitalization */
    return GET_NEW_VARG("summary", _("New Message"),
			MN_POPUP_PROP_MESSAGE(message),
			NULL);
  }
}
