/* Bluefish HTML Editor
 *
 * Copyright (C) 1998-1999 Olivier Sessink and Chris Mazuc
 *
 * 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 <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "bluefish.h"
#include "ref_dialog.h"
#include "html.h"

/* This is the struct that holds the info for every group of functions  */
typedef struct RefGroup
  {
    gchar *name;
    GList *functions;
  }
RefGroup;

typedef struct RefClass
  {
    gchar *name;
    GList *groupnameslist;	/* this list holds strings with the names of all the groups */
    GList *groupstructlist;	/* this list holds the structs with the GLists of all the groups */
  }
RefClass;

/* These are the widgets we need to access out of the callback functions  */
typedef struct RefDialog
  {
    GtkWidget *dialog;
    GtkWidget *groupcombo;
    GtkWidget *functioncombo;
    struct RefClass *which_class;
  }
RefDialog;

/* for this module'global' variables */
struct RefClass *php3_ref = NULL;
struct RefClass *ssi_ref = NULL;
struct RefClass *rxml_ref = NULL;

/* only local used functions */
struct RefClass *ref_init (gchar * filename);
void new_ref_dialog (struct RefClass *the_class, gchar *);
void group_changed (GtkWidget * widget, struct RefDialog *data);
void close_refdialog (GtkWidget * widget, struct RefDialog *data);
void insert_n_exit (GtkWidget * widget, struct RefDialog *data);
void insert (GtkWidget * widget, struct RefDialog *data);


/* 
 * the start of the functions --> global functions
 */
void
php3_dialog (GtkWidget * widget, gpointer * data)
{

  /* make sure it is properly initialised */
  if (php3_ref == NULL)
    {
      php3_ref = ref_init ("/.bluefish/php3_functions");
    }
  /* start the actual dialog */
  new_ref_dialog (php3_ref, "PHP3 Reference");
}

void
ssi_dialog (GtkWidget * widget, gpointer * data)
{

  /* make sure it is properly initialised */
  if (ssi_ref == NULL)
    {
      ssi_ref = ref_init ("/.bluefish/ssi_functions");
    }
  /* start the actual dialog */
  new_ref_dialog (ssi_ref, "SSI Reference");
}

void
rxml_dialog (GtkWidget * widget, gpointer * data)
{


  /* make sure it is properly initialised */
  if (rxml_ref == NULL)
    {
      rxml_ref = ref_init ("/.bluefish/rxml_functions");
    }
  /* start the actual dialog */
  new_ref_dialog (rxml_ref, "RXML Reference");
}

/* 
 * the start of the functions --> local functions
 */
struct RefClass *
ref_init (gchar * filename)
{

  struct RefGroup *tmp = NULL;
  struct RefClass *returnval = NULL;
  gchar *last_group, *tmpstr, *function;
  char *tmpbuf;
  FILE *fd;
  gint count;
  gchar *filename2;

#ifdef DEBUG
  g_print ("ref_init, started\n");
#endif
  /* first test if the file for init exists, return NULL if not */
  filename2 = g_malloc (500);
  strncat (strcpy (filename2, (char *) getenv ("HOME")), filename, 499);
  if (file_exists_and_readable (filename2))
    {

      /* alloc the memory for the RefClass */
      returnval = g_malloc (sizeof (RefClass));
      returnval->groupstructlist = NULL;
      returnval->groupnameslist = NULL;
#ifdef DEBUG
      g_print ("ref_init, returnval=%p\n", returnval);
#endif
      /* make the buffers ready for reading the file */
      tmpbuf = g_malloc (500);
      last_group = g_malloc0 (500);
      fd = fopen (filename2, "r");
      if (fd == NULL)
	{
	  /* if we can't read from the fd then return NULL */
	  return NULL;
	}
      while (fgets (tmpbuf, 499, fd) != NULL)
	{
	  for (count = 0; count <= strlen (tmpbuf); count++)
	    {
	      /* replace the \n with a string end */
	      if (tmpbuf[count] == '\n')
		tmpbuf[count] = '\0';
	    }
	  function = strchr (tmpbuf, ':');
	  function++;
	  /* if you don't do the function++ it will start every function
	     with a : */
#ifdef DEBUG1
	  g_print ("ref_init, function=%s\n", function);
#endif
	  tmpstr = g_malloc (strlen (function) + 1);
	  strcpy (tmpstr, function);

	  /* add an end of string at the place where funbction started */
	  function--;
	  strcpy (function, "");

	  if (strcmp (tmpbuf, last_group) != 0)
	    {
	      tmp = g_malloc (sizeof (RefGroup));
	      tmp->functions = NULL;
	      tmp->name = g_malloc (strlen (tmpbuf) + 1);
	      strcpy (tmp->name, tmpbuf);
	      returnval->groupstructlist = g_list_append
							  (returnval->groupstructlist, tmp);
	      /* we can refer to the same pointer for this one */
	      returnval->groupnameslist = g_list_append
							 (returnval->groupnameslist, tmp->name);
	      strncpy (last_group, tmpbuf, 499);
#ifdef DEBUG1
	      g_print ("ref_init, added group %s (=%s or =%s)\n", tmpbuf,
		       tmp->name, last_group);
#endif
	    }
	  tmp->functions = g_list_append (tmp->functions, tmpstr);
#ifdef DEBUG1
	  g_print ("ref_init, added tmpstr=%s to last_group=%s\n", tmpstr, last_group);
#endif
	}
      g_free (last_group);
      g_free (tmpbuf);
      g_free (filename2);
#ifdef DEBUG
      g_print ("ref_init, groupnameslist=%p, groupstructlist=%p\n",
	       returnval->groupnameslist, returnval->groupstructlist);
      g_print ("ref_init, returnval=%p, lenght(groupstructlist)=%d\n",
	       returnval, g_list_length (returnval->groupstructlist));
#endif
      return returnval;
    }
  else
    {
      g_free (filename2);
      return NULL;
    }
}


void
new_ref_dialog (struct RefClass *the_class, gchar *title)
{
  GtkWidget *table, *insertb, *closeb, *cancelb, *label;
  struct RefDialog *refdialog;
  RefGroup *tmp;

#ifdef DEBUG
  g_print ("new_ref_dialog, started, class=%p\n", the_class);
#endif
  if (the_class == NULL)
    {
      return;
    }
  refdialog = g_malloc (sizeof (RefDialog));
#ifdef DEBUG
  g_print ("new_ref_dialog, allocated this refdialog at %p\n", refdialog);
#endif
  refdialog->which_class = the_class;
  refdialog->dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_signal_connect (GTK_OBJECT (refdialog->dialog), "destroy",
		      GTK_SIGNAL_FUNC (close_refdialog), refdialog);
  gtk_container_border_width (GTK_CONTAINER (refdialog->dialog), 5);
  gtk_window_set_title (GTK_WINDOW (refdialog->dialog), title);

  table = gtk_table_new (3, 3, TRUE);
  gtk_table_set_row_spacing( GTK_TABLE(table), 1, 2);
  gtk_table_set_col_spacing(GTK_TABLE(table), 0, 5);
  gtk_table_set_col_spacing( GTK_TABLE(table), 1, 5);
  gtk_widget_show (table);
  gtk_container_add (GTK_CONTAINER (refdialog->dialog), table);
  label = gtk_label_new ("Group");
  gtk_widget_show (label);
  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
  label = gtk_label_new ("Function");
  gtk_widget_show (label);
  gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 0, 1);
#ifdef DEBUG
  g_print ("new_ref_dialog, euhhhh\n");
#endif
  refdialog->groupcombo = gtk_combo_new ();
  refdialog->functioncombo = gtk_combo_new ();
#ifdef DEBUG
  g_print ("new_ref_dialog, refdialog->groupcombo=%p, -functioncombo=%p\n",
	   refdialog->groupcombo, refdialog->functioncombo);
#endif
  gtk_table_attach_defaults (GTK_TABLE (table), refdialog->groupcombo, 0, 1,
			     1, 2);
  gtk_table_attach_defaults (GTK_TABLE (table), refdialog->functioncombo, 1,
			     3, 1, 2);
#ifdef DEBUG
  g_print
	   ("new_ref_dialog, the_class->groupnameslist=%p, the_class->groupstructlist=%p\n",
	   the_class->groupnameslist, the_class->groupstructlist);
#endif
  gtk_combo_set_popdown_strings (GTK_COMBO (refdialog->groupcombo), the_class->groupnameslist);
#ifdef DEBUG
  g_print ("new_ref_dialog, lenght(the_class->groupstructlist)=%d\n",
	   g_list_length (the_class->groupstructlist));
#endif
  tmp = g_list_nth_data (the_class->groupstructlist, 0);
#ifdef DEBUG
  g_print ("new_ref_dialog, tmp=%p, tmp->functions=%p, tmp->name=%s\n", tmp,
	   tmp->functions, tmp->name);
#endif
  gtk_combo_set_popdown_strings (GTK_COMBO (refdialog->functioncombo), tmp->functions);
#ifdef DEBUG
  g_print ("new_ref_dialog, length(tmp->functions)=%d\n", g_list_length (tmp->functions));
#endif
  gtk_signal_connect (GTK_OBJECT (GTK_COMBO (refdialog->groupcombo)->entry),
		      "changed",
		      GTK_SIGNAL_FUNC (group_changed), refdialog);
  gtk_widget_show (refdialog->groupcombo);
  gtk_widget_show (refdialog->functioncombo);

  insertb = gtk_button_new_with_label ("Insert");
  closeb = gtk_button_new_with_label ("Insert & close");
  cancelb = gtk_button_new_with_label ("Cancel");
  GTK_WIDGET_SET_FLAGS (closeb, GTK_CAN_DEFAULT);
  GTK_WIDGET_SET_FLAGS (cancelb, GTK_CAN_DEFAULT);
  GTK_WIDGET_SET_FLAGS (insertb, GTK_CAN_DEFAULT);
  gtk_window_set_default(GTK_WINDOW(refdialog->dialog), closeb);
  gtk_table_attach_defaults (GTK_TABLE (table), closeb, 0, 1, 2, 3);
  gtk_table_attach_defaults (GTK_TABLE (table), insertb, 1, 2, 2, 3);
  gtk_table_attach_defaults (GTK_TABLE (table), cancelb, 2, 3, 2, 3);
  gtk_signal_connect (GTK_OBJECT (insertb), "clicked",
		      GTK_SIGNAL_FUNC (insert), refdialog);
  gtk_signal_connect (GTK_OBJECT (closeb), "clicked",
		      GTK_SIGNAL_FUNC (insert_n_exit), refdialog);
  gtk_signal_connect (GTK_OBJECT (cancelb), "clicked",
		      GTK_SIGNAL_FUNC (close_refdialog), refdialog);
  gtk_widget_show (insertb);
  gtk_widget_show (closeb);
  gtk_widget_show (cancelb);

  gtk_widget_show (refdialog->dialog);
}

void
group_changed (GtkWidget * widget, struct RefDialog *data)
{

  gint count, count1 = 0;
  gchar *tmp1, *tmp2;
  struct RefGroup *tmplist;

/* find in which pointer of groupstructlist the selected string is found */
#ifdef DEBUG
  g_print ("group_changed, length groupnameslist=%d, groupstructlist=%d\n",
	   g_list_length (data->which_class->groupnameslist), g_list_length (data->which_class->groupstructlist));
#endif
  for (count = g_list_length (data->which_class->groupstructlist) - 1; count
       > 0; count--)
    {
      tmp1 = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (data->groupcombo)->entry));
      tmp2 = (gchar *) g_list_nth_data (data->which_class->groupnameslist, count);
#ifdef DEBUG
      g_print ("group_changed, count=%d, tmp1=%s, tmp2=%s\n", count, tmp1, tmp2);
#endif
      if (strcmp (tmp1, tmp2) == 0)
	{
	  count1 = count;
	  count = 0;
#ifdef DEBUG
	  g_print ("group_changed, it is=%s (=%s) !! count1=%d\n", tmp1,
		   tmp2, count1);
#endif
	}
    }
  /* set the GList of the functioncombo to that of the pointer where the string of the groupstructlist was found */
  tmplist = (struct RefGroup *) g_list_nth_data
						 (data->which_class->groupstructlist, count1);
  gtk_combo_set_popdown_strings (
				  GTK_COMBO (data->functioncombo),
				  tmplist->functions);
}

void
close_refdialog (GtkWidget * widget, struct RefDialog *data)
{
#ifdef DEBUG
  g_print ("close_refdialog, data=%p\n", data);
#endif
  gtk_signal_handlers_destroy (GTK_OBJECT (data->dialog));
  gtk_widget_destroy (data->dialog);
  g_free (data);
}

void
insert_n_exit (GtkWidget * widget, struct RefDialog *data)
{
  insert (widget, data);
  close_refdialog (widget, data);
}

void
insert (GtkWidget * widget, struct RefDialog *data)
{
  gchar *tmp;

  tmp = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (data->functioncombo)->entry));
  insert_text (tmp, "");
}
