/* This is -*- C -*- */
/* $Id: guppi-data-importer.c,v 1.18 2001/10/10 06:48:08 trow Exp $ */

/*
 * guppi-data-importer.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 *
 * Developed by Jon Trowbridge <trow@gnu.org> and
 * Havoc Pennington <hp@pobox.com>.
 *
 * 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
 */

#include <config.h>
#include "guppi-data-importer.h"

#include <gtk/gtkbox.h>
#include <gtk/gtksignal.h>

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-stock.h>

#include <guppi-convenient.h>
#include "guppi-data-importer-plug-in.h"

#include <guppi-plug-in-spec.h>
/* #include <gnome.h> */

static GtkObjectClass *parent_class = NULL;

static void
guppi_data_importer_finalize (GtkObject * obj)
{
  GuppiDataImporter *imp = GUPPI_DATA_IMPORTER (obj);

  guppi_finalized (obj);

  if (imp->file) {
    guppi_file_close (imp->file);
    guppi_unref0 (imp->file);
  }

  guppi_unref0 (imp->str);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

static void
guppi_data_importer_class_init (GuppiDataImporterClass * klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;

  parent_class = gtk_type_class (GTK_TYPE_OBJECT);

  object_class->finalize = guppi_data_importer_finalize;
}

static void
guppi_data_importer_init (GuppiDataImporter * obj)
{

}

GtkType guppi_data_importer_get_type (void)
{
  static GtkType guppi_data_importer_type = 0;
  if (!guppi_data_importer_type) {
    static const GtkTypeInfo guppi_data_importer_info = {
      "GuppiDataImporter",
      sizeof (GuppiDataImporter),
      sizeof (GuppiDataImporterClass),
      (GtkClassInitFunc) guppi_data_importer_class_init,
      (GtkObjectInitFunc) guppi_data_importer_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_data_importer_type =
      gtk_type_unique (GTK_TYPE_OBJECT, &guppi_data_importer_info);
  }
  return guppi_data_importer_type;
}

GuppiDataImporter *
guppi_data_importer_new (const gchar * name, const gchar *first_arg_name, ...)
{
  GuppiPlugIn *plug_in;
  GuppiDataImporterPlugIn *dipi;
  GuppiDataImporter *gdi;
  va_list var_args;
  GSList *arg_list;
  GSList *info_list;
  gchar *error;
  
  g_return_val_if_fail (name, NULL);

  plug_in = guppi_plug_in_lookup ("data_import", name);
  if (plug_in == NULL) {
    g_warning ("Unknown data-import plug-in: \"%s\"", name);
    return NULL;
  }

  g_return_val_if_fail (GUPPI_IS_DATA_IMPORTER_PLUG_IN (plug_in), NULL);
  dipi = GUPPI_DATA_IMPORTER_PLUG_IN (plug_in);

  g_return_val_if_fail (dipi->construct != NULL, NULL);
  gdi = (dipi->construct) ();

  va_start (var_args, first_arg_name);
  error = gtk_object_args_collect (GTK_OBJECT_TYPE (gdi),
				   &arg_list,
				   &info_list,
				   first_arg_name,
				   var_args);
  va_end (var_args);
  
  if (error) {
    g_warning ("Error processing GuppiDataImporter args: \"%s\"", error);
    return gdi;
  } else {
    GSList *slist_arg = arg_list;
    GSList *slist_info = info_list;
    
    while (slist_arg) {
      gtk_object_arg_set (GTK_OBJECT (gdi), slist_arg->data, slist_info->data);
      slist_arg = g_slist_next (slist_arg);
      slist_info = g_slist_next (slist_info);
    }
    gtk_args_collect_cleanup (arg_list, info_list);
  }

  return gdi;
}

GuppiDataImporter *
guppi_data_importer_newv (const gchar *name, guint nargs, GtkArg* args)
{
  GuppiDataImporter *gdi;

  g_return_val_if_fail (name, NULL);

  gdi = guppi_data_importer_new (name, NULL);
  g_return_val_if_fail (gdi, NULL);

  gtk_object_setv (GTK_OBJECT (gdi), nargs, args);

  return gdi;
}

const gchar *
guppi_data_importer_get_name (GuppiDataImporter * imp)
{
  GuppiDataImporterClass *klass;
  g_return_val_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp), NULL);
  klass = GUPPI_DATA_IMPORTER_CLASS (GTK_OBJECT (imp)->klass);
  return klass->name ? klass->name : _("unnamed");
}

void
guppi_data_importer_set_source (GuppiDataImporter * imp, GuppiFile * f)
{
  GuppiDataImporterClass *klass;

  g_return_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp));
  g_return_if_fail (f && GUPPI_IS_FILE (f));
  g_return_if_fail (imp->file == NULL && imp->str == NULL);

  imp->file = f;
  guppi_ref (imp->file);

  klass = GUPPI_DATA_IMPORTER_CLASS (GTK_OBJECT (imp)->klass);
  if (klass->set_source_hook)
    (klass->set_source_hook) (imp);
}

GuppiFile *
guppi_data_importer_file (GuppiDataImporter * imp)
{
  g_return_val_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp), NULL);

  return imp->file;
}

GuppiStream *
guppi_data_importer_stream (GuppiDataImporter * imp)
{
  g_return_val_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp), NULL);

  if (imp->str == NULL) {
    g_return_val_if_fail (imp->file != NULL, NULL);
    imp->str = guppi_stream_new (imp->file);
    guppi_unref (imp->file);
  }
  return imp->str;
}

const gchar *
guppi_data_importer_filename (GuppiDataImporter * imp)
{
  GuppiFile *file;
  GuppiStream *str;

  g_return_val_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp), NULL);

  file = guppi_data_importer_file (imp);
  if (file)
    return guppi_file_filename (file);

  str = guppi_data_importer_stream (imp);
  if (str)
    return guppi_stream_source (str);

  return NULL;
}

typedef struct _ImpInfo ImpInfo;
struct _ImpInfo {
  import_iter_fn imp_fn;
  gpointer user_data;
  gint count;
};

static void
imp_hook (GuppiData *d, gpointer ud)
{
  ImpInfo *ii = (ImpInfo *)ud;

  if (d) {
    ii->imp_fn (d, ii->user_data);
    ++ii->count;
  }
}

gint
guppi_data_importer_import (GuppiDataImporter * imp,
			    import_iter_fn fn,
			    gpointer user_data)
{
  GuppiDataImporterClass *klass;
  ImpInfo ii;

  g_return_val_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp), 0);
  g_return_val_if_fail (fn, 0);

  klass = GUPPI_DATA_IMPORTER_CLASS (GTK_OBJECT (imp)->klass);
  g_return_val_if_fail (klass->import != NULL, 0);

  ii.imp_fn = fn;
  ii.user_data = user_data;
  ii.count = 0;

  klass->import (imp, imp_hook, &ii);

  return ii.count;
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

typedef struct _InteractiveImport InteractiveImport;
struct _InteractiveImport {
  GuppiDataImporter *imp;

  import_iter_fn fn;
  gpointer fn_user_data;

  void (*post_hook) (gint, gpointer);
  gpointer post_user_data;
};

static void
inter_free (InteractiveImport *ii)
{
  guppi_unref (ii->imp);
  guppi_free (ii);
}

static void
interaction_complete (InteractiveImport *ii)
{
  gint N;

  N = guppi_data_importer_import (ii->imp, ii->fn, ii->fn_user_data);
  if (ii->post_hook)
    ii->post_hook (N, ii->post_user_data);
}

static void
dialog_clicked_cb (GtkWidget *w, gint button, gpointer ud)
{
  InteractiveImport *ii = (InteractiveImport *)ud;

  g_return_if_fail (ud);
  g_return_if_fail (GNOME_IS_DIALOG (w));

  gnome_dialog_close (GNOME_DIALOG (w));
  if (button == 0)
    interaction_complete (ii);

  inter_free (ii);
}

void
guppi_data_importer_import_interactive (GuppiDataImporter *imp,
					import_iter_fn fn,
					gpointer fn_user_data,
					void (*post_hook) (gint, gpointer),
					gpointer post_user_data)
{
  GuppiDataImporterClass *klass;
  InteractiveImport *ii;
  GtkWidget *dialog;
  GtkWidget *edit_widget;

  g_return_if_fail (imp && GUPPI_IS_DATA_IMPORTER (imp));

  /* If no iter fn is defined, immediately call the post hook reporting
     zero items have been loaded and return. */
  if (fn == NULL) {
    if (post_hook)
      post_hook (0, post_user_data);
    return;
  }

  klass = GUPPI_DATA_IMPORTER_CLASS (GTK_OBJECT (imp)->klass);

  /* If we don't define a state editor widget, just do a standard import
     right now, calling our appropriate callbacks. */
  if (klass->state_edit_widget == NULL) {
    gint N = guppi_data_importer_import (imp, fn, fn_user_data);
    if (post_hook)
      post_hook (N, post_user_data);
    return;
  }

  ii = guppi_new0 (InteractiveImport, 1);
  ii->imp = imp;
  guppi_ref (imp);
  ii->fn = fn;
  ii->fn_user_data = fn_user_data;
  ii->post_hook = post_hook;
  ii->post_user_data = post_user_data;

  /* Create our editor widget, put it in a dialog. */

  edit_widget = klass->state_edit_widget (imp);
  g_assert (edit_widget);
  dialog = gnome_dialog_new (_("Configure Import"),
			     GNOME_STOCK_BUTTON_OK,
			     GNOME_STOCK_BUTTON_CANCEL,
			     NULL);
  gtk_window_set_policy (GTK_WINDOW (dialog), FALSE, TRUE, FALSE);
  gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
		      edit_widget, TRUE, TRUE, 2);
  gtk_signal_connect (GTK_OBJECT (dialog),
		      "clicked",
		      GTK_SIGNAL_FUNC (dialog_clicked_cb),
		      ii);
  gtk_widget_show_all (dialog);
}

/* $Id: guppi-data-importer.c,v 1.18 2001/10/10 06:48:08 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1