/*
 * Cossa standalone applicaton
 *
 * ©2011 Carlos Garnacho <carlosg@gnome.org>
 *
 * 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"
#include "cossa-application.h"
#include "cossa-window.h"

typedef struct CossaApplicationPrivate CossaApplicationPrivate;
typedef struct WindowData WindowData;

struct WindowData {
  GtkWidget *window;
  GFile *file;
  GFileMonitor *monitor;
};

struct CossaApplicationPrivate
{
  GList *windows;
};

G_DEFINE_TYPE (CossaApplication, cossa_application, GTK_TYPE_APPLICATION)

static WindowData *
lookup_window_data_by_file (CossaApplication *application,
                            GFile            *file)
{
  CossaApplicationPrivate *priv = application->priv;
  GList *l;

  for (l = priv->windows; l; l = l->next)
    {
      WindowData *data = l->data;

      if (g_file_equal (file, data->file))
        return data;
    }

  return NULL;
}

static WindowData *
lookup_window_data (CossaApplication *application,
                    GtkWidget        *window)
{
  CossaApplicationPrivate *priv = application->priv;
  GList *l;

  for (l = priv->windows; l; l = l->next)
    {
      WindowData *data = l->data;

      if (window == data->window)
        return data;
    }

  return NULL;
}

static WindowData *
window_data_new (GFile *file)
{
  WindowData *data;
  gchar *name, *title;

  data = g_slice_new0 (WindowData);

  data->file = g_object_ref (file);
  data->window = cossa_window_new ();

  gtk_window_set_default_size (GTK_WINDOW (data->window), 400, 400);

  name = g_file_get_parse_name (file);
  title = g_strdup_printf ("Cossa - %s", name);
  g_free (name);

  gtk_window_set_title (GTK_WINDOW (data->window), title);
  g_free (title);

  /* Set up file monitor */
  data->monitor = g_file_monitor_file (file,
                                       G_FILE_MONITOR_NONE,
                                       NULL, NULL);
  return data;
}

static void
window_data_free (WindowData *data)
{
  gtk_widget_destroy (data->window);
  g_object_unref (data->file);

  g_file_monitor_cancel (data->monitor);
  g_object_unref (data->monitor);

  g_slice_free (WindowData, data);
}

static void
_cossa_application_update_window (CossaApplication *application,
                                  GFile            *file)
{
  CossaApplication *app;
  CossaPreviewer *preview;
  GtkCssProvider *style;
  WindowData *data;

  app = COSSA_APPLICATION (application);
  data = lookup_window_data_by_file (app, file);

  if (!data)
    return;

  preview = cossa_window_get_previewer (COSSA_WINDOW (data->window));
  style = cossa_previewer_get_style (COSSA_PREVIEWER (preview));

  if (gtk_css_provider_load_from_file (style, file, NULL))
    cossa_previewer_update_samples (preview);
}

static void
file_changed_cb (GFileMonitor      *monitor,
                 GFile             *file,
                 GFile             *other_file,
                 GFileMonitorEvent  event_type,
                 gpointer           user_data)
{
  if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
    _cossa_application_update_window (COSSA_APPLICATION (user_data), file);
}

static void
close_window_cb (GtkWidget *window,
                 GdkEvent  *event,
                 gpointer   user_data)
{
  CossaApplicationPrivate *priv;
  CossaApplication *app;
  WindowData *data;

  app = COSSA_APPLICATION (user_data);
  data = lookup_window_data (app, window);
  priv = app->priv;

  if (data)
    {
      priv->windows = g_list_remove (priv->windows, data);
      gtk_application_remove_window (GTK_APPLICATION (app),
                                     GTK_WINDOW (data->window));
      window_data_free (data);
    }
}

static void
cossa_application_open (GApplication  *application,
                        GFile        **files,
                        gint           n_files,
                        const gchar   *hint)
{
  CossaApplication *app;
  CossaApplicationPrivate *priv;
  gint i;

  app = COSSA_APPLICATION (application);
  priv = app->priv;

  for (i = 0; i < n_files; i++)
    {
      WindowData *data;
      GFile *file;

      file = files[i];
      data = lookup_window_data_by_file (app, file);

      if (!data)
        {
          data = window_data_new (file);
          priv->windows = g_list_prepend (priv->windows, data);

          g_signal_connect (data->window, "delete-event",
                            G_CALLBACK (close_window_cb), app);

          gtk_application_add_window (GTK_APPLICATION (application),
                                      GTK_WINDOW (data->window));

          if (data->monitor)
            {
              g_signal_connect (data->monitor, "changed",
                                G_CALLBACK (file_changed_cb),
                                application);
            }

          _cossa_application_update_window (app, file);
        }

      if (!gtk_widget_is_drawable (data->window))
        gtk_widget_show (data->window);
      else
        gtk_window_present (GTK_WINDOW (data->window));
    }
}

static void
cossa_application_activate (GApplication *application)
{
}

static void
cossa_application_class_init (CossaApplicationClass *klass)
{
  GApplicationClass *application_class = G_APPLICATION_CLASS (klass);

  application_class->open = cossa_application_open;
  application_class->activate = cossa_application_activate;

  g_type_class_add_private (klass, sizeof (CossaApplicationPrivate));
}

static void
cossa_application_init (CossaApplication *application)
{
  application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application,
                                                   COSSA_TYPE_APPLICATION,
                                                   CossaApplicationPrivate);
}

GApplication *
cossa_application_new (void)
{
  return g_object_new (COSSA_TYPE_APPLICATION,
                       "application-id", "org.gnome.Cossa",
                       "flags", G_APPLICATION_HANDLES_OPEN,
                       NULL);
}
