/* OGMRip - A DVD Encoder for GNOME
 * Copyright (C) 2004-2012 Olivier Rolland <billl@users.sourceforge.net>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "ogmdvd.h"
#include "ogmdvd-gtk.h"
#include "ogmrip.h"

#include "ogmrip-gconf.h"
#include "ogmrip-helper.h"
#include "ogmrip-lavc.h"
#include "ogmrip-profiles.h"

#include "ogmrip-crop-dialog.h"
#include "ogmrip-options-dialog.h"
#include "ogmrip-profiles-dialog.h"

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

#include <string.h>

#define OGMRIP_GLADE_FILE "ogmrip" G_DIR_SEPARATOR_S "ogmrip-options.glade"
#define OGMRIP_GLADE_ROOT "root"

#define ROUND(x) ((gint) ((x) + 0.5) != (gint) (x) ? ((gint) ((x) + 0.5)) : ((gint) (x)))

#define OGMRIP_OPTIONS_DIALOG_GET_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), OGMRIP_TYPE_OPTIONS_DIALOG, OGMRipOptionsDialogPriv))

enum
{
  COL_NAME,
  COL_SECTION,
  COL_LAST
};

enum
{
  PROFILE_CHANGED,
  EDIT_CLICKED,
  LAST_SIGNAL
};

enum
{
  PROP_0,
  PROP_ACTION
};

enum
{
  OGMRIP_SCALE_NONE,
  OGMRIP_SCALE_XSMALL,
  OGMRIP_SCALE_SMALL,
  OGMRIP_SCALE_MEDIUM,
  OGMRIP_SCALE_LARGE,
  OGMRIP_SCALE_XLARGE,
  OGMRIP_SCALE_FULL,
  OGMRIP_SCALE_USER,
  OGMRIP_SCALE_AUTOMATIC
};

struct _OGMRipOptionsDialogPriv
{
  OGMRipOptionsDialogAction action;

  GtkWidget *profile_combo;
  GtkWidget *edit_button;

  GtkWidget *crop_box;
  GtkWidget *crop_check;
  GtkWidget *crop_left_label;
  GtkWidget *crop_right_label;
  GtkWidget *crop_top_label;
  GtkWidget *crop_bottom_label;
  GtkWidget *autocrop_button;
  GtkWidget *crop_button;
  gint crop_type;

  GtkWidget *scale_box;
  GtkWidget *scale_check;
  GtkWidget *scale_combo;
  GtkWidget *scale_user_hbox;
  GtkWidget *scale_width_spin;
  GtkWidget *scale_height_spin;
  GtkWidget *autoscale_button;
  GtkListStore *scale_store;
  gint scale_type;

  GtkWidget *test_check;
  GtkWidget *test_button;

  GtkWidget *cartoon_check;
  GtkWidget *deint_check;

  gboolean is_autocropped;
  gboolean is_autoscaled;

  OGMRipEncoding *encoding;
  guint raw_width, raw_height;
  guint aspect_num, aspect_denom;
};

static GObject * ogmrip_options_dialog_constructor           (GType                 type,
                                                              guint                 nprops,
                                                              GObjectConstructParam *props);
static void      ogmrip_options_dialog_get_property          (GObject               *gobject,
                                                              guint                 property_id,
                                                              GValue                *value,
                                                              GParamSpec            *pspec);
static void      ogmrip_options_dialog_set_property          (GObject               *gobject,
                                                              guint                 property_id,
                                                              const GValue          *value,
                                                              GParamSpec            *pspec);
static void      ogmrip_options_dialog_dispose               (GObject               *gobject);

static void      ogmrip_options_dialog_set_encoding_internal (OGMRipOptionsDialog   *dialog,
                                                              OGMRipEncoding        *encoding,
                                                              gboolean              force);
static gint      ogmrip_options_dialog_get_scale_internal    (OGMRipOptionsDialog   *dialog,
                                                              guint                 *width,
                                                              guint                 *height);
static void      ogmrip_options_dialog_set_scale_internal    (OGMRipOptionsDialog   *dialog,
                                                              gint                  type,
                                                              gint                  width,
                                                              gint                  height);
static gint      ogmrip_options_dialog_get_crop_internal     (OGMRipOptionsDialog   *dialog,
                                                              guint                 *left,
                                                              guint                 *top,
                                                              guint                 *right,
                                                              guint                 *bottom);
static void      ogmrip_options_dialog_set_crop_internal     (OGMRipOptionsDialog   *dialog,
                                                              gint                  type,
                                                              gint                  left,
                                                              gint                  top,
                                                              gint                  right,
                                                              gint                  bottom);

static int signals[LAST_SIGNAL] = { 0 };

extern OGMRipSettings *settings;

static void
ogmrip_options_dialog_scale (guint size, gdouble aspect, guint *width, guint *height)
{
  const struct { guint mult; guint div; } table[] =
  {
    { 0, 0 }, { 1, 8 }, { 1, 4 }, { 1, 2 }, { 3, 4 }, { 5, 6 }, { 1, 1 }
  };

  g_return_if_fail (size != 0);

  *width = *width * table[size].mult / table[size].div;
  *width += *width % 2;

  *width = 16 * ROUND (*width / 16.);
  *height = 16 * ROUND (*width / aspect / 16);
}

static gdouble
ogmrip_options_dialog_get_aspect (OGMRipOptionsDialog *dialog, guint crop_width, guint crop_height)
{
  if (dialog->priv->raw_width > 0 && dialog->priv->raw_height > 0)
    return crop_width / (gdouble) crop_height *
      dialog->priv->raw_height / dialog->priv->raw_width *
      dialog->priv->aspect_num / dialog->priv->aspect_denom;

  return 1.0;
}

static void
ogmrip_options_dialog_update_scale_combo (OGMRipOptionsDialog *dialog)
{
  GtkTreeIter iter;
  guint scale_width, scale_height;
  guint crop_width, crop_height;
  gfloat aspect;
  gchar text[16];
  gint i, active;

  ogmrip_options_dialog_get_crop (dialog, NULL, NULL, &crop_width, &crop_height);
  aspect = ogmrip_options_dialog_get_aspect (dialog, crop_width, crop_height);

  gtk_spin_button_set_range (GTK_SPIN_BUTTON (dialog->priv->scale_width_spin), 0, crop_width);
  gtk_spin_button_set_range (GTK_SPIN_BUTTON (dialog->priv->scale_height_spin), 0, crop_height);

  active = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->scale_combo));

  for (i = 1; i < OGMRIP_SCALE_USER; i++)
  {
    if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (dialog->priv->scale_store), &iter, NULL, i))
    {
      scale_width = crop_width;
      scale_height = crop_height;

      ogmrip_options_dialog_scale (i, aspect, &scale_width, &scale_height);

      snprintf (text, 16, "%u x %u", scale_width, scale_height);
      gtk_list_store_set (dialog->priv->scale_store, &iter, 1, text, -1);

      if (active == i)
        ogmrip_options_dialog_set_scale_internal (dialog, -1, scale_width, scale_height);
    }
  }
}

static gboolean
ogmrip_options_dialog_combo_get_profile_iter (GtkTreeModel *model, GtkTreeIter *iter, const gchar *section)
{
  gboolean found = FALSE;

  if (gtk_tree_model_iter_children (model, iter, NULL))
  {
    gchar *str;

    do
    {
      gtk_tree_model_get (model, iter, COL_SECTION, &str, -1);
      if (g_str_equal (section, str))
        found = TRUE;
      g_free (str);
    }
    while (!found && gtk_tree_model_iter_next (model, iter));
  }

  return found;
}

static gint
ogmrip_options_dialog_compare_profiles (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, OGMRipProfilesDialog *dialog)
{
  gchar *aname, *bname;
  gint ret;

  gtk_tree_model_get (model, a, COL_NAME, &aname, -1);
  gtk_tree_model_get (model, b, COL_NAME, &bname, -1);

  ret = g_utf8_collate (aname, bname);

  g_free (aname);
  g_free (bname);

  return ret;
}

static void
ogmrip_options_dialog_construct_profiles_combo (OGMRipOptionsDialog *dialog, GtkWidget *combo)
{
  GtkListStore *store;
  GtkCellRenderer *cell;

  store = gtk_list_store_new (COL_LAST, G_TYPE_STRING, G_TYPE_STRING);
  gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
  g_object_unref (store);

  cell = gtk_cell_renderer_text_new ();
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell, "markup", COL_NAME, NULL);

  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), COL_NAME,
      (GtkTreeIterCompareFunc) ogmrip_options_dialog_compare_profiles, dialog, NULL);
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
      COL_NAME, GTK_SORT_ASCENDING);
}

static void
ogmrip_options_dialog_profile_get_value (GObject *combo, const gchar *property, GValue *value, gpointer data)
{
  GtkTreeModel *model;
  GtkTreeIter iter;
  
  const gchar *profile;
  gchar *section;

  if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
    return;

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
  if (!model)
    return;

  gtk_tree_model_get (model, &iter, COL_SECTION, &section, -1);
  profile = ogmrip_settings_get_section_name (settings, section);
  if (profile)
    g_value_set_string (value, profile);
  g_free (section);
}

static void
ogmrip_options_dialog_profile_set_value (GObject *combo, const gchar *property, const GValue *value, gpointer data)
{
  GtkTreeModel *model;
  GtkTreeIter iter;
  const gchar *section;

  section = ogmrip_settings_build_section (settings, OGMRIP_GCONF_PROFILES, g_value_get_string (value), NULL);

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
  if (ogmrip_options_dialog_combo_get_profile_iter (model, &iter, section))
    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
  else
    gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
}

static void
ogmrip_options_dialog_profile_combo_changed (OGMRipOptionsDialog *dialog)
{
  GType codec;
  gboolean can_crop, can_scale;
  gchar *section;
  gint method;

  section = ogmrip_options_dialog_get_active_profile (dialog);
  if (section)
  {
    ogmrip_settings_get (settings, section,
        OGMRIP_GCONF_VIDEO_CAN_SCALE, &can_scale,
        OGMRIP_GCONF_VIDEO_CAN_CROP, &can_crop,
        OGMRIP_GCONF_VIDEO_ENCODING, &method,
        NULL);

    codec = ogmrip_gconf_get_video_codec_type (section, NULL);

    gtk_widget_set_sensitive (dialog->priv->crop_check, can_crop && codec != G_TYPE_NONE);
    if (!can_crop || codec == G_TYPE_NONE)
      ogmrip_options_dialog_set_crop_internal (dialog, -1, -1, -1, -1, -1);
    gtk_widget_set_sensitive (dialog->priv->crop_box, can_crop && codec != G_TYPE_NONE);

    gtk_widget_set_sensitive (dialog->priv->scale_check, can_scale && codec != G_TYPE_NONE);
    if (!can_scale || codec == G_TYPE_NONE)
      ogmrip_options_dialog_set_scale_internal (dialog, -1, -1, -1);
    gtk_widget_set_sensitive (dialog->priv->scale_box, can_scale && codec != G_TYPE_NONE);

    gtk_widget_set_sensitive (dialog->priv->test_check, can_scale && codec != G_TYPE_NONE && method != OGMRIP_ENCODING_QUANTIZER);
    if (!can_scale || codec == G_TYPE_NONE || method == OGMRIP_ENCODING_QUANTIZER)
      ogmrip_options_dialog_set_test (dialog, FALSE);
    gtk_widget_set_sensitive (dialog->priv->test_button, can_scale && codec != G_TYPE_NONE && method != OGMRIP_ENCODING_QUANTIZER);

    gtk_widget_set_sensitive (dialog->priv->cartoon_check, codec != G_TYPE_NONE);
    gtk_widget_set_sensitive (dialog->priv->deint_check, codec != G_TYPE_NONE);

    if (dialog->priv->encoding)
      ogmrip_encoding_set_profile (dialog->priv->encoding, section);

    g_signal_emit (dialog, signals[PROFILE_CHANGED], 0);
  }
}

static void
ogmrip_options_dialog_edit_profiles_button_clicked (OGMRipOptionsDialog *dialog)
{
  g_signal_emit (dialog, signals[EDIT_CLICKED], 0);
}

static void
ogmrip_options_dialog_check_untoggled (GtkWidget *check, GtkWidget *widget)
{
  gboolean active;
  
  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check));

  g_object_set (G_OBJECT (widget), "visible", !active, "sensitive", !active, NULL);
}

static void
ogmrip_options_dialog_crop_check_toggled (OGMRipOptionsDialog *dialog)
{
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->crop_check)))
    ogmrip_options_dialog_set_crop_internal (dialog, OGMRIP_OPTIONS_AUTOMATIC, -1, -1, -1, -1);
  else
  {
    guint left, top, right, bottom;

    ogmrip_options_dialog_get_crop_internal (dialog, &left, &top, &right, &bottom);
    if (!left && !top && !right && !bottom)
      ogmrip_options_dialog_set_crop_internal (dialog, OGMRIP_OPTIONS_NONE, -1, -1, -1, -1);
    else
      ogmrip_options_dialog_set_crop_internal (dialog, OGMRIP_OPTIONS_MANUAL, -1, -1, -1, -1);
  }
}

static void
ogmrip_options_dialog_crop_button_clicked (OGMRipOptionsDialog *options)
{
  OGMDvdTitle *title;
  GtkWidget *dialog;

  g_assert (options->priv->encoding != NULL);

  title = ogmrip_encoding_get_title (options->priv->encoding);
  g_assert (title != NULL);

  if (!ogmdvd_title_open (title, NULL))
  {
    OGMDvdDisc *disc;
    gint response;

    disc = ogmdvd_title_get_disc (title);

    dialog = ogmrip_load_dvd_dialog_new (GTK_WINDOW (options), disc,
        ogmdvd_disc_get_label (disc), TRUE);
    response = gtk_dialog_run (GTK_DIALOG (dialog));
    gtk_widget_destroy (dialog);

    if (response == GTK_RESPONSE_ACCEPT)
      ogmdvd_title_open (title, NULL);
  }

  if (ogmdvd_title_is_open (title))
  {
    guint left, top, right, bottom;

    ogmrip_options_dialog_get_crop_internal (options, &left, &top, &right, &bottom);
    dialog = ogmrip_crop_dialog_new (title, left, top, right, bottom);

    g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_true), NULL);
    g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_hide), NULL);

    ogmrip_crop_dialog_set_deinterlacer (OGMRIP_CROP_DIALOG (dialog),
        ogmrip_options_dialog_get_deinterlacer (options));

    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
    {
      ogmrip_crop_dialog_get_crop (OGMRIP_CROP_DIALOG (dialog), &left, &top, &right, &bottom);
      ogmrip_options_dialog_set_crop_internal (options, OGMRIP_OPTIONS_MANUAL, left, top, right, bottom);
    }
    gtk_widget_destroy (dialog);

    ogmdvd_title_close (title);
  }
}

static void
ogmrip_options_dialog_autocrop_button_clicked (OGMRipOptionsDialog *options)
{
  GType video_codec;
  const gchar *profile;

  OGMDvdTitle *title;
  GtkWidget *dialog;

  g_assert (options->priv->encoding != NULL);

  profile = ogmrip_encoding_get_profile (options->priv->encoding);
  if (profile)
    video_codec = ogmrip_gconf_get_video_codec_type (profile, NULL);
  else
    video_codec = ogmrip_plugin_get_nth_video_codec (0);

  g_assert (video_codec != G_TYPE_NONE);

  title = ogmrip_encoding_get_title (options->priv->encoding);
  g_assert (title != NULL);

  if (!ogmdvd_title_open (title, NULL))
  {
    OGMDvdDisc *disc;
    gint response;

    disc = ogmdvd_title_get_disc (title);

    dialog = ogmrip_load_dvd_dialog_new (GTK_WINDOW (options), disc,
        ogmdvd_disc_get_label (disc), TRUE);
    response = gtk_dialog_run (GTK_DIALOG (dialog));
    gtk_widget_destroy (dialog);

    if (response == GTK_RESPONSE_ACCEPT)
      ogmdvd_title_open (title, NULL);
  }

  if (ogmdvd_title_is_open (title))
  {
    OGMJobSpawn *spawn;

    guint x, y, w, h;

    dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (options), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
        GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, "<b>%s</b>\n\n%s", _("Detecting cropping parameters"), _("Please wait"));
    // gtk_label_set_selectable (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label), FALSE);

    gtk_window_set_icon_from_stock (GTK_WINDOW (dialog), GTK_STOCK_DIALOG_INFO);
    gtk_widget_show (dialog);

    spawn = g_object_new (video_codec, "input", title, NULL);

    if (ogmrip_options_dialog_get_deinterlacer (options))
      ogmrip_video_codec_set_deinterlacer (OGMRIP_VIDEO_CODEC (spawn), OGMRIP_DEINT_YADIF);
    else
      ogmrip_video_codec_set_deinterlacer (OGMRIP_VIDEO_CODEC (spawn), OGMRIP_DEINT_NONE);

    ogmrip_video_codec_autocrop (OGMRIP_VIDEO_CODEC (spawn), 0);
    ogmrip_video_codec_get_crop_size (OGMRIP_VIDEO_CODEC (spawn), &x, &y, &w, &h);
    g_object_unref (spawn);

    gtk_widget_destroy (dialog);

    if (w == 0)
      w = options->priv->raw_width;

    if (h == 0)
      h = options->priv->raw_height;

    options->priv->is_autocropped = TRUE;
    ogmrip_options_dialog_set_crop (options, OGMRIP_OPTIONS_MANUAL, x, y, w, h);

    ogmdvd_title_close (title);
  }
}

static void
ogmrip_options_dialog_scale_check_toggled (OGMRipOptionsDialog *dialog)
{
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->scale_check)))
    ogmrip_options_dialog_set_scale_internal (dialog, OGMRIP_SCALE_AUTOMATIC, -1, -1);
  else
  {
    gint active;

    active = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->scale_combo));
    ogmrip_options_dialog_set_scale_internal (dialog, active, -1, -1);
  }
}

static void
ogmrip_options_dialog_scale_check_after_toggled (OGMRipOptionsDialog *dialog)
{
  gchar *profile;

  profile = ogmrip_options_dialog_get_active_profile (dialog);
  if (profile)
  {
    gint method;

    ogmrip_settings_get (settings, profile,
        OGMRIP_GCONF_VIDEO_ENCODING, &method,
        NULL);
    g_free (profile);

    if (method != OGMRIP_ENCODING_QUANTIZER)
    {
      gboolean active;

      active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->scale_check));
      if (!active)
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->test_check), FALSE);

      gtk_widget_set_sensitive (dialog->priv->test_check, active);
      gtk_widget_set_sensitive (dialog->priv->test_button, active);
    }
  }
}

static void
ogmrip_options_dialog_scale_combo_changed (OGMRipOptionsDialog *dialog)
{
  gint active;

  active = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->scale_combo));
  if (active == OGMRIP_SCALE_NONE || active == OGMRIP_SCALE_USER)
    ogmrip_options_dialog_set_scale_internal (dialog, active, -1, -1);
  else
  {
    guint w, h;
    gdouble aspect;

    ogmrip_options_dialog_get_crop (dialog, NULL, NULL, &w, &h);
    aspect = ogmrip_options_dialog_get_aspect (dialog, w, h);

    ogmrip_options_dialog_scale (active, aspect, &w, &h);

    ogmrip_options_dialog_set_scale_internal (dialog, active, w, h);
  }
}

static void
ogmrip_options_dialog_scale_combo_after_changed (OGMRipOptionsDialog *dialog)
{
  gint active;

  active = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->scale_combo));
  gtk_widget_set_sensitive (dialog->priv->scale_user_hbox, active == OGMRIP_SCALE_USER);
}

static void
ogmrip_options_dialog_autoscale_button_clicked (OGMRipOptionsDialog *dialog)
{
  OGMDvdTitle *title;
  OGMJobSpawn *spawn;

  GType video_codec;
  const gchar *profile;
  guint x, y, w, h;

  g_assert (dialog->priv->encoding != NULL);

  profile = ogmrip_encoding_get_profile (dialog->priv->encoding);
  if (profile)
    video_codec = ogmrip_gconf_get_video_codec_type (profile, NULL);
  else
    video_codec = ogmrip_plugin_get_nth_video_codec (0);

  g_assert (video_codec != G_TYPE_NONE);

  title = ogmrip_encoding_get_title (dialog->priv->encoding);
  g_assert (title != NULL);

  spawn = g_object_new (video_codec, "input", title, NULL);

  ogmrip_options_dialog_get_crop (dialog, &x, &y, &w, &h);
  ogmrip_video_codec_set_crop_size (OGMRIP_VIDEO_CODEC (spawn), x, y, w, h);

  ogmrip_video_codec_autoscale (OGMRIP_VIDEO_CODEC (spawn));
  ogmrip_video_codec_get_scale_size (OGMRIP_VIDEO_CODEC (spawn), &w, &h);
  g_object_unref (spawn);

  dialog->priv->is_autoscaled = TRUE;
  ogmrip_options_dialog_set_scale_internal (dialog, OGMRIP_SCALE_USER, w, h);
}

static void
ogmrip_options_dialog_scale_width_spin_changed (OGMRipOptionsDialog *dialog)
{
  ogmrip_options_dialog_set_scale_internal (dialog, -1,
      gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->scale_width_spin)), -1);
}

static void
ogmrip_options_dialog_scale_height_spin_changed (OGMRipOptionsDialog *dialog)
{
  ogmrip_options_dialog_set_scale_internal (dialog, -1,
      -1, gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->scale_height_spin)));
}

static void
ogmrip_options_dialog_test_check_toggled (OGMRipOptionsDialog *dialog)
{
  ogmrip_options_dialog_set_test (dialog,
      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->test_check)));
}

static void
ogmrip_options_dialog_test_button_clicked (OGMRipOptionsDialog *dialog)
{
  if (ogmrip_options_dialog_get_crop_internal (dialog, NULL, NULL, NULL, NULL) == OGMRIP_OPTIONS_AUTOMATIC && !dialog->priv->is_autocropped)
    gtk_button_clicked (GTK_BUTTON (dialog->priv->autocrop_button));

  if (ogmrip_options_dialog_get_scale_internal (dialog, NULL, NULL) == OGMRIP_SCALE_AUTOMATIC && !dialog->priv->is_autoscaled)
    gtk_button_clicked (GTK_BUTTON (dialog->priv->autoscale_button));

  gtk_dialog_response (GTK_DIALOG (dialog), OGMRIP_RESPONSE_TEST);
}

static void
ogmrip_options_dialog_cartoon_check_toggled (OGMRipOptionsDialog *dialog)
{
  ogmrip_options_dialog_set_cartoon (dialog,
      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->cartoon_check)));
}

static void
ogmrip_options_dialog_deint_check_toggled (OGMRipOptionsDialog *dialog)
{
  ogmrip_options_dialog_set_deinterlacer (dialog,
      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->deint_check)));
}

G_DEFINE_TYPE (OGMRipOptionsDialog, ogmrip_options_dialog, GTK_TYPE_DIALOG)

static void
ogmrip_options_dialog_class_init (OGMRipOptionsDialogClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->constructor = ogmrip_options_dialog_constructor;
  gobject_class->get_property = ogmrip_options_dialog_get_property;
  gobject_class->set_property = ogmrip_options_dialog_set_property;
  gobject_class->dispose = ogmrip_options_dialog_dispose;

  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ACTION,
      g_param_spec_uint ("action", "action", "action",
        OGMRIP_OPTIONS_DIALOG_CREATE, OGMRIP_OPTIONS_DIALOG_EDIT, OGMRIP_OPTIONS_DIALOG_CREATE,
        G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

  signals[PROFILE_CHANGED] = g_signal_new ("profile-changed", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
      G_STRUCT_OFFSET (OGMRipOptionsDialogClass, profile_changed), NULL, NULL,
      g_cclosure_marshal_VOID__VOID,
      G_TYPE_NONE, 0);

  signals[EDIT_CLICKED] = g_signal_new ("edit-clicked", G_TYPE_FROM_CLASS (klass), 
      G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
      G_STRUCT_OFFSET (OGMRipOptionsDialogClass, edit_clicked), NULL, NULL,
      g_cclosure_marshal_VOID__VOID,
      G_TYPE_NONE, 0);

  g_type_class_add_private (klass, sizeof (OGMRipOptionsDialogPriv));
}

static void
ogmrip_options_dialog_init (OGMRipOptionsDialog *dialog)
{
  dialog->priv = OGMRIP_OPTIONS_DIALOG_GET_PRIVATE (dialog);

  dialog->priv->action = OGMRIP_OPTIONS_DIALOG_CREATE;
}

static GObject *
ogmrip_options_dialog_constructor (GType type, guint n_props, GObjectConstructParam *props)
{
  OGMRipOptionsDialog *dialog;
  GObject *gobject;

  GtkCellRenderer *renderer;
  GtkWidget *area, *widget;
  GtkTreeIter iter;
  GladeXML *xml;
  guint i;

  gchar *size[] = { N_("None"), N_("Extra Small"), N_("Small"), N_("Medium"), 
    N_("Large"), N_("Extra Large"), N_("Full"), N_("User Defined") };

  gobject = G_OBJECT_CLASS (ogmrip_options_dialog_parent_class)->constructor (type, n_props, props);
  dialog = OGMRIP_OPTIONS_DIALOG (gobject);

  xml = glade_xml_new (OGMRIP_DATA_DIR G_DIR_SEPARATOR_S OGMRIP_GLADE_FILE, OGMRIP_GLADE_ROOT, NULL);
  if (!xml)
  {
    g_warning ("Could not find " OGMRIP_GLADE_FILE);
    return NULL;
  }

  gtk_window_set_title (GTK_WINDOW (dialog), _("Options"));
  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
  gtk_dialog_set_default_response (GTK_DIALOG (dialog), OGMRIP_RESPONSE_EXTRACT);
  gtk_window_set_icon_from_stock (GTK_WINDOW (dialog), GTK_STOCK_PROPERTIES);

  if (dialog->priv->action == OGMRIP_OPTIONS_DIALOG_EDIT)
    gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
  else
  {
    GtkWidget *image;

    gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);

    widget = gtk_button_new_with_mnemonic (_("En_queue"));
    gtk_dialog_add_action_widget (GTK_DIALOG (dialog), widget, OGMRIP_RESPONSE_ENQUEUE);
    gtk_widget_show (widget);

    image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
    gtk_button_set_image (GTK_BUTTON (widget), image);

#if GTK_CHECK_VERSION(2,18,0)
    gtk_widget_set_can_default (widget, TRUE);
#else
    GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
#endif

    widget = gtk_button_new_with_mnemonic (_("E_xtract"));
    gtk_dialog_add_action_widget (GTK_DIALOG (dialog), widget, OGMRIP_RESPONSE_EXTRACT);
    gtk_widget_show (widget);

    image = gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_BUTTON);
    gtk_button_set_image (GTK_BUTTON (widget), image);

#if GTK_CHECK_VERSION(2,18,0)
    gtk_widget_set_can_default (widget, TRUE);
#else
    GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
#endif
  }

  area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));

  widget = glade_xml_get_widget (xml, OGMRIP_GLADE_ROOT);
  gtk_container_add (GTK_CONTAINER (area), widget);
  gtk_widget_show (widget);

  dialog->priv->profile_combo = glade_xml_get_widget (xml, "profile-combo");
  ogmrip_options_dialog_construct_profiles_combo (dialog, dialog->priv->profile_combo);
  g_signal_connect_swapped (dialog->priv->profile_combo, "changed",
      G_CALLBACK (ogmrip_options_dialog_profile_combo_changed), dialog);

  if (dialog->priv->action == OGMRIP_OPTIONS_DIALOG_CREATE)
    ogmrip_settings_bind_custom (settings, OGMRIP_GCONF_GENERAL, OGMRIP_GCONF_PROFILE,
        G_OBJECT (OGMRIP_OPTIONS_DIALOG (dialog)->priv->profile_combo), "active",
        ogmrip_options_dialog_profile_get_value,
        ogmrip_options_dialog_profile_set_value,
        NULL);

  dialog->priv->edit_button = glade_xml_get_widget (xml, "edit-button");
  g_signal_connect_swapped (dialog->priv->edit_button, "clicked",
      G_CALLBACK (ogmrip_options_dialog_edit_profiles_button_clicked), dialog);

  dialog->priv->crop_box = glade_xml_get_widget (xml, "crop-box");
  dialog->priv->scale_box = glade_xml_get_widget (xml, "scale-box");

  dialog->priv->crop_check = glade_xml_get_widget (xml, "crop-check");
  widget = glade_xml_get_widget (xml,"crop-box");
  g_signal_connect (dialog->priv->crop_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_check_untoggled), widget);
  g_signal_connect_swapped (dialog->priv->crop_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_crop_check_toggled), dialog);

  dialog->priv->crop_left_label = glade_xml_get_widget (xml, "crop-left-label");
  dialog->priv->crop_right_label = glade_xml_get_widget (xml, "crop-right-label");
  dialog->priv->crop_top_label = glade_xml_get_widget (xml, "crop-top-label");
  dialog->priv->crop_bottom_label = glade_xml_get_widget (xml, "crop-bottom-label");

  dialog->priv->crop_button = glade_xml_get_widget (xml, "crop-button");
  g_signal_connect_swapped (dialog->priv->crop_button, "clicked", 
      G_CALLBACK (ogmrip_options_dialog_crop_button_clicked), dialog);

  dialog->priv->autocrop_button = glade_xml_get_widget (xml, "autocrop-button");
  g_signal_connect_swapped (dialog->priv->autocrop_button, "clicked", 
      G_CALLBACK (ogmrip_options_dialog_autocrop_button_clicked), dialog);

  dialog->priv->scale_check = glade_xml_get_widget (xml, "scale-check");
  widget = glade_xml_get_widget (xml,"scale-box");
  g_signal_connect (dialog->priv->scale_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_check_untoggled), widget);
  g_signal_connect_swapped (dialog->priv->scale_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_scale_check_toggled), dialog);
  g_signal_connect_swapped (dialog->priv->scale_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_scale_check_after_toggled), dialog);

  dialog->priv->autoscale_button = glade_xml_get_widget (xml, "autoscale-button");
  g_signal_connect_swapped (dialog->priv->autoscale_button, "clicked", 
      G_CALLBACK (ogmrip_options_dialog_autoscale_button_clicked), dialog);

  dialog->priv->scale_user_hbox = glade_xml_get_widget (xml, "scale-user-hbox");

  dialog->priv->scale_width_spin = glade_xml_get_widget (xml, "scale-width-spin");
  g_signal_connect_swapped (dialog->priv->scale_width_spin, "value-changed",
      G_CALLBACK (ogmrip_options_dialog_scale_width_spin_changed), dialog);

  dialog->priv->scale_height_spin = glade_xml_get_widget (xml, "scale-height-spin");
  g_signal_connect_swapped (dialog->priv->scale_height_spin, "value-changed",
      G_CALLBACK (ogmrip_options_dialog_scale_height_spin_changed), dialog);

  dialog->priv->scale_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

  dialog->priv->scale_combo = glade_xml_get_widget (xml, "scale-combo");
  g_signal_connect_swapped (dialog->priv->scale_combo, "changed",
      G_CALLBACK (ogmrip_options_dialog_scale_combo_changed), dialog);
  g_signal_connect_swapped (dialog->priv->scale_combo, "changed",
      G_CALLBACK (ogmrip_options_dialog_scale_combo_after_changed), dialog);

  for (i = 0; i < G_N_ELEMENTS (size); i++)
  {
    gtk_list_store_append (dialog->priv->scale_store, &iter);
    gtk_list_store_set (dialog->priv->scale_store, &iter, 0, _(size[i]), -1);
  }

  renderer = gtk_cell_renderer_text_new ();
  g_object_set (renderer, "xalign", 0.0, NULL);
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->priv->scale_combo), renderer, TRUE);
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->priv->scale_combo), renderer, "text", 0, NULL);

  renderer = gtk_cell_renderer_text_new ();
  g_object_set (renderer, "xalign", 1.0, "xpad", 4, NULL);
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->priv->scale_combo), renderer, TRUE);
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->priv->scale_combo), renderer, "text", 1, NULL);

  gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->priv->scale_combo), GTK_TREE_MODEL (dialog->priv->scale_store));

  dialog->priv->test_check = glade_xml_get_widget (xml, "test-check");
  widget = glade_xml_get_widget (xml,"test-box");
  g_signal_connect (dialog->priv->test_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_check_untoggled), widget);
  g_signal_connect_swapped (dialog->priv->test_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_test_check_toggled), dialog);

  dialog->priv->test_button = glade_xml_get_widget (xml, "test-button");
  g_signal_connect_swapped (dialog->priv->test_button, "clicked",
      G_CALLBACK (ogmrip_options_dialog_test_button_clicked), dialog);

  dialog->priv->cartoon_check = glade_xml_get_widget (xml, "cartoon-check");
  g_signal_connect_swapped (dialog->priv->cartoon_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_cartoon_check_toggled), dialog);

  dialog->priv->deint_check = glade_xml_get_widget (xml, "deint-check");
  g_signal_connect_swapped (dialog->priv->deint_check, "toggled",
      G_CALLBACK (ogmrip_options_dialog_deint_check_toggled), dialog);

  g_object_unref (xml);

  ogmrip_options_dialog_set_encoding_internal (dialog, NULL, TRUE);

  return gobject;
}

static void
ogmrip_options_dialog_get_property (GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec)
{
  switch (property_id)
  {
    case PROP_ACTION:
      g_value_set_uint (value, OGMRIP_OPTIONS_DIALOG (gobject)->priv->action);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
      break;
  }
}

static void
ogmrip_options_dialog_set_property (GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec)
{
  switch (property_id)
  {
    case PROP_ACTION:
      OGMRIP_OPTIONS_DIALOG (gobject)->priv->action = g_value_get_uint (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
      break;
  }
}

static void
ogmrip_options_dialog_dispose (GObject *gobject)
{
  OGMRipOptionsDialog *dialog = OGMRIP_OPTIONS_DIALOG (gobject);

  if (dialog->priv->scale_store)
  {
    g_object_unref (dialog->priv->scale_store);
    dialog->priv->scale_store = NULL;
  }

  if (dialog->priv->encoding)
  {
    g_object_unref (dialog->priv->encoding);
    dialog->priv->encoding = NULL;
  }

  G_OBJECT_CLASS (ogmrip_options_dialog_parent_class)->dispose (gobject);
}

GtkWidget *
ogmrip_options_dialog_new (OGMRipOptionsDialogAction action)
{
  return g_object_new (OGMRIP_TYPE_OPTIONS_DIALOG, "action", action, NULL);
}

void
ogmrip_options_dialog_set_response_sensitive (OGMRipOptionsDialog *dialog, guint type, gboolean sensitive)
{
  g_return_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog));

  /*
   * TODO
   * - method ?
   * - codec ?
   */
  if (type == OGMRIP_RESPONSE_TEST)
    gtk_widget_set_sensitive (dialog->priv->test_button, sensitive);
  else
    gtk_dialog_set_response_visible (GTK_DIALOG (dialog), type, sensitive);
}

OGMRipEncoding *
ogmrip_options_dialog_get_encoding (OGMRipOptionsDialog *dialog)
{
  g_return_val_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog), NULL);

  return dialog->priv->encoding;
}

static gboolean
ogmrip_options_dialog_encoding_equal (OGMRipEncoding *encoding1, OGMRipEncoding *encoding2)
{
  OGMDvdTitle *title1, *title2;
  const gchar *id1, *id2;

  if ((!encoding1 && encoding2) || (encoding1 && !encoding2))
    return FALSE;

  if (encoding1 == encoding2)
    return TRUE;

  id1 = ogmrip_encoding_get_id (encoding1);
  id2 = ogmrip_encoding_get_id (encoding2);

  if (!g_str_equal (id1, id2))
    return FALSE;

  title1 = ogmrip_encoding_get_title (encoding1);
  title2 = ogmrip_encoding_get_title (encoding2);

  if (ogmdvd_title_get_nr (title1) != ogmdvd_title_get_nr (title2))
    return FALSE;

  return TRUE;
}

static void
ogmrip_options_dialog_set_encoding_internal (OGMRipOptionsDialog *dialog, OGMRipEncoding *encoding, gboolean force)
{
  gboolean equal;
  guint x, y, w, h;
  gint type;

  equal = ogmrip_options_dialog_encoding_equal (encoding, dialog->priv->encoding);

  if (equal && encoding && dialog->priv->encoding)
  {
    type = ogmrip_encoding_get_scale (dialog->priv->encoding, &w, &h);
    ogmrip_encoding_set_scale (encoding, type, w, h);

    type = ogmrip_encoding_get_crop (dialog->priv->encoding, &x, &y, &w, &h);
    ogmrip_encoding_set_crop (encoding, type, x, y, w, h);

    ogmrip_encoding_set_test (encoding, ogmrip_encoding_get_test (dialog->priv->encoding));
    ogmrip_encoding_set_cartoon (encoding, ogmrip_encoding_get_cartoon (dialog->priv->encoding));
    ogmrip_encoding_set_deinterlacer (encoding, ogmrip_encoding_get_deinterlacer (dialog->priv->encoding));
  }

  if (encoding)
    g_object_ref (encoding);

  if (dialog->priv->encoding)
    g_object_unref (dialog->priv->encoding);

  dialog->priv->encoding = encoding;

  if (!equal || force)
  {
    dialog->priv->is_autocropped = FALSE;
    dialog->priv->is_autoscaled = FALSE;

    dialog->priv->scale_type = -1;
    dialog->priv->crop_type = -1;

    if (encoding)
    {
      OGMDvdTitle *title;

      ogmrip_options_dialog_set_active_profile (dialog, ogmrip_encoding_get_profile (encoding));

      title = ogmrip_encoding_get_title (encoding);
      ogmdvd_title_get_size (title, &dialog->priv->raw_width, &dialog->priv->raw_height);

      ogmrip_encoding_get_aspect_ratio (encoding, &dialog->priv->aspect_num, &dialog->priv->aspect_denom);

      type = ogmrip_encoding_get_crop (encoding, &x, &y, &w, &h);
      ogmrip_options_dialog_set_crop (dialog, type, x, y, w, h);

      type = ogmrip_encoding_get_scale (encoding, &w, &h);
      ogmrip_options_dialog_set_scale (dialog, type, w, h);
    }
    else
    {
      dialog->priv->raw_width = 0;
      dialog->priv->raw_height = 0;

      dialog->priv->aspect_num = 0;
      dialog->priv->aspect_denom = 1;

      ogmrip_options_dialog_set_crop (dialog, OGMRIP_OPTIONS_AUTOMATIC, 0, 0, 0, 0);
      ogmrip_options_dialog_set_scale (dialog, OGMRIP_OPTIONS_AUTOMATIC, 0, 0);
    }

    ogmrip_options_dialog_set_test (dialog,
        encoding ? ogmrip_encoding_get_test (encoding) : TRUE);
    ogmrip_options_dialog_set_cartoon (dialog,
        encoding ? ogmrip_encoding_get_cartoon (encoding) : FALSE);
    ogmrip_options_dialog_set_deinterlacer (dialog,
        encoding ? ogmrip_encoding_get_deinterlacer (encoding) != OGMRIP_DEINT_NONE : FALSE);
  }
}

void
ogmrip_options_dialog_set_encoding (OGMRipOptionsDialog *dialog, OGMRipEncoding *encoding)
{
  g_return_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog));
  g_return_if_fail (encoding == NULL || OGMRIP_IS_ENCODING (encoding));

  if (encoding != dialog->priv->encoding)
    ogmrip_options_dialog_set_encoding_internal (dialog, encoding, FALSE);
}

static gint
ogmrip_options_dialog_get_crop_internal (OGMRipOptionsDialog *dialog, guint *left, guint *top, guint *right, guint *bottom)
{
  gint cur_left, cur_top, cur_right, cur_bottom;
  gint type;

  cur_left = gtk_label_get_int (GTK_LABEL (dialog->priv->crop_left_label));
  cur_top = gtk_label_get_int (GTK_LABEL (dialog->priv->crop_top_label));
  cur_right = gtk_label_get_int (GTK_LABEL (dialog->priv->crop_right_label));
  cur_bottom = gtk_label_get_int (GTK_LABEL (dialog->priv->crop_bottom_label));

  if (dialog->priv->crop_type < 0 ||
      (dialog->priv->crop_type == OGMRIP_OPTIONS_AUTOMATIC && dialog->priv->is_autocropped))
    type = OGMRIP_OPTIONS_MANUAL;
  else
    type = dialog->priv->crop_type;

  if (left)
    *left = type == OGMRIP_OPTIONS_MANUAL ? cur_left : 0;

  if (top)
    *top = type == OGMRIP_OPTIONS_MANUAL ? cur_top : 0;

  if (right)
    *right = type == OGMRIP_OPTIONS_MANUAL ? cur_right : 0;

  if (bottom)
    *bottom = type == OGMRIP_OPTIONS_MANUAL ? cur_bottom : 0;

  return dialog->priv->scale_type;
}

gint
ogmrip_options_dialog_get_crop (OGMRipOptionsDialog *dialog, guint *x, guint *y, guint *width, guint *height)
{
  gint type;
  guint left, top, right, bottom;

  type = ogmrip_options_dialog_get_crop_internal (dialog, &left, &top, &right, &bottom);

  if (x)
    *x = left;

  if (y)
    *y = top;

  if (width)
  {
    *width = dialog->priv->raw_width;
    if (type == OGMRIP_OPTIONS_MANUAL && *width > left + right)
      *width -= left + right;
  }

  if (height)
  {
    *height = dialog->priv->raw_height;
    if (type == OGMRIP_OPTIONS_MANUAL && *height > top + bottom)
      *height -= top + bottom;
  }

  if (type == OGMRIP_OPTIONS_AUTOMATIC && dialog->priv->is_autocropped)
    type = OGMRIP_OPTIONS_MANUAL;

  return type;
}

static void
ogmrip_options_dialog_set_crop_internal (OGMRipOptionsDialog *dialog, gint type, gint left, gint top, gint right, gint bottom)
{
  guint old_left, old_top, old_right, old_bottom;

#if GTK_CHECK_VERSION(2,18,0)
  if (!gtk_widget_is_sensitive (dialog->priv->crop_check))
#else
  if (!GTK_WIDGET_IS_SENSITIVE (dialog->priv->crop_check))
#endif
    type = OGMRIP_OPTIONS_NONE;

  if (type != dialog->priv->crop_type && type == OGMRIP_OPTIONS_AUTOMATIC &&
      dialog->priv->scale_type >= 0 && dialog->priv->scale_type != OGMRIP_SCALE_AUTOMATIC &&
      !dialog->priv->is_autocropped && dialog->priv->encoding)
    gtk_button_clicked (GTK_BUTTON (dialog->priv->autocrop_button));
  else
  {
    if (type < 0)
      type = dialog->priv->crop_type;

    if (type == OGMRIP_OPTIONS_NONE || dialog->priv->encoding == NULL)
      left = top = right = bottom = 0;
    else if (type == OGMRIP_OPTIONS_AUTOMATIC && !dialog->priv->is_autocropped)
      left = top = right = bottom = -1;

    ogmrip_options_dialog_get_crop_internal (dialog, &old_left, &old_top, &old_right, &old_bottom);

    if (left < 0)
      left = old_left;

    if (top < 0)
      top = old_top;

    if (right < 0)
      right = old_right;

    if (bottom < 0)
      bottom = old_bottom;

    if (type != dialog->priv->crop_type)
    {
      g_signal_handlers_block_by_func (dialog->priv->crop_check, ogmrip_options_dialog_crop_check_toggled, dialog);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->crop_check), type == OGMRIP_OPTIONS_AUTOMATIC);
      g_signal_handlers_unblock_by_func (dialog->priv->crop_check, ogmrip_options_dialog_crop_check_toggled, dialog);
    }

    if (left != old_left)
      gtk_label_set_int (GTK_LABEL (dialog->priv->crop_left_label), left);

    if (top != old_top)
      gtk_label_set_int (GTK_LABEL (dialog->priv->crop_top_label), top);

    if (right != old_right)
      gtk_label_set_int (GTK_LABEL (dialog->priv->crop_right_label), right);

    if (bottom != old_bottom)
      gtk_label_set_int (GTK_LABEL (dialog->priv->crop_bottom_label), bottom);

    dialog->priv->is_autocropped = dialog->priv->is_autocropped && type == OGMRIP_OPTIONS_AUTOMATIC;

    ogmrip_options_dialog_update_scale_combo (dialog);

    if (dialog->priv->encoding)
    {
      guint width, height;

      width = dialog->priv->raw_width;
      if (width > left + right)
        width -= left + right;

      height = dialog->priv->raw_height;
      if (height > top + bottom)
        height -= top + bottom;

      if (type == OGMRIP_OPTIONS_AUTOMATIC && dialog->priv->is_autocropped)
        ogmrip_encoding_set_crop (dialog->priv->encoding, OGMRIP_OPTIONS_MANUAL, left, top, width, height);
      else
        ogmrip_encoding_set_crop (dialog->priv->encoding, type, left, top, width, height);
    }

    dialog->priv->crop_type = type;
  }
}

void
ogmrip_options_dialog_set_crop (OGMRipOptionsDialog *dialog, OGMRipOptionsType type, guint x, guint y, guint width, guint height)
{
  gint right = 0, bottom = 0;

  if (dialog->priv->raw_width > x + width)
    right = dialog->priv->raw_width - x - width;

  if (dialog->priv->raw_height > y + height)
    bottom = dialog->priv->raw_height - y - height;

  ogmrip_options_dialog_set_crop_internal (dialog, type, x, y, right, bottom);
}

static gint
ogmrip_options_dialog_get_scale_internal (OGMRipOptionsDialog *dialog, guint *width, guint *height)
{
  if (width)
  {
    if (dialog->priv->scale_type == OGMRIP_SCALE_USER)
      *width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->scale_width_spin));
    else if (dialog->priv->scale_type == OGMRIP_SCALE_NONE)
      *width = dialog->priv->raw_width;
    else
      *width = 0;
  }

  if (height)
  {
    if (dialog->priv->scale_type == OGMRIP_SCALE_USER)
      *height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->scale_height_spin));
    else if (dialog->priv->scale_type == OGMRIP_SCALE_NONE)
      *height = dialog->priv->raw_height;
    else
      *height = 0;
  }

  return dialog->priv->scale_type;
}

gint
ogmrip_options_dialog_get_scale (OGMRipOptionsDialog *dialog, guint *width, guint *height)
{
  gint type;

  type = ogmrip_options_dialog_get_scale_internal (dialog, width, height);

  if (type == OGMRIP_SCALE_AUTOMATIC && dialog->priv->is_autoscaled)
    return OGMRIP_OPTIONS_MANUAL;

  if (type == OGMRIP_SCALE_AUTOMATIC)
    return OGMRIP_OPTIONS_AUTOMATIC;

  if (type == OGMRIP_SCALE_NONE)
    return OGMRIP_OPTIONS_NONE;

  return OGMRIP_OPTIONS_MANUAL;
}

static void
ogmrip_options_dialog_set_scale_internal (OGMRipOptionsDialog *dialog, gint type, gint width, gint height)
{
  guint old_width, old_height;

#if GTK_CHECK_VERSION(2,18,0)
  if (!gtk_widget_is_sensitive (dialog->priv->scale_check))
#else
  if (!GTK_WIDGET_IS_SENSITIVE (dialog->priv->scale_check))
#endif
    type = OGMRIP_SCALE_NONE;

  if (type < 0)
    type = dialog->priv->scale_type;

  if (type != dialog->priv->scale_type && dialog->priv->scale_type == OGMRIP_SCALE_AUTOMATIC &&
      dialog->priv->crop_type >= 0 && dialog->priv->crop_type == OGMRIP_OPTIONS_AUTOMATIC &&
      !dialog->priv->is_autocropped && dialog->priv->encoding)
    gtk_button_clicked (GTK_BUTTON (dialog->priv->autocrop_button));

  if (type == OGMRIP_SCALE_AUTOMATIC && !dialog->priv->is_autoscaled)
    width = height = -1;
  else if (type == OGMRIP_SCALE_NONE)
  {
    width = dialog->priv->raw_width;
    height = dialog->priv->raw_height;
  }

  ogmrip_options_dialog_get_scale_internal (dialog, &old_width, &old_height);

  if (width < 0)
    width = old_width;

  if (height < 0)
    height = old_height;

  if (type != dialog->priv->scale_type)
  {
    g_signal_handlers_block_by_func (dialog->priv->scale_check, ogmrip_options_dialog_scale_check_toggled, dialog);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->scale_check), type == OGMRIP_SCALE_AUTOMATIC);
    g_signal_handlers_unblock_by_func (dialog->priv->scale_check, ogmrip_options_dialog_scale_check_toggled, dialog);

    g_signal_handlers_block_by_func (dialog->priv->scale_combo, ogmrip_options_dialog_scale_combo_changed, dialog);
    gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->scale_combo), type == OGMRIP_SCALE_AUTOMATIC ? OGMRIP_SCALE_NONE : type);
    g_signal_handlers_unblock_by_func (dialog->priv->scale_combo, ogmrip_options_dialog_scale_combo_changed, dialog);
  }

  if (width != old_width)
  {
    g_signal_handlers_block_by_func (dialog->priv->scale_width_spin, ogmrip_options_dialog_scale_width_spin_changed, dialog);
    gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_width_spin), (gdouble) width);
    g_signal_handlers_unblock_by_func (dialog->priv->scale_width_spin, ogmrip_options_dialog_scale_width_spin_changed, dialog);
  }

  if (height != old_height)
  {
    g_signal_handlers_block_by_func (dialog->priv->scale_height_spin, ogmrip_options_dialog_scale_height_spin_changed, dialog);
    gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_height_spin), (gdouble) height);
    g_signal_handlers_unblock_by_func (dialog->priv->scale_height_spin, ogmrip_options_dialog_scale_height_spin_changed, dialog);
  }

  dialog->priv->is_autoscaled = dialog->priv->is_autoscaled && type == OGMRIP_SCALE_AUTOMATIC;

  if (dialog->priv->encoding)
  {
    switch (type)
    {
      case OGMRIP_SCALE_AUTOMATIC:
        if (dialog->priv->is_autoscaled)
          ogmrip_encoding_set_scale (dialog->priv->encoding, OGMRIP_OPTIONS_MANUAL, width, height);
        else
          ogmrip_encoding_set_scale (dialog->priv->encoding, OGMRIP_OPTIONS_AUTOMATIC, width, height);
        break;
      case OGMRIP_SCALE_NONE:
        ogmrip_encoding_set_scale (dialog->priv->encoding, OGMRIP_OPTIONS_NONE, width, height);
        break;
      default:
        ogmrip_encoding_set_scale (dialog->priv->encoding, OGMRIP_OPTIONS_MANUAL, width, height);
        break;
    }
  }

  dialog->priv->scale_type = type;
}

void
ogmrip_options_dialog_set_scale (OGMRipOptionsDialog *dialog, OGMRipOptionsType type, guint width, guint height)
{
  switch (type)
  {
    case OGMRIP_OPTIONS_AUTOMATIC:
      ogmrip_options_dialog_set_scale_internal (dialog, OGMRIP_SCALE_AUTOMATIC, width, height);
      break;
    case OGMRIP_OPTIONS_NONE:
      ogmrip_options_dialog_set_scale_internal (dialog, OGMRIP_SCALE_NONE, width, height);
      break;
    default:
      ogmrip_options_dialog_set_scale_internal (dialog, OGMRIP_SCALE_USER, width, height);
      break;
  }
}

gboolean
ogmrip_options_dialog_get_test (OGMRipOptionsDialog *dialog)
{
  g_return_val_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog), FALSE);

  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->test_check));
}

void
ogmrip_options_dialog_set_test (OGMRipOptionsDialog *dialog, gboolean test)
{
  g_return_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog));

#if GTK_CHECK_VERSION(2,18,0)
  if (!gtk_widget_is_sensitive (dialog->priv->test_check))
#else
  if (!GTK_WIDGET_IS_SENSITIVE (dialog->priv->test_check))
#endif
    test = FALSE;

  g_signal_handlers_block_by_func (dialog->priv->test_check, ogmrip_options_dialog_test_check_toggled, dialog);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->test_check), test);
  g_signal_handlers_unblock_by_func (dialog->priv->test_check, ogmrip_options_dialog_test_check_toggled, dialog);

  if (dialog->priv->encoding)
    ogmrip_encoding_set_test (dialog->priv->encoding, test);
}

gboolean
ogmrip_options_dialog_get_deinterlacer (OGMRipOptionsDialog *dialog)
{
  g_return_val_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog), -1);

  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->deint_check));
}

void
ogmrip_options_dialog_set_deinterlacer (OGMRipOptionsDialog *dialog, gboolean deint)
{
  g_return_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog));

  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->deint_check), deint);

  if (dialog->priv->encoding)
    ogmrip_encoding_set_deinterlacer (dialog->priv->encoding, deint ? OGMRIP_DEINT_YADIF : OGMRIP_DEINT_NONE);
}

gboolean
ogmrip_options_dialog_get_cartoon (OGMRipOptionsDialog *dialog)
{
  g_return_val_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog), FALSE);

  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->cartoon_check));
}

void
ogmrip_options_dialog_set_cartoon (OGMRipOptionsDialog *dialog, gboolean cartoon)
{
  g_return_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog));

  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->cartoon_check), cartoon);

  if (dialog->priv->encoding)
    ogmrip_encoding_set_cartoon (dialog->priv->encoding, cartoon);
}

gchar *
ogmrip_options_dialog_get_active_profile (OGMRipOptionsDialog *dialog)
{
  GtkTreeModel *model;
  GtkTreeIter iter;
  gchar *section;

  g_return_val_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog), NULL);

  if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->priv->profile_combo), &iter))
    return NULL;

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->profile_combo));
  if (!model)
    return NULL;

  gtk_tree_model_get (model, &iter, COL_SECTION, &section, -1);

  return section;
}

void
ogmrip_options_dialog_set_active_profile (OGMRipOptionsDialog *dialog, const gchar *profile)
{
  GtkTreeModel *model;
  GtkTreeIter iter;

  g_return_if_fail (OGMRIP_IS_OPTIONS_DIALOG (dialog));
  g_return_if_fail (profile != NULL);

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->profile_combo));
  if (ogmrip_options_dialog_combo_get_profile_iter (model, &iter, profile))
    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->profile_combo), &iter);
  else
    gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->profile_combo), 0);
}

void
ogmrip_options_dialog_clear_profiles (OGMRipOptionsDialog *dialog)
{
  GtkTreeModel *model;

  if (dialog->priv)
  {
    model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->profile_combo));
    if (model)
      gtk_list_store_clear (GTK_LIST_STORE (model));
  }
}

void
ogmrip_options_dialog_add_profile (OGMRipOptionsDialog *dialog, const gchar *profile, const gchar *name)
{
  GtkTreeModel *model;
  GtkTreeIter iter;

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->profile_combo));
  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
  gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_NAME, name, COL_SECTION, profile, -1);

  gtk_widget_set_sensitive (dialog->priv->profile_combo, TRUE);
  gtk_widget_set_sensitive (dialog->priv->edit_button, TRUE);
}

void
ogmrip_options_dialog_remove_profile (OGMRipOptionsDialog *dialog, const gchar *profile)
{
  GtkTreeModel *model;
  GtkTreeIter iter;

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->profile_combo));
  if (ogmrip_options_dialog_combo_get_profile_iter (model, &iter, profile))
  {
    gboolean has_child;

    gtk_list_store_remove (GTK_LIST_STORE (model), &iter);

    has_child = gtk_tree_model_iter_n_children (model, NULL) > 0;
    if (has_child)
    {
      if (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->profile_combo)) < 0)
        gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->profile_combo), 0);
    }

    gtk_widget_set_sensitive (dialog->priv->profile_combo, has_child);
    gtk_widget_set_sensitive (dialog->priv->edit_button, has_child);
  }
}

void
ogmrip_options_dialog_rename_profile (OGMRipOptionsDialog *dialog, const gchar *profile, const gchar *new_name)
{
  GtkTreeModel *model;
  GtkTreeIter iter;

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->priv->profile_combo));
  if (ogmrip_options_dialog_combo_get_profile_iter (model, &iter, profile))
    gtk_list_store_set (GTK_LIST_STORE (model), &iter, COL_NAME, new_name, -1);
}

