/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * webapps-spreader.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 <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <gtk/gtk.h>

#include <gdk/gdkx.h>

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

static UnityWebappsService *service = NULL;

static GMainLoop *mainloop = NULL;
static gchar *context_name = NULL;

static GOptionEntry option_entries[] =
	{
		{ "context-name", 'n',0,G_OPTION_ARG_STRING, &context_name, "Context DBus Name", NULL },
	};



static gboolean
parse_data_uri (const gchar *data_uri,
				gchar **mimetype,
				gchar **data)
{
  gchar **split;
  int result;
  
  g_assert (g_str_has_prefix (data_uri, "data:") == TRUE);

  split = g_strsplit (data_uri+5,
		      ";base64,",
		      2);

  result = g_strv_length (split);
  
  if (result != 2)
    {
      g_warning ("Failed to parse data uri: \n %s \n", data_uri);

      *mimetype = NULL;
      *data = NULL;
      
      g_strfreev (split);

      return FALSE;
    }
  
  *mimetype = split[0];
  *data = split[1];
  
  g_free (split);
  
  if (g_str_has_prefix (*mimetype, "image/") == FALSE)
    {
      g_warning ("Data URI does not have an image mimetype");

      g_free (mimetype);
      g_free (data);

      *mimetype = NULL;
      *data = NULL;
      
      return FALSE;
    }
  
  return TRUE;
}

static GdkPixbuf *
preview_image_from_data_uri (const gchar *data_uri)
{
  GdkPixbufLoader *loader;
  GdkPixbuf *pixbuf;
  gchar *mimetype, *data;
  guchar *decoded;
  gsize decoded_length;
  gboolean parsed, wrote;
  GError *error;

  mimetype = NULL;
  data = NULL;

  pixbuf = NULL;
  loader = NULL;
  
  parsed = parse_data_uri (data_uri, &mimetype, &data);
  
  if (parsed == FALSE)
	{
	  g_warning ("Failed to parse data uri");
	  return NULL;
	}
  
  decoded = g_base64_decode (data, &decoded_length);
  
  g_assert (decoded != NULL);
  
  loader = gdk_pixbuf_loader_new ();
  
  
  error = NULL;
  wrote = gdk_pixbuf_loader_write (loader, decoded,
								   decoded_length,
								   &error);
  if (wrote == FALSE)
	{
	  if (error == NULL)
		{
		  goto out;
		}
	  g_warning ("Failed to write data to GdkPixbuf: %s", error->message);
	  g_error_free (error);
	  
	  goto out;
	}
  
  error = NULL;

  if (error != NULL)
	{
	  g_warning("Failed to close pixbuf loader: %s", error->message);
	  g_error_free (error);
	  
	  goto out;
	}
  
  pixbuf = GDK_PIXBUF (g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)));  
  
  gdk_pixbuf_loader_close (loader, NULL); 
 out:  
  if (loader != NULL)
	{
	  g_object_unref (G_OBJECT (loader));
	}
  g_free (mimetype);
  g_free (data);
  g_free (decoded);
  
  return pixbuf;
}

static gchar *
get_preview_title (UnityWebappsContext *context,
				   gint interest_id)
{
  const gchar *app_name;
  gchar *view_location, *title;
  
  app_name = unity_webapps_context_get_name (context);
  view_location = unity_webapps_context_get_view_location (context, interest_id);
  
  title = g_strdup_printf("%s - (%s)", app_name, view_location);

  g_free (view_location);
  return title;
}

static void
create_preview_window (UnityWebappsContext *context,
					   gint interest_id,
					   GdkPixbuf *preview_pixbuf,
					   gint width,
					   gint height)
{
  GtkWidget *window, *image;
  GdkWindow *gdkwin;
  gchar *title;
  guint32 xid;
  
  window = gtk_window_new (GTK_WINDOW_POPUP);
  
  gtk_window_set_default_size (GTK_WINDOW (window), width, height);
  gtk_window_set_accept_focus (GTK_WINDOW (window), FALSE);
  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
  gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
  
  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_UTILITY);
  
  gtk_window_move (GTK_WINDOW (window), -10000, -10000);
  
  image = gtk_image_new_from_pixbuf (preview_pixbuf);
  
  gtk_container_add (GTK_CONTAINER (window), image);  
  
  title = get_preview_title (context, interest_id);
  gtk_window_set_title (GTK_WINDOW (window), title);
  
  gtk_widget_show_all (GTK_WIDGET (window));
  
  gdkwin = gtk_widget_get_window (GTK_WIDGET (window));
  
  xid = gdk_x11_window_get_xid (gdkwin);
  printf("%d - %u\n", interest_id, xid);
  
  g_free (title);
}


static void
preview_ready (UnityWebappsContext *context,
			   gint interest_id,
			   const gchar *preview_data,
			   gpointer user_data)
{
  GdkPixbuf *preview_pixbuf;
  gint width, height;
  
  preview_pixbuf = preview_image_from_data_uri (preview_data);
  
  if (preview_pixbuf == NULL)
	{
	  return;
	}
  
  width = gdk_pixbuf_get_width (preview_pixbuf);
  height = gdk_pixbuf_get_height (preview_pixbuf);
  
  create_preview_window (context, interest_id, preview_pixbuf, width, height);
  
  g_object_unref (G_OBJECT (preview_pixbuf));
}

static gboolean
spreader_request_previews (UnityWebappsContext *context)
{
  GVariant *interests, *interest_variant;
  GVariantIter *variant_iter;
  
  interests = unity_webapps_context_list_interests (context);
  
  if (interests == NULL)
	{
	  return FALSE;
	}

  variant_iter = g_variant_iter_new (interests);
  
  while ((interest_variant = g_variant_iter_next_value (variant_iter)))
	{
	  gint interest_id;
	  
	  interest_id = g_variant_get_int32 (interest_variant);
	  
	  unity_webapps_context_request_preview (context, interest_id, preview_ready, GINT_TO_POINTER (interest_id));
	}
  
  g_variant_iter_free (variant_iter);
  g_variant_unref (interests);
  
  return TRUE;
}

gint
main (gint argc, gchar **argv)
{
  GOptionContext *option_context;
  UnityWebappsContext *context; 
  GError *error;
  gboolean req;

  gtk_init (&argc, &argv);
  
  service = unity_webapps_service_new ();
  
  option_context = g_option_context_new ("- Create Preview Windows for Unity Webapps");
  
  // TODO: GETTEXT
  g_option_context_add_main_entries (option_context, option_entries, NULL);
  
  error = NULL;

  if (!g_option_context_parse (option_context, &argc, &argv, &error))
	{
	  g_error("Failed to parse arguments: %s", error->message);
	  exit(1);
	}

  context = unity_webapps_context_new_for_context_name (service, context_name);

  req = spreader_request_previews (context);
  
  if (req == FALSE)
	{
	  exit(1);
	}

  mainloop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (mainloop);
  
  exit (0);
  
}

