/*
 * Photos - access, organize and share your photos on GNOME
 * Copyright © 2012, 2013 Red Hat, Inc.
 *
 * 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
 * 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.
 */

/* Based on code from:
 *   + Documents
 */


#include "config.h"

#include <glib.h>
#include <glib/gi18n.h>

#include "photos-about-data.h"
#include "photos-embed.h"
#include "photos-item-manager.h"
#include "photos-main-window.h"
#include "photos-mode-controller.h"
#include "photos-settings.h"


struct _PhotosMainWindowPrivate
{
  GtkWidget *embed;
  GSettings *settings;
  PhotosBaseManager *item_mngr;
  PhotosModeController *controller;
  guint configure_id;
};


G_DEFINE_TYPE_WITH_PRIVATE (PhotosMainWindow, photos_main_window, GTK_TYPE_APPLICATION_WINDOW);


enum
{
  CONFIGURE_ID_TIMEOUT = 100, /* ms */
  WINDOW_MIN_HEIGHT = 600,
  WINDOW_MIN_WIDTH = 640,
};


static void
photos_main_window_save_geometry (PhotosMainWindow *self)
{
  PhotosMainWindowPrivate *priv = self->priv;
  GVariant *variant;
  GdkWindow *window;
  GdkWindowState state;
  gint32 position[2];
  gint32 size[2];

  window = gtk_widget_get_window (GTK_WIDGET (self));
  state = gdk_window_get_state (window);
  if (state & GDK_WINDOW_STATE_MAXIMIZED)
    return;

  gtk_window_get_size (GTK_WINDOW (self), (gint *) &size[0], (gint *) &size[1]);
  variant = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, size, 2, sizeof (size[0]));
  g_settings_set_value (priv->settings, "window-size", variant);

  gtk_window_get_position (GTK_WINDOW (self), (gint *) &position[0], (gint *) &position[1]);
  variant = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, position, 2, sizeof (position[0]));
  g_settings_set_value (priv->settings, "window-position", variant);
}


static gboolean
photos_main_window_configure_id_timeout (gpointer user_data)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (user_data);

  photos_main_window_save_geometry (self);
  return G_SOURCE_REMOVE;
}


static gboolean
photos_main_window_configure_event (GtkWidget *widget, GdkEventConfigure *event)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (widget);
  PhotosMainWindowPrivate *priv = self->priv;
  gboolean ret_val;

  ret_val = GTK_WIDGET_CLASS (photos_main_window_parent_class)->configure_event (widget, event);

  if (photos_mode_controller_get_fullscreen (priv->controller))
    return ret_val;

  if (priv->configure_id != 0)
    {
      g_source_remove (priv->configure_id);
      priv->configure_id = 0;
    }

  priv->configure_id = g_timeout_add (CONFIGURE_ID_TIMEOUT, photos_main_window_configure_id_timeout, self);
  return ret_val;
}


static gboolean
photos_main_window_delete_event (GtkWidget *widget, GdkEventAny *event)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (widget);
  PhotosMainWindowPrivate *priv = self->priv;

  if (priv->configure_id != 0)
    {
      g_source_remove (priv->configure_id);
      priv->configure_id = 0;
    }

  photos_main_window_save_geometry (self);
  return GDK_EVENT_PROPAGATE;
}


static void
photos_main_window_fullscreen_changed (PhotosModeController *controller, gboolean fullscreen, gpointer user_data)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (user_data);

  if (fullscreen)
    gtk_window_fullscreen (GTK_WINDOW (self));
  else
    gtk_window_unfullscreen (GTK_WINDOW (self));
}


static gboolean
photos_main_window_handle_key_overview (PhotosMainWindow *self, GdkEventKey *event)
{
  return GDK_EVENT_PROPAGATE;
}


static gboolean
photos_main_window_handle_key_preview (PhotosMainWindow *self, GdkEventKey *event)
{
  PhotosMainWindowPrivate *priv = self->priv;
  GtkTextDirection direction;
  gboolean fullscreen;

  direction = gtk_widget_get_direction (GTK_WIDGET (self));
  fullscreen = photos_mode_controller_get_fullscreen (priv->controller);

  if ((fullscreen && event->keyval == GDK_KEY_Escape)
      || ((event->state & GDK_MOD1_MASK) != 0
          && ((direction == GTK_TEXT_DIR_LTR && event->keyval == GDK_KEY_Left)
              || (direction == GTK_TEXT_DIR_RTL && event->keyval == GDK_KEY_Right)))
      || event->keyval == GDK_KEY_BackSpace
      || event->keyval == GDK_KEY_Back)
    {
      photos_base_manager_set_active_object (priv->item_mngr, NULL);
      return GDK_EVENT_STOP;
    }

  return GDK_EVENT_PROPAGATE;
}


static gboolean
photos_main_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (widget);
  PhotosMainWindowPrivate *priv = self->priv;
  PhotosWindowMode mode;
  gboolean handled;

  mode = photos_mode_controller_get_window_mode (priv->controller);
  if (mode == PHOTOS_WINDOW_MODE_PREVIEW)
    handled = photos_main_window_handle_key_preview (self, event);
  else
    handled = photos_main_window_handle_key_overview (self, event);

  if (!handled)
    handled = GTK_WIDGET_CLASS (photos_main_window_parent_class)->key_press_event (widget, event);

  return handled;
}


static gboolean
photos_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (widget);
  GdkWindow *window;
  GdkWindowState state;
  gboolean maximized;
  gboolean ret_val;

  ret_val = GTK_WIDGET_CLASS (photos_main_window_parent_class)->window_state_event (widget, event);

  window = gtk_widget_get_window (widget);
  state = gdk_window_get_state (window);

  if (state & GDK_WINDOW_STATE_FULLSCREEN)
    return ret_val;

  maximized = (state & GDK_WINDOW_STATE_MAXIMIZED);
  g_settings_set_boolean (self->priv->settings, "window-maximized", maximized);

  return ret_val;
}


static void
photos_main_window_dispose (GObject *object)
{
  PhotosMainWindow *self = PHOTOS_MAIN_WINDOW (object);
  PhotosMainWindowPrivate *priv = self->priv;

  g_clear_object (&priv->settings);
  g_clear_object (&priv->item_mngr);
  g_clear_object (&priv->controller);

  if (priv->configure_id != 0)
    {
      g_source_remove (priv->configure_id);
      priv->configure_id = 0;
    }

  G_OBJECT_CLASS (photos_main_window_parent_class)->dispose (object);
}


static void
photos_main_window_init (PhotosMainWindow *self)
{
  PhotosMainWindowPrivate *priv;
  GVariant *variant;
  gboolean maximized;
  const gint32 *position;
  const gint32 *size;
  gsize n_elements;

  self->priv = photos_main_window_get_instance_private (self);
  priv = self->priv;

  priv->settings = photos_settings_new ();

  variant = g_settings_get_value (priv->settings, "window-size");
  size = g_variant_get_fixed_array (variant, &n_elements, sizeof (gint32));
  if (n_elements == 2)
    gtk_window_set_default_size (GTK_WINDOW (self), size[0], size[1]);
  g_variant_unref (variant);

  variant = g_settings_get_value (priv->settings, "window-position");
  position = g_variant_get_fixed_array (variant, &n_elements, sizeof (gint32));
  if (n_elements == 2)
    gtk_window_move (GTK_WINDOW (self), position[0], position[1]);
  g_variant_unref (variant);

  maximized = g_settings_get_boolean (priv->settings, "window-maximized");
  if (maximized)
    gtk_window_maximize (GTK_WINDOW (self));

  priv->item_mngr = photos_item_manager_dup_singleton ();

  priv->controller = photos_mode_controller_dup_singleton ();
  g_signal_connect (priv->controller,
                    "fullscreen-changed",
                    G_CALLBACK (photos_main_window_fullscreen_changed),
                    self);

  priv->embed = photos_embed_new ();
  gtk_container_add (GTK_CONTAINER (self), priv->embed);
}


static void
photos_main_window_class_init (PhotosMainWindowClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);

  object_class->dispose = photos_main_window_dispose;
  widget_class->configure_event = photos_main_window_configure_event;
  widget_class->delete_event = photos_main_window_delete_event;
  widget_class->key_press_event = photos_main_window_key_press_event;
  widget_class->window_state_event = photos_main_window_window_state_event;
}


GtkWidget *
photos_main_window_new (GtkApplication *application)
{
  g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);

  return g_object_new (PHOTOS_TYPE_MAIN_WINDOW,
                       "width_request", WINDOW_MIN_WIDTH,
                       "height_request", WINDOW_MIN_HEIGHT,
                       "application", application,
                       "title", _(PACKAGE_NAME),
                       "window-position", GTK_WIN_POS_CENTER,
                       NULL);
}


void
photos_main_window_show_about (PhotosMainWindow *self)
{
  GtkWidget *about_dialog;

  about_dialog = gtk_about_dialog_new ();
  gtk_window_set_modal (GTK_WINDOW (about_dialog), TRUE);
  gtk_window_set_transient_for (GTK_WINDOW (about_dialog), GTK_WINDOW (self));

  gtk_about_dialog_set_artists (GTK_ABOUT_DIALOG (about_dialog), PHOTOS_ARTISTS);
  gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (about_dialog), PHOTOS_AUTHORS);
  gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (about_dialog),
                                 _("Access, organize and share your photos on GNOME"));
  gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (about_dialog), "Copyright © 2012, 2013 Red Hat, Inc.");
  gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (about_dialog), GTK_LICENSE_GPL_2_0);
  gtk_about_dialog_set_logo_icon_name (GTK_ABOUT_DIALOG (about_dialog), PACKAGE_TARNAME);
  gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG (about_dialog), _(PACKAGE_NAME));
  gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (about_dialog), _(PACKAGE_VERSION));
  gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (about_dialog), PACKAGE_URL);
  gtk_about_dialog_set_wrap_license (GTK_ABOUT_DIALOG (about_dialog), TRUE);

  /* Translators: Put your names here */
  gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (about_dialog), _("translator-credits"));

  gtk_widget_show (about_dialog);
  g_signal_connect (about_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
}
