/** -*- Mode: C++; tab-width: 4 -*-
 * vim: sw=4:ts=4:
 *
 * Gnome Apt source line druid
 *
 * 	(C) 1999 Olivier Gravel Aubin <ogaubin@ucalgary.ca>
 * 	    2002, 2003 Filip Van Raemdonck <mechanix@debian.org>
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 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
 *
 * 	$Id$
 *
 **/

/* Needs to be before libgnome/gnome-i18n.h */
#include "sources.h"

#include <libgnome/gnome-i18n.h>
#include <libgnomeui/gnome-druid.h>
#include <libgnomeui/gnome-druid-page-standard.h>
#include <libgnomeui/gnome-entry.h>

#include "sources-wizard.h"

#include "gdeb/debianlogo.xpm"

#define GAPT_PAD 6

SourcesWizard::SourcesWizard()
  : wizard_(0), drud_(0), page_dist_(0), page_uri_(0),
    page_section_(0), dist_stable_(0), dist_unstable_(0),
    dist_other_(0), dist_entry_box_(0), section_main_(0),
    section_contrib_(0), section_non_free_(0), section_non_us_(0),
    current_page_(PageInvalid)
{

}

SourcesWizard::~SourcesWizard()
{
  if (wizard_)
    gtk_widget_destroy(wizard_);
}

void
SourcesWizard::add (GtkWidget* parent) {
  if (wizard_ != 0 && GTK_WIDGET_REALIZED(wizard_)) {
    gdk_window_show(wizard_->window);
    gdk_window_raise(wizard_->window);
    return;
  }

	wizard_ = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_transient_for (GTK_WINDOW (wizard_), GTK_WINDOW (parent));

  // zero wizard_ if the widget is destroyed; paranoia,
  //  not really necessary.
	g_signal_connect (G_OBJECT (wizard_), "destroy", G_CALLBACK (gtk_widget_destroyed), &wizard_);
	g_signal_connect (G_OBJECT (wizard_), "delete_event", G_CALLBACK (close_cb), this);

  //  gtk_window_set_default_size(GTK_WINDOW(wizard_),
  //                              100, 400);

  gtk_window_set_title(GTK_WINDOW(wizard_), _("Package Source Setup"));

	drud_ = gnome_druid_new ();
	g_signal_connect (G_OBJECT (drud_), "cancel", G_CALLBACK (cancel_cb), this);

	GdkPixbuf* logo = gdk_pixbuf_new_from_xpm_data (debianlogo_xpm);

  //
  // Wizard Page for "Distribution"
  //

	page_dist_ = gnome_druid_page_standard_new ();
	g_signal_connect (G_OBJECT (page_dist_), "next", G_CALLBACK (next_cb), this);

	gnome_druid_page_standard_set_logo (GNOME_DRUID_PAGE_STANDARD (page_dist_), logo);
	gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (page_dist_), _("Select Distribution"));

  GtkWidget* dist_vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_set_border_width (GTK_CONTAINER (dist_vbox), GAPT_PAD);

	GtkWidget* dist_label = gtk_label_new (
	    _("The distribution is the version of the Debian packages you wish "
	      "access. This can be \"stable\", for the latest official release, "
	      "or \"unstable\" for the current development version; you can also "
	      "use a symbolic name, such as \"woody\" or \"sid\"."));

  gtk_label_set_line_wrap(GTK_LABEL(dist_label),
                          TRUE);

  gtk_label_set_justify(GTK_LABEL(dist_label),
                        GTK_JUSTIFY_LEFT);

  gtk_misc_set_alignment(GTK_MISC(dist_label), 0.0, 0.5);
	gtk_box_pack_start (GTK_BOX (dist_vbox), dist_label, TRUE, TRUE, GAPT_PAD);

  GSList* dist_list = NULL;

  dist_stable_ = gtk_radio_button_new_with_label(dist_list,
                                                 _("stable"));
	gtk_box_pack_start (GTK_BOX (dist_vbox), dist_stable_, FALSE, FALSE, GAPT_PAD);
	dist_list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (dist_stable_));

  dist_unstable_ = gtk_radio_button_new_with_label(dist_list,
                                                   _("unstable"));
	gtk_box_pack_start (GTK_BOX (dist_vbox), dist_unstable_, FALSE, FALSE, GAPT_PAD);
	dist_list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (dist_unstable_));

  dist_other_ = gtk_radio_button_new_with_label(dist_list,
                                                _("other"));
	gtk_box_pack_start (GTK_BOX (dist_vbox), dist_other_, FALSE, FALSE, GAPT_PAD);
	g_signal_connect (G_OBJECT (dist_other_), "toggled", G_CALLBACK (toggled_cb), this);

  dist_entry_box_ = gtk_entry_new();

  gtk_widget_set_sensitive(GTK_WIDGET(dist_entry_box_), FALSE);

	gtk_box_pack_start (GTK_BOX (dist_vbox), dist_entry_box_, FALSE, FALSE, GAPT_PAD);

	gtk_box_pack_start (
	      GTK_BOX (GNOME_DRUID_PAGE_STANDARD (page_dist_)->vbox),
	      dist_vbox, FALSE, FALSE, GAPT_PAD);
	gnome_druid_append_page (GNOME_DRUID (drud_), GNOME_DRUID_PAGE (page_dist_));

  //
  // Wizard Page for "URI"
  //
	page_uri_ = gnome_druid_page_standard_new ();
	g_signal_connect (G_OBJECT (page_uri_), "back", G_CALLBACK (back_cb), this);
	g_signal_connect (G_OBJECT (page_uri_), "next", G_CALLBACK (next_cb), this);

	gnome_druid_page_standard_set_logo (GNOME_DRUID_PAGE_STANDARD (page_uri_), logo);
	gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (page_uri_), _("Provide Uniform Resource Identifier"));

  GtkWidget* uri_vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_set_border_width (GTK_CONTAINER (uri_vbox), GAPT_PAD);

  GtkWidget* uri_label = gtk_label_new(_("The Uniform Resource Identifier (or URI) is a method of identifying files, whether they are on the local disk or accessible via HTTP or FTP. You must specify the desired source type, server (for HTTP and FTP), and location below. The location (a directory) should contain a \"dists\" subdirectory."));

  gtk_label_set_line_wrap(GTK_LABEL(uri_label),
                          TRUE);

  gtk_label_set_justify(GTK_LABEL(uri_label),
                        GTK_JUSTIFY_LEFT);

  gtk_misc_set_alignment(GTK_MISC(uri_label), 0.0, 0.5);
	gtk_box_pack_start (GTK_BOX (uri_vbox), uri_label, TRUE, TRUE, GAPT_PAD);

	uri_entry_box_ = gnome_entry_new ("gnomeapt_sources_uris");
  gnome_entry_append_history(GNOME_ENTRY(uri_entry_box_), TRUE,
                             _("http://http.us.debian.org/debian"));

  gnome_entry_append_history(GNOME_ENTRY(uri_entry_box_), TRUE,
                             _("ftp://ftp.debian.org/debian"));

  gnome_entry_append_history(GNOME_ENTRY(uri_entry_box_), TRUE,
                             _("file:/home/debian"));
	gtk_box_pack_start (GTK_BOX (uri_vbox), uri_entry_box_, FALSE, FALSE, GAPT_PAD);
	gtk_box_pack_start (
	      GTK_BOX (GNOME_DRUID_PAGE_STANDARD (page_uri_)->vbox),
	      uri_vbox, FALSE, FALSE, GAPT_PAD);
	gnome_druid_append_page (GNOME_DRUID (drud_), GNOME_DRUID_PAGE (page_uri_));

  //
  // Wizard Page for "Section"
  //
	page_section_ = gnome_druid_page_standard_new ();
	g_signal_connect (G_OBJECT (page_section_), "back", G_CALLBACK (back_cb), this);
	g_signal_connect (G_OBJECT (page_section_), "finish", G_CALLBACK (finish_cb), this);

	gnome_druid_page_standard_set_logo (GNOME_DRUID_PAGE_STANDARD (page_section_), logo);
	gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (page_section_), _("Choose Section"));

  GtkWidget* section_vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_set_border_width (GTK_CONTAINER (section_vbox), GAPT_PAD);

	GtkWidget* section_label = gtk_label_new (
	    _("The section classifies the packages based on their redistribution "
	      "policy. Packages which are considered to freely usable, modifiable "
	      "and distributable are in \"main\", except for those encumbered by "
	      "US patents which are in \"non-US\". Packages with restricted "
	      "licenses are in \"non-free\" while packages who are in \"contrib\" "
	      "do not have license restrictions themselves but are dependent on "
	      "such packages or on non-packaged software to be useful at all."));

  gtk_label_set_line_wrap(GTK_LABEL(section_label),
                          TRUE);

  gtk_label_set_justify(GTK_LABEL(section_label),
                        GTK_JUSTIFY_LEFT);

  gtk_misc_set_alignment(GTK_MISC(section_label), 0.0, 0.5);
	gtk_box_pack_start (GTK_BOX (section_vbox), section_label, TRUE, TRUE, GAPT_PAD);

  section_main_ = gtk_check_button_new_with_label("main");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (section_main_), TRUE);
	gtk_box_pack_start (GTK_BOX (section_vbox), section_main_, FALSE, FALSE, GAPT_PAD);

  section_contrib_ = gtk_check_button_new_with_label("contrib");
	gtk_box_pack_start (GTK_BOX (section_vbox), section_contrib_, FALSE, FALSE, GAPT_PAD);

  section_non_free_ = gtk_check_button_new_with_label("non-free");
	gtk_box_pack_start (GTK_BOX (section_vbox), section_non_free_, TRUE, TRUE, GAPT_PAD);

  section_non_us_ = gtk_check_button_new_with_label("non-US");
	gtk_box_pack_start (GTK_BOX (section_vbox), section_non_us_, TRUE, TRUE, GAPT_PAD);

	gtk_box_pack_start (
	      GTK_BOX (GNOME_DRUID_PAGE_STANDARD (page_section_)->vbox),
	      section_vbox, FALSE, FALSE, GAPT_PAD);
	gnome_druid_append_page (GNOME_DRUID (drud_), GNOME_DRUID_PAGE (page_section_));

  // Build and show the window

  current_page_ = PageDist;

  config_current_page();

  gtk_container_add(GTK_CONTAINER(wizard_), drud_);

  gtk_widget_show_all(wizard_);
}

gint
SourcesWizard::close_cb(GtkWidget* w, GdkEvent* e, gpointer data)
{
  SourcesWizard* ptr = static_cast<SourcesWizard*>(data);

  ptr->close();

  // This is a delete_event callback; we return TRUE to tell Gtk
  // not to gtk_widget_destroy() the window.
  return TRUE;
}

void
SourcesWizard::close()
{
  if (wizard_ != 0)
    gtk_widget_destroy(wizard_);

  wizard_ = 0;
}

void
SourcesWizard::finish_cb (GnomeDruidPage* p, gpointer arg, gpointer data) {
  SourcesWizard* ptr = static_cast<SourcesWizard*>(data);

  ptr->finish();
}

void
SourcesWizard::finish()
{
  Sources::SourceAddResult error = Sources::Ok;

  char string_stable[] = "stable";
  char string_unstable[] = "unstable";
	string dist, uri, sections[4];

	int last_section = 0;

  // Get the selections
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dist_stable_)))
    {
      dist = string_stable;
    }
  else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dist_unstable_)))
    {
      dist = string_unstable;
    }
  else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dist_other_)))
    {
		dist = gtk_entry_get_text (GTK_ENTRY (dist_entry_box_));

		if (dist.length() == 0) {
          error = Sources::BadDist;
        }
    }
  else
    {
      error = Sources::BadDist;
    }

  if (error == Sources::Ok)
    {
		uri = gtk_entry_get_text (GTK_ENTRY (gnome_entry_gtk_entry (GNOME_ENTRY (uri_entry_box_))));
		if (uri.length() == 0) {
        error = Sources::BadURI;
		}
    }

  if (error == Sources::Ok &&
     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(section_main_)))
    {
		sections[last_section++] = "main";
    }
  
  if (error == Sources::Ok &&
     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(section_contrib_)))
    {
		sections[last_section++] = "contrib";
    }
      
  if (error == Sources::Ok &&
     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(section_non_free_)))
    {
		sections[last_section++] = "non-free";
    }
      
  if (error == Sources::Ok &&
     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(section_non_us_)))
    {
		sections[last_section++] = "non-US";
    }

	g_assert (last_section <= 4);
	error = gnome_apt_sources()->add_source (dist, uri, sections, last_section);

  /*
   * If we got an error at some stage (in this function, or when adding the
   * source), tell the user and switch the wizard to the offending page.
   * If everything is ok (error is Ok, destroy the wizard window, returning
   * to the source editing window.
   */

  if (error != Sources::Ok)
    {
      const gchar* error_page = NULL;
      
      switch (error)
        {
        case Sources::BadDist:
          current_page_ = PageDist;
          error_page = _("distribution");
          break;
        case Sources::BadURI:
          current_page_ = PageURI;
          error_page = _("URI");
          break;
        case Sources::BadSection:
          current_page_ = PageSection;
          error_page = _("section");
          break;
        default:
          g_assert_not_reached();
        }

		GtkWidget* err_dialog = gtk_message_dialog_new (
			GTK_WINDOW(wizard_), GTK_DIALOG_DESTROY_WITH_PARENT,
			GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
			_("Missing or invalid %s."), error_page);
		gtk_dialog_run (GTK_DIALOG (err_dialog));
		gtk_widget_destroy (err_dialog);

      config_current_page();
    }
  else
    {
      if (wizard_ != 0)
        gtk_widget_destroy(wizard_);
      
      wizard_ = 0;
    }      
}

void
SourcesWizard::cancel_cb (GnomeDruid* p, gpointer data) {
  SourcesWizard* ptr = static_cast<SourcesWizard*>(data);

  ptr->cancel();
}

void
SourcesWizard::cancel()
{
  if (wizard_ != 0)
    gtk_widget_destroy(wizard_);

  wizard_ = 0;
}

gboolean
SourcesWizard::next_cb (GnomeDruidPage* p, gpointer arg, gpointer data) {
  SourcesWizard* ptr = static_cast<SourcesWizard*>(data);

  return ptr->next();
}

gboolean
SourcesWizard::next()
{
  switch (current_page_)
    {
    case PageDist:
      current_page_ = PageURI;
      break;
    case PageURI:
      current_page_ = PageSection;
      break;
    case PageSection:
      g_assert_not_reached(); // should have had a finish button
      break;
    default:
      g_assert_not_reached();
      break;
    }
  
  config_current_page();

  return TRUE;
}

gboolean
SourcesWizard::back_cb (GnomeDruidPage* p, gpointer arg, gpointer data) {
  SourcesWizard* ptr = static_cast<SourcesWizard*>(data);

  return ptr->back();
}

gboolean
SourcesWizard::back()
{
  switch (current_page_)
    {
    case PageDist:
      g_assert_not_reached(); // back button should have been insensitive
      break;
    case PageURI:
      current_page_ = PageDist;
      break;
    case PageSection:
      current_page_ = PageURI;
      break;
    default:
      g_assert_not_reached();
      break;
    }

  config_current_page();

  return TRUE;
}

void
SourcesWizard::toggled_cb(GtkToggleButton* b, gpointer data)
{
  SourcesWizard* ptr = static_cast<SourcesWizard*>(data);

  ptr->toggled(b);
}

void
SourcesWizard::toggled(GtkToggleButton* b)
{
  if (GTK_WIDGET(b) == dist_other_)
    {
      if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b)))
        gtk_widget_set_sensitive(GTK_WIDGET(dist_entry_box_), TRUE);
      else
        gtk_widget_set_sensitive(GTK_WIDGET(dist_entry_box_), FALSE);
    }
}

void
SourcesWizard::config_current_page()
{
  switch (current_page_)
    {
    case PageDist:
			gnome_druid_set_page (GNOME_DRUID (drud_), GNOME_DRUID_PAGE (page_dist_));
			gnome_druid_set_show_finish (GNOME_DRUID (drud_), FALSE);
			gnome_druid_set_buttons_sensitive (GNOME_DRUID (drud_), FALSE, TRUE, TRUE, FALSE);
      break;
    case PageURI:
			gnome_druid_set_page (GNOME_DRUID (drud_), GNOME_DRUID_PAGE (page_uri_));
			gnome_druid_set_show_finish (GNOME_DRUID (drud_), FALSE);
			gnome_druid_set_buttons_sensitive (GNOME_DRUID (drud_), TRUE, TRUE, TRUE, FALSE);
      break;
    case PageSection:
			gnome_druid_set_page (GNOME_DRUID (drud_), GNOME_DRUID_PAGE (page_section_));
			gnome_druid_set_show_finish (GNOME_DRUID (drud_), TRUE);
			gnome_druid_set_buttons_sensitive (GNOME_DRUID (drud_), TRUE, TRUE, TRUE, FALSE);
      break;
    default:
      // How did we get here?!?
      g_assert_not_reached();
      break;
    }
}

static SourcesWizard* sources_wizard = 0;

SourcesWizard*
gnome_apt_sources_wizard()
{
  if (sources_wizard == 0)
    sources_wizard = new SourcesWizard;

  return sources_wizard;
}

void
gnome_apt_sources_wizard_shutdown()
{
  if (sources_wizard != 0)
    delete sources_wizard;

  sources_wizard = 0;
}
