/*
 * Copyright (C) 2013 Tristan Van Berkom.
 *
 * This library 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 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * Authors:
 *   Tristan Van Berkom <tvb@gnome.org>
 */

#include <config.h>
#include <glib/gi18n-lib.h>

#include "glade-project-properties.h"
#include "glade-project.h"
#include "glade-command.h"
#include "glade-app.h"
#include "glade-utils.h"
#include "glade-private.h"

/* GObjectClass */
static void     glade_project_properties_finalize     (GObject                *object);
static void     glade_project_properties_set_property (GObject                *object,
						       guint                   prop_id,
						       const GValue           *value,
						       GParamSpec             *pspec);

/* UI Callbacks */
static void     on_template_combo_box_changed         (GtkComboBox            *combo,
						       GladeProjectProperties *properties);
static void     on_template_checkbutton_toggled       (GtkToggleButton        *togglebutton,
						       GladeProjectProperties *properties);
static void     resource_default_toggled              (GtkWidget              *widget,
						       GladeProjectProperties *properties);
static void     resource_relative_toggled             (GtkWidget              *widget,
						       GladeProjectProperties *properties);
static void     resource_fullpath_toggled             (GtkWidget              *widget,
						       GladeProjectProperties *properties);
static void     on_relative_path_entry_insert_text    (GtkEditable            *editable,
                                                       gchar                  *new_text,
                                                       gint                    new_text_length,
                                                       gint                   *position,
                                                       GladeProjectProperties *properties); 
static void     on_relative_path_entry_changed        (GtkEntry               *entry,
						       GladeProjectProperties *properties);
static void     resource_full_path_set                (GtkFileChooserButton   *button,
						       GladeProjectProperties *properties);
static void     verify_clicked                        (GtkWidget              *button,
						       GladeProjectProperties *properties);
static void     on_domain_entry_changed               (GtkWidget              *entry,
						       GladeProjectProperties *properties);
static void     target_button_clicked                 (GtkWidget              *widget,
						       GladeProjectProperties *properties);
static void     on_glade_project_properties_hide      (GtkWidget              *widget,
                                                       GladeProjectProperties *properties);
static void     on_css_filechooser_file_set           (GtkFileChooserButton   *widget,
                                                       GladeProjectProperties *properties);
static void     on_css_checkbutton_toggled            (GtkWidget              *widget,
                                                       GladeProjectProperties *properties);
static void     on_license_comboboxtext_changed       (GtkComboBox *widget,
                                                       GladeProjectProperties *properties);

static void     on_license_data_changed               (GladeProjectProperties *properties);

/* Project callbacks */
static void     project_resource_path_changed         (GladeProject           *project,
						       GParamSpec             *pspec,
						       GladeProjectProperties *properties);
static void     project_template_changed              (GladeProject           *project,
						       GParamSpec             *pspec,
						       GladeProjectProperties *properties);
static void     project_domain_changed                (GladeProject           *project,
						       GParamSpec             *pspec,
						       GladeProjectProperties *properties);
static void     project_targets_changed               (GladeProject           *project,
						       GladeProjectProperties *properties);
static void     project_license_changed               (GladeProject           *project,
						       GParamSpec             *pspec,
						       GladeProjectProperties *properties);
static void     project_css_provider_path_changed     (GladeProject           *project,
                                                       GParamSpec             *pspec,
                                                       GladeProjectProperties *properties);

struct _GladeProjectPropertiesPrivate
{
  GladeProject *project;

  /* Properties */
  GtkWidget *project_wide_radio;
  GtkWidget *toplevel_contextual_radio;
  GtkWidget *toolkit_box;

  GtkWidget *resource_default_radio;
  GtkWidget *resource_relative_radio;
  GtkWidget *resource_fullpath_radio;
  GtkWidget *relative_path_entry;
  GtkWidget *full_path_button;
  GtkWidget *domain_entry;
  GtkWidget *template_combobox;
  GtkWidget *template_checkbutton;

  GtkWidget *css_filechooser;
  GtkWidget *css_checkbutton;
  
  GHashTable *target_radios;

  /* License */
  GtkComboBox    *license_comboboxtext;
  GtkTextView    *license_textview;
  GtkEntryBuffer *name_entrybuffer;
  GtkEntryBuffer *description_entrybuffer;
  GtkTextBuffer  *authors_textbuffer;
  GtkTextBuffer  *copyright_textbuffer;
  GtkTextBuffer  *license_textbuffer;
  
  gboolean ignore_ui_cb;
};

enum
{
  PROP_0,
  PROP_PROJECT,
};

G_DEFINE_TYPE_WITH_PRIVATE (GladeProjectProperties, glade_project_properties, GTK_TYPE_DIALOG);

/********************************************************
 *                  Class/Instance Init                 *
 ********************************************************/
static void
glade_project_properties_init (GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv;

  properties->priv = priv = glade_project_properties_get_instance_private (properties);

  priv->target_radios = g_hash_table_new_full (g_str_hash, g_str_equal,
                                               g_free, NULL);

  gtk_widget_init_template (GTK_WIDGET (properties));
}

static void
glade_project_properties_class_init (GladeProjectPropertiesClass *klass)
{
  GObjectClass *gobject_class;
  GtkWidgetClass *widget_class;

  gobject_class = G_OBJECT_CLASS (klass);
  widget_class  = GTK_WIDGET_CLASS (klass);

  gobject_class->finalize = glade_project_properties_finalize;
  gobject_class->set_property = glade_project_properties_set_property;

  g_object_class_install_property
    (gobject_class, PROP_PROJECT,
     g_param_spec_object ("project", _("Project"),
			  _("The project this properties dialog was created for"),
			  GLADE_TYPE_PROJECT,
			  G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));

  /* Setup the template GtkBuilder xml for this class
   */
  gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/gladeui/glade-project-properties.ui");

  /* Define the relationship of the private entry and the entry defined in the xml
   */
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, resource_default_radio);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, resource_relative_radio);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, resource_fullpath_radio);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, relative_path_entry);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, full_path_button);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, domain_entry);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, template_checkbutton);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, template_combobox);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, toolkit_box);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, css_filechooser);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, css_checkbutton);

  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, license_comboboxtext);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, license_textview);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, name_entrybuffer);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, description_entrybuffer);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, authors_textbuffer);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, copyright_textbuffer);
  gtk_widget_class_bind_template_child_private (widget_class, GladeProjectProperties, license_textbuffer);

  
  /* Declare the callback ports that this widget class exposes, to bind with <signal>
   * connections defined in the GtkBuilder xml
   */
  gtk_widget_class_bind_template_callback (widget_class, on_template_combo_box_changed);
  gtk_widget_class_bind_template_callback (widget_class, on_template_checkbutton_toggled);
  gtk_widget_class_bind_template_callback (widget_class, resource_default_toggled);
  gtk_widget_class_bind_template_callback (widget_class, resource_relative_toggled);
  gtk_widget_class_bind_template_callback (widget_class, resource_fullpath_toggled);
  gtk_widget_class_bind_template_callback (widget_class, resource_full_path_set);
  gtk_widget_class_bind_template_callback (widget_class, verify_clicked);
  gtk_widget_class_bind_template_callback (widget_class, on_domain_entry_changed);
  gtk_widget_class_bind_template_callback (widget_class, on_relative_path_entry_insert_text);
  gtk_widget_class_bind_template_callback (widget_class, on_relative_path_entry_changed);
  gtk_widget_class_bind_template_callback (widget_class, on_glade_project_properties_hide);  
  gtk_widget_class_bind_template_callback (widget_class, on_css_filechooser_file_set);
  gtk_widget_class_bind_template_callback (widget_class, on_css_checkbutton_toggled);
  gtk_widget_class_bind_template_callback (widget_class, on_license_comboboxtext_changed);
  gtk_widget_class_bind_template_callback (widget_class, on_license_data_changed);
}

/********************************************************
 *                     GObjectClass                     *
 ********************************************************/
static void
glade_project_properties_finalize (GObject *object)
{
  GladeProjectProperties        *properties = GLADE_PROJECT_PROPERTIES (object);
  GladeProjectPropertiesPrivate *priv = properties->priv;

  g_hash_table_destroy (priv->target_radios);

  G_OBJECT_CLASS (glade_project_properties_parent_class)->finalize (object);
}

static void
target_version_box_fill (GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GladeProject *project = priv->project;
  GtkWidget *vbox = priv->toolkit_box;
  GtkWidget *label, *active_radio, *target_radio, *hbox;
  GList *list, *targets;

  /* Add stuff to vbox */
  for (list = glade_app_get_catalogs (); list; list = g_list_next (list))
    {
      GladeCatalog *catalog = list->data;
      gint minor, major;

      /* Skip if theres only one option */
      if (g_list_length (glade_catalog_get_targets (catalog)) <= 1)
        continue;

      glade_project_get_target_version (project,
                                        glade_catalog_get_name (catalog),
                                        &major, &minor);

      /* Special case to mark GTK+ in upper case */
      if (strcmp (glade_catalog_get_name (catalog), "gtk+") == 0)
        label = gtk_label_new ("GTK+");
      else
        label = gtk_label_new (glade_catalog_get_name (catalog));
      gtk_widget_set_halign (label, GTK_ALIGN_START);

      gtk_widget_show (label);
      gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
      hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);

      active_radio = target_radio = NULL;

      for (targets = glade_catalog_get_targets (catalog);
           targets; targets = targets->next)
        {
          GladeTargetableVersion *version = targets->data;
          gchar *name = g_strdup_printf ("%d.%d",
                                         version->major,
                                         version->minor);

          if (!target_radio)
            target_radio = gtk_radio_button_new_with_label (NULL, name);
          else
            target_radio =
                gtk_radio_button_new_with_label_from_widget
                (GTK_RADIO_BUTTON (target_radio), name);
          g_free (name);

          g_signal_connect (G_OBJECT (target_radio), "clicked",
                            G_CALLBACK (target_button_clicked), properties);

          g_object_set_data (G_OBJECT (target_radio), "version", version);
          g_object_set_data (G_OBJECT (target_radio), "catalog",
                             (gchar *) glade_catalog_get_name (catalog));

          gtk_widget_show (target_radio);
          gtk_box_pack_end (GTK_BOX (hbox), target_radio, TRUE, TRUE, 2);

          if (major == version->major && minor == version->minor)
            active_radio = target_radio;

        }

      if (active_radio)
        {
          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_radio), TRUE);
          g_hash_table_insert (priv->target_radios,
                               g_strdup (glade_catalog_get_name (catalog)),
                               gtk_radio_button_get_group (GTK_RADIO_BUTTON
                                                           (active_radio)));
        }
      else
        g_warning ("Corrupt catalog versions");

      gtk_widget_show (hbox);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2);
    }
}

static void
update_prefs_for_resource_path (GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  const gchar *resource_path;

  resource_path = glade_project_get_resource_path (priv->project);
  
  if (resource_path == NULL)
    {
      gtk_entry_set_text (GTK_ENTRY (priv->relative_path_entry), "");
      gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->full_path_button));

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_default_radio), TRUE);
      gtk_widget_set_sensitive (priv->full_path_button, FALSE);
      gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
    }
  else if (g_path_is_absolute (resource_path) &&
           g_file_test (resource_path, G_FILE_TEST_IS_DIR))
    {
      gtk_entry_set_text (GTK_ENTRY (priv->relative_path_entry), "");
      gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (priv->full_path_button),
                                        resource_path);

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_fullpath_radio), TRUE);
      gtk_widget_set_sensitive (priv->full_path_button, TRUE);
      gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
    }
  else
    {
      if (g_strcmp0 (resource_path, gtk_entry_get_text (GTK_ENTRY (priv->relative_path_entry))))
        gtk_entry_set_text (GTK_ENTRY (priv->relative_path_entry), resource_path);

      gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->full_path_button));

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->resource_relative_radio), TRUE);
      gtk_widget_set_sensitive (priv->relative_path_entry, TRUE);
      gtk_widget_set_sensitive (priv->full_path_button, FALSE);
    }
}

static void
glade_project_properties_set_project (GladeProjectProperties *properties,
				      GladeProject           *project)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  /* No strong reference, we belong to the project */
  g_assert (priv->project == NULL);
  priv->project = project;

  g_signal_connect (priv->project, "notify::resource-path",
		    G_CALLBACK (project_resource_path_changed), properties);
  g_signal_connect (priv->project, "notify::template",
		    G_CALLBACK (project_template_changed), properties);
  g_signal_connect (priv->project, "notify::translation-domain",
		    G_CALLBACK (project_domain_changed), properties);
  g_signal_connect (priv->project, "notify::css-provider-path",
		    G_CALLBACK (project_css_provider_path_changed), properties);  
  g_signal_connect (priv->project, "targets-changed",
		    G_CALLBACK (project_targets_changed), properties);
  g_signal_connect (priv->project, "notify::license",
		    G_CALLBACK (project_license_changed), properties);

  target_version_box_fill (properties);
  update_prefs_for_resource_path (properties);

  project_template_changed (project, NULL, properties);
  project_domain_changed (project, NULL, properties);
  project_css_provider_path_changed (project, NULL, properties);
}

static void
glade_project_properties_set_property (GObject *object,
				       guint prop_id,
				       const GValue *value,
				       GParamSpec *pspec)
{
  switch (prop_id)
    {
    case PROP_PROJECT:
      glade_project_properties_set_project (GLADE_PROJECT_PROPERTIES (object),
					    g_value_get_object (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

/********************************************************
 *                     Callbacks                        *
 ********************************************************/
static void
target_button_clicked (GtkWidget              *widget,
		       GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GladeTargetableVersion        *version;
  gchar                         *catalog;

  if (priv->ignore_ui_cb)
    return;

  version = g_object_get_data (G_OBJECT (widget), "version");
  catalog = g_object_get_data (G_OBJECT (widget), "catalog");
  glade_command_set_project_target (priv->project, catalog, version->major, version->minor);
}

static void
resource_default_toggled (GtkWidget              *widget,
			  GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  if (priv->ignore_ui_cb || 
      !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
    return;

  glade_command_set_project_resource_path (priv->project, NULL);
}

static void
resource_relative_toggled (GtkWidget              *widget,
			   GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (widget);
  
  if (priv->ignore_ui_cb || !gtk_toggle_button_get_active (toggle))
    return;

  glade_command_set_project_resource_path (priv->project, NULL);
  gtk_toggle_button_set_active (toggle, TRUE);
  gtk_widget_set_sensitive (priv->relative_path_entry, TRUE);
  gtk_widget_set_sensitive (priv->full_path_button, FALSE);
}

static void
resource_fullpath_toggled (GtkWidget              *widget,
			   GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (widget);

  if (priv->ignore_ui_cb || !gtk_toggle_button_get_active (toggle))
    return;

  glade_command_set_project_resource_path (priv->project, NULL);
  gtk_toggle_button_set_active (toggle, TRUE);
  gtk_widget_set_sensitive (priv->relative_path_entry, FALSE);
  gtk_widget_set_sensitive (priv->full_path_button, TRUE);
}

static void
on_relative_path_entry_insert_text (GtkEditable            *editable,
                                    gchar                  *new_text,
                                    gint                    new_text_length,
                                    gint                   *position,
                                    GladeProjectProperties *properties) 
{
  GString *fullpath = g_string_new (gtk_entry_get_text (GTK_ENTRY(editable)));

  g_string_insert (fullpath, *position, new_text);
  
  if (g_path_is_absolute (fullpath->str))
    g_signal_stop_emission_by_name (editable, "insert-text");
  
  g_string_free (fullpath, TRUE);
}

static void
on_relative_path_entry_changed (GtkEntry *entry, GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  if (priv->ignore_ui_cb)
    return;

  glade_command_set_project_resource_path (priv->project, gtk_entry_get_text (entry));
}

static void
resource_full_path_set (GtkFileChooserButton *button, GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  gchar *text;
  
  if (priv->ignore_ui_cb)
    return;
  
  text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (button));
  glade_command_set_project_resource_path (priv->project, text);
  g_free (text);
}

static void
on_template_combo_box_changed (GtkComboBox            *combo,
			       GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GtkTreeIter iter;

  if (priv->ignore_ui_cb)
    return;
  
  if (gtk_combo_box_get_active_iter (combo, &iter))
    {
      GladeWidget *gwidget;
      GObject *object;

      gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object, -1);
      
      gwidget = glade_widget_get_from_gobject (object);

      glade_command_set_project_template (priv->project, gwidget);
    }
}

static void
on_template_checkbutton_toggled (GtkToggleButton        *togglebutton,
                                 GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  if (priv->ignore_ui_cb)
    return;
  
  if (gtk_toggle_button_get_active (togglebutton))
    {
      gboolean composite = FALSE;
      GList *l;

      for (l = glade_project_toplevels (priv->project); l; l = l->next)
	{
	  GObject *object = l->data;
	  GladeWidget *gwidget;

	  gwidget = glade_widget_get_from_gobject (object);

	  if (GTK_IS_WIDGET (object))
	    {
	      glade_command_set_project_template (priv->project, gwidget);
	      composite = TRUE;
	      break;
	    }
	}

      if (!composite)
	gtk_toggle_button_set_active (togglebutton, FALSE);
    }
  else
    glade_command_set_project_template (priv->project, NULL);
}

static gboolean
template_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
  GtkTreeIter parent;
  gboolean visible;
  GObject *object;

  visible = !gtk_tree_model_iter_parent (model, &parent, iter);

  if (visible)
    {
      gtk_tree_model_get (model, iter,
			  GLADE_PROJECT_MODEL_COLUMN_OBJECT, &object,
			  -1);

      visible = GTK_IS_WIDGET (object);
      g_object_unref (object);
    }

  return visible;
}

static GtkTreeModel *
glade_project_toplevel_model_filter_new (GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GtkTreeModel *model;

  model = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->project), NULL);
  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
                                          template_visible_func, NULL, NULL);
  return model;
}

static void
verify_clicked (GtkWidget *button, GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  if (glade_project_verify (priv->project, FALSE,
			    GLADE_VERIFY_VERSIONS     |
			    GLADE_VERIFY_DEPRECATIONS |
			    GLADE_VERIFY_UNRECOGNIZED))
    {
      gchar *name = glade_project_get_name (priv->project);
      glade_util_ui_message (glade_app_get_window (),
                             GLADE_UI_INFO, NULL,
                             _("Project %s has no deprecated widgets "
                               "or version mismatches."), name);
      g_free (name);
    }
}

static void
on_domain_entry_changed (GtkWidget *entry, GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  if (priv->ignore_ui_cb)
    return;

  glade_command_set_project_domain (priv->project, gtk_entry_get_text (GTK_ENTRY (entry)));
}

#define GNU_GPLv2_TEXT \
    "$(name) - $(description)\n" \
    "Copyright (C) $(copyright)\n" \
    "\n" \
    "This program is free software; you can redistribute it and/or\n" \
    "modify it under the terms of the GNU General Public License\n" \
    "as published by the Free Software Foundation; either version 2\n" \
    "of the License, or (at your option) any later version.\n" \
    "\n" \
    "This program is distributed in the hope that it will be useful,\n" \
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" \
    "GNU General Public License for more details.\n" \
    "\n" \
    "You should have received a copy of the GNU General Public License\n" \
    "along with this program; if not, write to the Free Software\n" \
    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n"

#define GNU_LGPLv2_TEXT \
    "$(name) - $(description)\n" \
    "Copyright (C) $(copyright)\n" \
    "\n" \
    "This library is free software; you can redistribute it and/or\n" \
    "modify it under the terms of the GNU Lesser General Public\n" \
    "License as published by the Free Software Foundation; either\n" \
    "version 2.1 of the License, or (at your option) any later version.\n" \
    "\n" \
    "This library is distributed in the hope that it will be useful,\n" \
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" \
    "Lesser General Public License for more details.\n" \
    "\n" \
    "You should have received a copy of the GNU Lesser General Public\n" \
    "License along with this library; if not, write to the Free Software\n" \
    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n"

#define GNU_GPLv3_TEXT \
    "Copyright (C) $(copyright)\n" \
    "\n" \
    "This file is part of $(name).\n" \
    "\n" \
    "$(name) is free software: you can redistribute it and/or modify\n" \
    "it under the terms of the GNU General Public License as published by\n" \
    "the Free Software Foundation, either version 3 of the License, or\n" \
    "(at your option) any later version.\n" \
    "\n" \
    "$(name) is distributed in the hope that it will be useful,\n" \
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" \
    "GNU General Public License for more details.\n" \
    "\n" \
    "You should have received a copy of the GNU General Public License\n" \
    "along with $(name).  If not, see <http://www.gnu.org/licenses/>.\n"

#define GNU_LGPLv3_TEXT \
    "Copyright (C) $(copyright)\n" \
    "\n" \
    "This file is part of $(name).\n" \
    "\n" \
    "$(name) is free software: you can redistribute it and/or modify\n" \
    "it under the terms of the GNU Lesser General Public License as published by\n" \
    "the Free Software Foundation, either version 3 of the License, or\n" \
    "(at your option) any later version.\n" \
    "\n" \
    "$(name) is distributed in the hope that it will be useful,\n" \
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" \
    "GNU Lesser General Public License for more details.\n" \
    "\n" \
    "You should have received a copy of the GNU Lesser General Public License\n" \
    "along with $(name).  If not, see <http://www.gnu.org/licenses/>.\n"

#define BSD3c_TEXT \
    "Copyright (c) $(copyright)\n" \
    "All rights reserved.\n" \
    "\n" \
    "Redistribution and use in source and binary forms, with or without\n" \
    "modification, are permitted provided that the following conditions are met:\n" \
    "    * Redistributions of source code must retain the above copyright\n" \
    "      notice, this list of conditions and the following disclaimer.\n" \
    "    * Redistributions in binary form must reproduce the above copyright\n" \
    "      notice, this list of conditions and the following disclaimer in the\n" \
    "      documentation and/or other materials provided with the distribution.\n" \
    "    * Neither the name of the <organization> nor the\n" \
    "      names of its contributors may be used to endorse or promote products\n" \
    "      derived from this software without specific prior written permission.\n" \
    "\n" \
    "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n" \
    "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n" \
    "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n" \
    "DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n" \
    "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" \
    "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" \
    "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n" \
    "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" \
    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n" \
    "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"

#define BSD2c_TEXT \
    "Copyright (c) $(copyright)\n" \
    "All rights reserved.\n" \
    "\n" \
    "Redistribution and use in source and binary forms, with or without\n" \
    "modification, are permitted provided that the following conditions are met:\n" \
    "\n" \
    "1. Redistributions of source code must retain the above copyright notice, this\n" \
    "   list of conditions and the following disclaimer. \n" \
    "2. Redistributions in binary form must reproduce the above copyright notice,\n" \
    "   this list of conditions and the following disclaimer in the documentation\n" \
    "   and/or other materials provided with the distribution. \n" \
    "\n" \
    "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n" \
    "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n" \
    "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n" \
    "DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\n" \
    "ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" \
    "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" \
    "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n" \
    "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" \
    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n" \
    "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"

#define APACHE2_TEXT \
    "Copyright $(copyright)\n" \
    "\n" \
    "Licensed under the Apache License, Version 2.0 (the \"License\"); \n" \
    "you may not use this file except in compliance with the License. \n" \
    "You may obtain a copy of the License at \n" \
    "\n" \
    "    http://www.apache.org/licenses/LICENSE-2.0 \n" \
    "\n" \
    "Unless required by applicable law or agreed to in writing, software \n" \
    "distributed under the License is distributed on an \"AS IS\" BASIS, \n" \
    "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n" \
    "See the License for the specific language governing permissions and \n" \
    "limitations under the License. \n"

#define GNU_ALL_PERMISSIVE_TEXT \
    "Copyright (C) $(copyright)\n" \
    "\n" \
    "Copying and distribution of this file, with or without modification,\n" \
    "are permitted in any medium without royalty provided the copyright\n" \
    "notice and this notice are preserved.  This file is offered as-is,\n" \
    "without any warranty.\n"

#define MIT_TEXT \
    "The MIT License (MIT)\n" \
    "\n" \
    "Copyright (c) $(copyright)\n" \
    "\n" \
    "Permission is hereby granted, free of charge, to any person obtaining a copy\n" \
    "of this software and associated documentation files (the \"Software\"), to deal\n" \
    "in the Software without restriction, including without limitation the rights\n" \
    "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n" \
    "copies of the Software, and to permit persons to whom the Software is\n" \
    "furnished to do so, subject to the following conditions:\n" \
    "\n" \
    "The above copyright notice and this permission notice shall be included in\n" \
    "all copies or substantial portions of the Software.\n" \
    "\n" \
    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n" \
    "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" \
    "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n" \
    "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n" \
    "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n" \
    "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n" \
    "THE SOFTWARE.\n"

static gchar *
gpp_get_license_from_id (const gchar *id)
{
  if (!g_strcmp0 (id, "gplv2"))
    return GNU_GPLv2_TEXT;
  else if (!g_strcmp0 (id, "gplv3"))
    return GNU_GPLv3_TEXT;
  else if (!g_strcmp0 (id, "lgplv2"))
    return GNU_LGPLv2_TEXT;
  else if (!g_strcmp0 (id, "lgplv3"))
    return GNU_LGPLv3_TEXT;
  else if (!g_strcmp0 (id, "bsd2c"))
    return BSD2c_TEXT;
  else if (!g_strcmp0 (id, "bsd3c"))
    return BSD3c_TEXT;
  else if (!g_strcmp0 (id, "apache2"))
    return APACHE2_TEXT;
  else if (!g_strcmp0 (id, "mit"))
    return MIT_TEXT;
  else if (!g_strcmp0 (id, "all_permissive"))
    return GNU_ALL_PERMISSIVE_TEXT;
  else
    return NULL;
}

static gint
string_count_new_lines (const gchar *str)
{
  gint c = 0;

  while (*str)
    {
      if (*str == '\n')
        c++;
      str = g_utf8_next_char (str);
    }
  return c;
}

static void
gpp_update_license (GladeProjectProperties *properties, gchar *license)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  const gchar *name, *description;
  gchar *copyright, *authors;

  if (!license)
    return;

  /* get data */
  name = gtk_entry_buffer_get_text (priv->name_entrybuffer);
  description = gtk_entry_buffer_get_text (priv->description_entrybuffer);
  
  g_object_get (priv->copyright_textbuffer, "text", &copyright, NULL);
  g_object_get (priv->authors_textbuffer, "text", &authors, NULL);
  
  /* Now we can replace strings in the license template */
  license = _glade_util_strreplace (license, FALSE, "$(name)", name);
  license = _glade_util_strreplace (license, TRUE, "$(description)", description);
  license = _glade_util_strreplace (license, TRUE, "$(copyright)", copyright);

  if (authors && *authors)
    {
      gchar *tmp = license;

      if (string_count_new_lines (authors))
        license = g_strconcat (license, "\n", "Authors:", "\n", authors, NULL);
      else
        license = g_strconcat (license, "\n", "Author:", " ", authors, NULL);

      g_free (tmp);
    }
  
  gtk_text_buffer_set_text (priv->license_textbuffer, license, -1);

  g_free (license);
  g_free (copyright);
  g_free (authors);
}

static void
on_license_data_changed (GladeProjectProperties *properties)
{
  const gchar *id = gtk_combo_box_get_active_id (properties->priv->license_comboboxtext);
  gchar *license;

  if ((license = gpp_get_license_from_id (id)))
    gpp_update_license (properties, license);
}

static void
on_license_comboboxtext_changed (GtkComboBox            *widget,
                                 GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  gchar *license;

  if ((license = gpp_get_license_from_id (gtk_combo_box_get_active_id (widget))))
    {
      gpp_update_license (properties, license);
      gtk_text_view_set_editable (priv->license_textview, FALSE);
    }
  else
    {
      /* Other license */
      gtk_text_buffer_set_text (priv->license_textbuffer, "", -1);      
      gtk_text_view_set_editable (priv->license_textview, TRUE);
      gtk_widget_grab_focus (GTK_WIDGET (priv->license_textview));
    }
}

static void
on_glade_project_properties_hide (GtkWidget              *widget,
                                  GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GtkTextIter start, end;
  gchar *license;

  gtk_text_buffer_get_bounds (priv->license_textbuffer, &start, &end);
  license = gtk_text_buffer_get_text (priv->license_textbuffer, &start, &end, FALSE);
  g_strstrip (license);

  glade_command_set_project_license (priv->project, (license[0] != '\0') ? license : NULL);

  g_free (license);
}

static void
on_css_checkbutton_toggled (GtkWidget *widget, GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  if (priv->ignore_ui_cb)
    return;

  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
    {
      gtk_widget_set_sensitive (priv->css_filechooser, TRUE);
    }
  else
    {
      gtk_widget_set_sensitive (priv->css_filechooser, FALSE);
      glade_project_set_css_provider_path (priv->project, NULL);
    }
}

static void
on_css_filechooser_file_set (GtkFileChooserButton   *widget,
                             GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  const gchar *path;

  if (priv->ignore_ui_cb)
    return;

  path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));

  glade_project_set_css_provider_path (priv->project, path);
}

/******************************************************
 *                   Project Callbacks                *
 ******************************************************/
static void
project_targets_changed (GladeProject           *project,
			 GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GList *list;
  GSList *radios, *l;

  priv->ignore_ui_cb = TRUE;

  /* For each catalog */
  for (list = glade_app_get_catalogs (); list; list = g_list_next (list))
    {
      GladeTargetableVersion *version;
      GladeCatalog *catalog = list->data;
      gint minor, major;

      /* Skip if theres only one option */
      if (g_list_length (glade_catalog_get_targets (catalog)) <= 1)
        continue;

      /* Fetch the version for this project */
      glade_project_get_target_version (priv->project,
                                        glade_catalog_get_name (catalog),
                                        &major, &minor);

      /* Fetch the radios for this catalog  */
      if (priv->target_radios &&
	  (radios = g_hash_table_lookup (priv->target_radios, glade_catalog_get_name (catalog))) != NULL)
	{
	  for (l = radios; l; l = l->next)
	    {
	      GtkWidget *radio = l->data;

	      /* Activate the appropriate button for the project/catalog */
	      version = g_object_get_data (G_OBJECT (radio), "version");
	      if (version->major == major && version->minor == minor)
		{
		  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
		  break;
		}
	    }
	}
    }
  priv->ignore_ui_cb = FALSE;
}

static void
project_domain_changed (GladeProject           *project,
			GParamSpec             *pspec,
			GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  const gchar *domain;

  priv->ignore_ui_cb = TRUE;
  
  domain = glade_project_get_translation_domain (priv->project);
  gtk_entry_set_text (GTK_ENTRY (priv->domain_entry), domain ? domain : "");

  priv->ignore_ui_cb = FALSE;
}

static void
project_resource_path_changed (GladeProject           *project,
			       GParamSpec             *pspec,
			       GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  priv->ignore_ui_cb = TRUE;
  update_prefs_for_resource_path (properties);
  priv->ignore_ui_cb = FALSE;
}

static void
project_template_changed (GladeProject           *project,
			  GParamSpec             *pspec,
			  GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gboolean valid;
  gboolean template_found = FALSE;

  priv->ignore_ui_cb = TRUE;

  model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox));
  if (!model)
    {
      model = glade_project_toplevel_model_filter_new (properties);

      gtk_combo_box_set_model (GTK_COMBO_BOX (priv->template_combobox), model);
      g_object_unref (model);
    }

  valid = gtk_tree_model_get_iter_first (model, &iter);
  while (valid)
    {
      GladeWidget *gwidget;
      GObject *obj;
      
      gtk_tree_model_get (model, &iter,
                          GLADE_PROJECT_MODEL_COLUMN_OBJECT, &obj,
                          -1);

      gwidget = glade_widget_get_from_gobject (obj);
      g_object_unref (obj);

      if (gwidget == glade_project_get_template (priv->project))
	{
          gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), &iter);

	  template_found = TRUE;
	  break;
        }

      valid = gtk_tree_model_iter_next (model, &iter);
    }

  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->template_checkbutton), template_found);
  gtk_widget_set_sensitive (priv->template_combobox, template_found);

  if (!template_found && gtk_combo_box_get_model (GTK_COMBO_BOX (priv->template_combobox)))
    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->template_combobox), NULL);

  priv->ignore_ui_cb = FALSE;
}

static void
project_license_changed (GladeProject           *project,
                         GParamSpec             *pspec,
			 GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;

  priv->ignore_ui_cb = TRUE;  
  gtk_text_buffer_set_text (priv->license_textbuffer, 
                            glade_project_get_license (project),
                            -1);
  priv->ignore_ui_cb = FALSE;
}

static void
project_css_provider_path_changed (GladeProject           *project,
                                   GParamSpec             *pspec,
                                   GladeProjectProperties *properties)
{
  GladeProjectPropertiesPrivate *priv = properties->priv;
  const gchar *filename = glade_project_get_css_provider_path (project);
  GtkFileChooser *chooser = GTK_FILE_CHOOSER (priv->css_filechooser);

  priv->ignore_ui_cb = TRUE;
  
  if (filename)
    {
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->css_checkbutton), TRUE);
      gtk_widget_set_sensitive (priv->css_filechooser, TRUE);
      gtk_file_chooser_set_filename (chooser, filename);
    }
  else
    {
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->css_checkbutton), FALSE);
      gtk_widget_set_sensitive (priv->css_filechooser, FALSE);
      gtk_file_chooser_unselect_all (chooser);
    }

  priv->ignore_ui_cb = FALSE;
}

/* Private API */

void
_glade_project_properties_set_license_data (GladeProjectProperties *props,
                                            const gchar *license,
                                            const gchar *name,
                                            const gchar *description,
                                            const gchar *copyright,
                                            const gchar *authors)
{
  if (!license ||
      !gtk_combo_box_set_active_id (props->priv->license_comboboxtext, license))
    {
      gtk_combo_box_set_active_id (props->priv->license_comboboxtext, "other");
      name = description = copyright = authors = "";
      license = "other";
    }
        
  gtk_entry_buffer_set_text (props->priv->name_entrybuffer, name ? name : "", -1);
  gtk_entry_buffer_set_text (props->priv->description_entrybuffer, description ? description : "", -1);

  gtk_text_buffer_set_text (props->priv->copyright_textbuffer, copyright ? copyright : "", -1);
  gtk_text_buffer_set_text (props->priv->authors_textbuffer, authors ? authors : "", -1);

  gpp_update_license (props, gpp_get_license_from_id (license));
}

void
_glade_project_properties_get_license_data (GladeProjectProperties *props,
                                            gchar **license,
                                            gchar **name,
                                            gchar **description,
                                            gchar **copyright,
                                            gchar **authors)
{
  const gchar *id = gtk_combo_box_get_active_id (props->priv->license_comboboxtext);

  if (!g_strcmp0 (id, "other"))
    {
      *license = *name = *description = *copyright = *authors = NULL;
      return;
    }

  *license = g_strdup (id);
  *name = g_strdup (gtk_entry_buffer_get_text (props->priv->name_entrybuffer));
  *description = g_strdup (gtk_entry_buffer_get_text (props->priv->description_entrybuffer));

  g_object_get (props->priv->copyright_textbuffer, "text", copyright, NULL);
  g_object_get (props->priv->authors_textbuffer, "text", authors, NULL);
}

/******************************************************
 *                         API                        *
 ******************************************************/
GtkWidget *
glade_project_properties_new (GladeProject *project)
{
  return g_object_new (GLADE_TYPE_PROJECT_PROPERTIES, "project", project, NULL);
}
