/*
 * unity-webapps-indicator-context.c
 * Copyright (C) Canonical LTD 2011
 *
 * Author: Robert Carr <racarr@canonical.com>
 * 
 unity-webapps 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 3 of the License, or
 * (at your option) any later version.
 * 
 * unity-webapps 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 program.  If not, see <http://www.gnu.org/licenses/>.";
 */

#include <gtk/gtk.h>

#include "unity-webapps-indicator-context.h"
#include "unity-webapps-indicator-manager.h"

#include "unity-webapps-dbus-defs.h"

#include "unity-webapps-dirs.h"
#include "unity-webapps-debug.h"

#include "unity-webapps-interest-tracker.h"

#include "unity-webapps-telepathy-presence-manager.h"

#include "config.h"

static void
emit_action_invoked_signal (UnityWebappsIndicatorContext *indicator_context,
			    const gchar *action)
{
  GError *error;

  UNITY_WEBAPPS_NOTE (INDICATOR, "Emitting ActionInvoked signal (%s)", action);

  error = NULL;
  g_dbus_connection_emit_signal (indicator_context->connection,
				 NULL,
				 UNITY_WEBAPPS_INDICATOR_PATH,
				 UNITY_WEBAPPS_INDICATOR_IFACE,
				 "ActionInvoked",
				 g_variant_new ("(s)", (gchar *)action, NULL),
				 &error);
  if (error != NULL)
    {
      g_warning ("Error emitting ActionInvoked signal (from indicator) in indicator context: %s", error->message);
      
      g_error_free (error);
    }


  
}

/*
 * When an action menuitem is activated. We need to emit our action
 * signal.
 */
static void
unity_webapps_indicator_context_on_action_invoked (UnityWebappsActionManager *manager,
						  const gchar *action_path,
						  gpointer user_data)
{
  UnityWebappsIndicatorContext *indicator_context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling Menuitem activated signal");
  
  indicator_context = (UnityWebappsIndicatorContext *)user_data;

  unity_webapps_context_daemon_raise_most_recent ();
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Menuitem label is: %s", action_path);
  
  emit_action_invoked_signal (indicator_context, action_path);
}


static void
unity_webapps_indicator_context_application_activated_callback (UnityWebappsInterestManager *manager,
							       gpointer user_data)
{
  UNITY_WEBAPPS_NOTE (INDICATOR, "Got server-displayed callback");
  
  unity_webapps_context_daemon_raise_most_recent ();
}

static void
unity_webapps_indicator_context_indicator_activated_callback (UnityWebappsInterestManager *manager,
							      const gchar *name,
							      gpointer user_data)
{
  UnityWebappsIndicatorContext *indicator_context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Got user-displayed callback (%s)", name);
  
  indicator_context = (UnityWebappsIndicatorContext *)user_data;

  
  unity_webapps_context_daemon_raise_most_recent();

  emit_action_invoked_signal (indicator_context, name);
				
}

static gboolean
on_handle_show_indicator (UnityWebappsGenIndicator *indicator,
			  GDBusMethodInvocation *invocation,
			  const gchar *name,
			    gint interest_id,
			  gpointer user_data)
{
  UnityWebappsIndicatorContext *context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling ShowIndicator call: %s", name);
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_indicator_model_show_indicator_for_interest (context->indicator_model,
							     name,
							     interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}

static gboolean
on_handle_clear_indicator (UnityWebappsGenIndicator *indicator,
			   GDBusMethodInvocation *invocation,
			   const gchar *name,
			   gint interest_id,
			   gpointer user_data)
{
  UnityWebappsIndicatorContext *context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling ClearIndicator call: %s", name);
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_indicator_model_clear_indicator_for_interest (context->indicator_model,
							      name,
							      interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}

static gboolean
on_handle_clear_indicators (UnityWebappsGenIndicator *indicator,
			      GDBusMethodInvocation *invocation,
			      gint interest_id,
			      gpointer user_data)
{
  UnityWebappsIndicatorContext *context;

  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling ClearIndicator calls");

  context = (UnityWebappsIndicatorContext *)user_data;

  unity_webapps_indicator_model_clear_indicators_for_interest (context->indicator_model,
							       interest_id);

  g_dbus_method_invocation_return_value (invocation, NULL);

  return TRUE;
}

static gboolean
on_handle_set_property (UnityWebappsGenIndicator *indicator,
			GDBusMethodInvocation *invocation,
			const gchar *name,
			const gchar *property,
			const gchar *value,
			gint interest_id,
			gpointer user_data)
{
  UnityWebappsIndicatorContext *context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling SetProperty call for %s: %s->%s",
		      name, property, value);
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_indicator_model_set_indicator_property_for_interest (context->indicator_model,
								     name,
								     property,
								     g_variant_new("s", value, NULL),
								     interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}


static gboolean
on_handle_set_property_icon (UnityWebappsGenIndicator *indicator,
			     GDBusMethodInvocation *invocation,
			     const gchar *name,
			     const gchar *property,
			     const gchar *value,
			     gint interest_id,
			     gpointer user_data)
{
  UnityWebappsIndicatorContext *context;

  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling SetPropertyIcon call for %s: %s->%s",
		      name, property, value);
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_indicator_model_set_indicator_property_for_interest (context->indicator_model,
								     name,
								     property,
								     g_variant_new("s", value, NULL),
								     interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}

static gboolean
on_handle_add_action (UnityWebappsGenIndicator *indicator,
		      GDBusMethodInvocation *invocation,
		      const gchar *label,
		      gint interest_id,
		      gpointer user_data)
{
  UnityWebappsIndicatorContext *context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling AddAction call, label: %s", label);
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_indicator_view_show (context->indicator_view);
  
  // TODO: FIXME: 
  //  indicate_server_show (unity_webapps_indicator_context_get_server (context));
  
  unity_webapps_action_manager_add_action (context->action_manager,
					   label,
					   interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}

static gboolean
on_handle_remove_action (UnityWebappsGenIndicator *indicator,
			 GDBusMethodInvocation *invocation,
			 const gchar *label,
			 gint interest_id,
			 gpointer user_data)
{
  UnityWebappsIndicatorContext *context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling RemoveAction call, label: %s", label);
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_action_manager_remove_action (context->action_manager,
					      label,
					      interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}

static gboolean 
on_handle_remove_actions (UnityWebappsGenIndicator *indicator,
			  GDBusMethodInvocation *invocation,
			  gint interest_id,
			  gpointer user_data)
{
  UnityWebappsIndicatorContext *context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Handling RemoveActions call");
  
  context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_action_manager_remove_all_actions (context->action_manager,
						   interest_id);
  
  g_dbus_method_invocation_return_value (invocation, NULL);
  
  return TRUE;
}



static void
export_object (GDBusConnection *connection,
	       UnityWebappsIndicatorContext *indicator_context)
{
  GError *error;
  
  indicator_context->indicator_service_interface = unity_webapps_gen_indicator_skeleton_new ();
  
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-show-indicator",
		    G_CALLBACK (on_handle_show_indicator),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-clear-indicator",
		    G_CALLBACK (on_handle_clear_indicator),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-clear-indicators",
		    G_CALLBACK (on_handle_clear_indicators),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-set-property",
		    G_CALLBACK (on_handle_set_property),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-set-property-icon",
		    G_CALLBACK (on_handle_set_property_icon),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-add-action",
		    G_CALLBACK (on_handle_add_action),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-remove-action",
		    G_CALLBACK (on_handle_remove_action),
		    indicator_context);
  g_signal_connect (indicator_context->indicator_service_interface,
		    "handle-remove-actions",
		    G_CALLBACK (on_handle_remove_actions),
		    indicator_context);
  
  error = NULL;
  
  g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (indicator_context->indicator_service_interface),
				    connection,
				    UNITY_WEBAPPS_INDICATOR_PATH,
				    &error);
  
  if (error != NULL)
    {
      g_error ("Error exporting Unity Webapps Indicator object: %s", error->message);
      
      g_error_free (error);
      
      return;
    }
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Exported Indicator object");

}

static void
on_presence_changed (UnityWebappsPresenceManager *presence_manager,
		     gchar *status,
		     gchar *message,
		     gpointer user_data)
{
  UnityWebappsIndicatorContext *indicator_context;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Most available presence changed to %s", status);
  
  indicator_context = (UnityWebappsIndicatorContext *)user_data;
  
  unity_webapps_gen_indicator_set_presence (indicator_context->indicator_service_interface, status);
}

static void
create_presence_manager (UnityWebappsIndicatorContext *indicator_context)
{
  indicator_context->presence_manager = unity_webapps_telepathy_presence_manager_new ();
  
  g_signal_connect (indicator_context->presence_manager, "presence-changed",
		    G_CALLBACK (on_presence_changed), indicator_context);
}

UnityWebappsIndicatorContext *
unity_webapps_indicator_context_new (GDBusConnection *connection, const gchar *desktop_path, const gchar *canonical_name, UnityWebappsInterestTracker *interest_tracker)
{
  UnityWebappsIndicatorContext *indicator_context;
  gchar *menu_dbus_path;
  
  UNITY_WEBAPPS_NOTE (INDICATOR, "Creating new UnityWebappsIndicatorContext object");

  indicator_context = g_malloc0 (sizeof (UnityWebappsIndicatorContext));
  
  indicator_context->connection = g_object_ref (G_OBJECT (connection));
  indicator_context->canonical_name = g_strdup (canonical_name);
  indicator_context->desktop_path = g_strdup (desktop_path);
  
  indicator_context->num_actions = 0;

  menu_dbus_path = g_strdup_printf("/com/canonical/Unity/WebApps/%s/indicate/menu", indicator_context->canonical_name);

  indicator_context->action_manager = unity_webapps_action_manager_new_flat (interest_tracker, menu_dbus_path);
  
  unity_webapps_action_manager_set_track_activity (indicator_context->action_manager,
						   FALSE);
  
  g_signal_connect (indicator_context->action_manager,
		    "action-invoked",
		    G_CALLBACK (unity_webapps_indicator_context_on_action_invoked),
		    indicator_context);
  
  indicator_context->indicator_manager = unity_webapps_indicator_manager_new (desktop_path, unity_webapps_interest_tracker_get_interest_manager (interest_tracker));
  indicator_context->indicator_model = unity_webapps_indicator_manager_get_model (indicator_context->indicator_manager);
  indicator_context->indicator_view = unity_webapps_indicator_manager_get_view (indicator_context->indicator_manager);
  
  g_signal_connect (indicator_context->indicator_manager,
		    "application-activated",
		    G_CALLBACK (unity_webapps_indicator_context_application_activated_callback),
		    indicator_context);

  g_signal_connect (indicator_context->indicator_manager,
		    "indicator-activated",
		    G_CALLBACK (unity_webapps_indicator_context_indicator_activated_callback),
		    indicator_context);
  
  export_object (connection, indicator_context);
  
  //  create_indicate_server (indicator_context);
  
  create_presence_manager (indicator_context);
  
  g_free (menu_dbus_path);
  
  return indicator_context;
}

void
unity_webapps_indicator_context_free (UnityWebappsIndicatorContext *indicator_context)
{
  UNITY_WEBAPPS_NOTE (INDICATOR, "Finalizing UnityWebappsIndicatorContext object");
  
  g_object_unref (G_OBJECT (indicator_context->indicator_service_interface));
  
  g_free (indicator_context->canonical_name);
  g_free (indicator_context->desktop_path);

  g_object_unref (G_OBJECT (indicator_context->connection));
  g_object_unref (G_OBJECT (indicator_context->presence_manager));
  
  g_object_unref (G_OBJECT (indicator_context->action_manager));
  g_object_unref (G_OBJECT (indicator_context->indicator_manager));

  g_free (indicator_context);
}
