/*
 * unity-webapps-service.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/>.";
 */

/**
 * SECTION:unity-webapps-service
 * @short_description: Unity Webapps Service client bindings.
 *
 * Client bindings for the Unity Webapps Service daemon.
 */
#include <stdio.h>

#include <unistd.h>

#include "unity-webapps-service.h"
#include "unity-webapps-gen-service.h"

#include "unity-webapps-debug.h"

struct _UnityWebappsServicePrivate {
  GDBusConnection *connection;
  UnityWebappsGenService *service_proxy;
};

G_DEFINE_TYPE(UnityWebappsService, unity_webapps_service, G_TYPE_OBJECT)

#define UNITY_WEBAPPS_SERVICE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), UNITY_WEBAPPS_TYPE_SERVICE, UnityWebappsServicePrivate))

static void
unity_webapps_service_finalize (GObject *object)
{
  UnityWebappsService *service;
  
  service = UNITY_WEBAPPS_SERVICE (object);

  g_object_unref (G_OBJECT (service->priv->service_proxy));
  g_object_unref (G_OBJECT (service->priv->connection));
}

static void
unity_webapps_service_class_init (UnityWebappsServiceClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  
  object_class->finalize = unity_webapps_service_finalize;
  
  g_type_class_add_private (object_class, sizeof(UnityWebappsServicePrivate));
}

static void
unity_webapps_service_init (UnityWebappsService *service)
{
  GError *error;

  service->priv = UNITY_WEBAPPS_SERVICE_GET_PRIVATE (service);

#ifdef UNITY_WEBAPPS_ENABLE_DEBUG
  unity_webapps_debug_initialize_flags ();
#endif
  
  error = NULL;

  service->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
					 NULL /*Cancellable*/,
					 &error /*Error*/);
  
  if (error != NULL)
    {
      g_critical ("Failed to open session bus! %s", error->message);

      g_error_free (error);
      return;
    }
  
  service->priv->service_proxy = unity_webapps_gen_service_proxy_new_sync (service->priv->connection,
									     G_DBUS_PROXY_FLAGS_NONE,
									     UNITY_WEBAPPS_SERVICE_NAME,
									     UNITY_WEBAPPS_SERVICE_PATH,
									     NULL,
									     &error);
  
  if (error != NULL)
    {
      g_critical ("Failed to create service proxy. %s", error->message);
      g_error_free (error);
      
      return;
    }
}

/**
 * unity_webapps_service_new:
 *
 * Creates a new #UnityWebappsService proxy object. If 'com.canonical.Unity.Webapps.Service'
 * is unowned, the daemon will be started following method invocation by this proxy.
 *
 * Return value: (transfer full): The newly constructed #UnityWebappsService objec,tg
 */
UnityWebappsService *
unity_webapps_service_new ()
{
  return g_object_new (UNITY_WEBAPPS_TYPE_SERVICE, NULL);
}

/**
 * unity_webapps_service_get_connection:
 * @service: A #UnityWebappsService object.
 *
 * Returns the #GDBusConnection used by @service.
 *
 * Return value: (transfer none): The #GDBusConnection used by @service.
 */
GDBusConnection *
unity_webapps_service_get_connection (UnityWebappsService *service)
{
  return service->priv->connection;
}

/**
 * unity_webapps_service_get_proxy:
 * @service: A #UnityWebappsService object.
 *
 * Returns the internal #GDBusProxy used by @service.
 *
 * Return value: (transfer none): The #GDBusProxy used by @service.
 */
GDBusProxy *
unity_webapps_service_get_proxy (UnityWebappsService *service)
{
  return G_DBUS_PROXY (service->priv->service_proxy);
}

void
unity_webapps_service_open_homepage_sync (UnityWebappsService *service,
					  const gchar *homepage)
{
  GError *error;
  
  g_return_if_fail (UNITY_WEBAPPS_IS_SERVICE (service));
  g_return_if_fail (homepage != NULL);
  
  error = NULL;
  
  unity_webapps_gen_service_call_open_homepage_sync (service->priv->service_proxy, homepage, NULL, &error);
  
  if (error != NULL)
    {
      g_warning ("Failure calling OpenHomepage (%s): %s", homepage,
		 error->message);
      g_error_free (error);
    }
}

/**
 * unity_webapps_service_activate_application:
 * @service: A #UnityWebappsService object.
 * @name: Application name.
 * @domain: Applicatoin domain.
 *
 * Invokes the ActivateApplication method of the UnityWebappsService object. This will
 * activate the application uniquely idenfied by the pair (@name, @domain).
 */
void
unity_webapps_service_activate_application (UnityWebappsService *service, 
					    const gchar *name, 
					    const gchar *domain,
                                            const gchar *const *files)
{
  GError *error;

  g_return_if_fail (service != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_SERVICE (service));
  g_return_if_fail (name != NULL);
  g_return_if_fail (domain != NULL);
  
  error = NULL;

  unity_webapps_gen_service_call_activate_application_sync (service->priv->service_proxy, name, domain, files, NULL, &error);
  
  if (error != NULL)
    {
      g_warning ("Failure calling ActivateApplication (%s,%s): %s", name, domain, error->message);
      g_error_free (error);
      
      return;
    }
  
}

typedef struct _unity_webapps_service_notify_data {
  gpointer user_data;
  UnityWebappsServiceContextNotifyCallback callback;
  UnityWebappsService *service;
} unity_webapps_service_notify_data;

static void
on_notify_context_appeared (UnityWebappsGenService *gen_service,
			    const gchar *name,
			    gpointer user_data)
{
  unity_webapps_service_notify_data *data;
  
  data = (unity_webapps_service_notify_data *)user_data;
  
  data->callback(data->service, name, data->user_data);
}

/**
 * unity_webapps_service_on_context_appeared:
 * @service: A #UnityWebappsService object.
 * @callback: A callback to be invoked when a new context is registered with @service.
 * @user_data: User supplied data to be passed to @callback.
 *
 * Registers @callback to be invoked when the "ContextAppeared" signal is emitted from the 
 * remote service instance. This indicates a new application context has come online.
 */
void
unity_webapps_service_on_context_appeared (UnityWebappsService *service,
					   UnityWebappsServiceContextNotifyCallback callback,
					   gpointer user_data)
{
  unity_webapps_service_notify_data *data;
  
  g_return_if_fail (service != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_SERVICE (service));
  g_return_if_fail (callback != NULL);
  
  data = g_malloc0 (sizeof (unity_webapps_service_notify_data));
  data->user_data = user_data;
  data->callback = callback;
  data->service = service;
  
  g_signal_connect (service->priv->service_proxy,
		    "context-appeared",
		    G_CALLBACK (on_notify_context_appeared),
		    data);
}



static void
on_notify_context_vanished (UnityWebappsGenService *gen_service,
			    const gchar *name,
			    gpointer user_data)
{
  unity_webapps_service_notify_data *data;
  
  data = (unity_webapps_service_notify_data *)user_data;
  
  data->callback(data->service, name, data->user_data);
}

/**
 * unity_webapps_service_on_context_vanished:
 * @service: A #UnityWebappsService object.
 * @callback: A callback to be invoked when a new context is registered with @service.
 * @user_data: User supplied data to be passed to @callback.
 *
 * Registers @callback to be invoked when the "ContextVanished" signal is emitted from the 
 * remote service instance. This indicates an application context has gone offline.
 */
void
unity_webapps_service_on_context_vanished (UnityWebappsService *service,
					   UnityWebappsServiceContextNotifyCallback callback,
					   gpointer user_data)
{
  unity_webapps_service_notify_data *data;
  
  g_return_if_fail (service != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_SERVICE (service));
  g_return_if_fail (callback != NULL);
  
  data = g_malloc0 (sizeof (unity_webapps_service_notify_data));
  data->user_data = user_data;
  data->callback = callback;
  data->service = service;
  
  g_signal_connect (service->priv->service_proxy,
		    "context-vanished",
		    G_CALLBACK (on_notify_context_vanished),
		    data);
}

/**
 * unity_webapps_service_list_contexts:
 * @service: A #UnityWebappsService object.
 *
 * Returns a list of context names (unique DBus names), registered with the remote
 * service.
 *
 * Return value: (transfer full): A list of context names.
 */
gchar **
unity_webapps_service_list_contexts (UnityWebappsService *service)
{
  gchar **out_contexts;
  GError *error;
  
  g_return_val_if_fail (service != NULL, NULL);
  g_return_val_if_fail (UNITY_WEBAPPS_IS_SERVICE (service), NULL);
  
  error = NULL;
  
  unity_webapps_gen_service_call_list_contexts_sync (service->priv->service_proxy,
						     &out_contexts,
						     NULL /* Cancellable */,
						     &error);
  
  if (error != NULL)
    {
      g_warning ("Failure calling ListContexts: %s", error->message);
      g_error_free (error);
      
      return NULL;
    }
  
  return out_contexts;
}

#include "unity-webapps-context.h" 

/**
 * WARNING: this is only kept part of the "ABI"
 * so that ufe still works (jsctypes still tried to bind with it).
 * Should be removed ASAP ufe is released.
 */
void
unity_webapps_service_set_xid_for_browser_window_id (UnityWebappsService *service,
						     UnityWebappsContext *context,
						     int window_id)
{
  g_warning("unity_webapps_service_set_xid_for_browser_window_id: called but empty");
}

void 
unity_webapps_service_shutdown (UnityWebappsService *service)
{
  GError *error;

  g_return_if_fail (UNITY_WEBAPPS_IS_SERVICE (service));
  
  error = NULL;
  
  unity_webapps_gen_service_call_shutdown_sync (service->priv->service_proxy,
						NULL /* Cancellable */,
						&error);
  
  if (error != NULL)
    {
      g_warning ("Failure calling service Shutdown: %s", error->message);
      g_error_free (error);
    }
  
  return;  
}


void
unity_webapps_service_destroy_interest_for_context (UnityWebappsService *service,
                                                    const gchar *name,
                                                    const gchar *domain,
                                                    gint interest_id,
                                                    gboolean abandoned)
{
  GError *error;
  g_return_if_fail (UNITY_WEBAPPS_IS_SERVICE (service));

  error = NULL;

  unity_webapps_gen_service_call_destroy_interest_for_context_sync (service->priv->service_proxy,
                                                                    name, domain,
                                                                    interest_id,
                                                                    abandoned,
                                                                    NULL /* Cancellable */,
                                                                    &error);
  if (error != NULL)
    {
      g_critical ("Failure calling service DestroyInterestForContext: %s"
                  , error->message != NULL ? error->message : "(Unknown)");
      g_error_free (error);
    }

  return;  
}
