/* Bluefish HTML Editor

 * Copyright (C) 1998-1999 Olivier Sessink
 *
 * 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 "default_include.h"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "bluefish.h"
#include "bf_lib.h"
#include "ref_dialog.h"
#include "document.h"
#include "gtk_easy.h"

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

typedef struct {
	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 {
	GtkWidget *dialog;
	GtkWidget *groupcombo;
	GtkWidget *functioncombo;
	RefClass *which_class;
} RefDialog;

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

/********************************************************************/
void php3_dialog(GtkWidget * widget, gpointer * data);
void ssi_dialog(GtkWidget * widget, gpointer * data);
void rxml_dialog(GtkWidget * widget, gpointer * data);
static RefClass *ref_init(gchar * filename);
static void new_ref_dialog(RefClass * the_class, gchar * title);
static void group_changed(GtkWidget * widget, RefDialog * data);
static void close_refdialog(GtkWidget * widget, RefDialog * data);
static void insert_n_exit(GtkWidget * widget, RefDialog * data);
static void insert(GtkWidget * widget, 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, _("PHP 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"));
}

void php4_dialog(GtkWidget * widget, gpointer * data)
{
	/* make sure it is properly initialised */
	if (php4_ref == NULL) {
		php4_ref = ref_init("/.bluefish/php4_functions");
	}
	/* start the actual dialog */
	new_ref_dialog(php4_ref, _("PHP4 Reference"));
}


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

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

	DEBUG_MSG("ref_init, started\n");
	/* first test if the file for init exists, return NULL if not */
	filename2 = g_strconcat((char *) getenv("HOME"), filename, NULL);
	g_assert(filename2);
	if (file_exists_and_readable(filename2)) {
		fd = fopen(filename2, "r");
		if (fd == NULL) {
			/* if we can't read from the fd then return NULL */
			returnval = NULL;
			goto out_free;
		}

		/* calloc the memory for the RefClass */
		returnval = g_malloc0(sizeof(RefClass));
		g_assert(returnval);
		DEBUG_MSG("ref_init, returnval=%p\n", returnval);
		/* make the buffers ready for reading the file */
		tmpbuf = g_malloc(500);
		g_assert(tmpbuf);
		last_group = g_malloc0(500);
		g_assert(last_group);
		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 : */
			DEBUG_MSG("ref_init, function=%s\n", function);
			tmpstr = g_strdup(function);
			g_assert(tmpstr);

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

			if (strcmp(tmpbuf, last_group) != 0) {
				tmp = g_malloc0(sizeof(RefGroup));
				g_assert(tmp);
				tmp->name = g_strdup(tmpbuf);
				g_assert(tmp->name);
				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);
				DEBUG_MSG("ref_init, added group %s (=%s or =%s)\n", tmpbuf, tmp->name, last_group);
			}
			tmp->functions = g_list_append(tmp->functions, tmpstr);
			DEBUG_MSG("ref_init, added tmpstr=%s to last_group=%s\n", tmpstr, last_group);
		}
		g_free(last_group);
		g_free(tmpbuf);
		DEBUG_MSG("ref_init, groupnameslist=%p, groupstructlist=%p\n", returnval->groupnameslist, returnval->groupstructlist);
		DEBUG_MSG("ref_init, returnval=%p, lenght(groupstructlist)=%d\n", returnval, g_list_length(returnval->groupstructlist));
	} else {
		returnval = NULL;
	}
  out_free:
	g_free(filename2);
	return returnval;
}


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

	DEBUG_MSG("new_ref_dialog, started, class=%p\n", the_class);
	if (the_class == NULL) {
		return;
	}
	refdialog = g_malloc(sizeof(RefDialog));
	DEBUG_MSG("new_ref_dialog, allocated this refdialog at %p\n", refdialog);
	refdialog->which_class = (RefClass *) 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);
	DEBUG_MSG("new_ref_dialog, euhhhh\n");
	refdialog->groupcombo = gtk_combo_new();
	refdialog->functioncombo = gtk_combo_new();
	DEBUG_MSG("new_ref_dialog, refdialog->groupcombo=%p, -functioncombo=%p\n", refdialog->groupcombo, refdialog->functioncombo);
	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);
	DEBUG_MSG
		("new_ref_dialog, the_class->groupnameslist=%p, the_class->groupstructlist=%p\n",
		 the_class->groupnameslist, the_class->groupstructlist);
	gtk_combo_set_popdown_strings(GTK_COMBO(refdialog->groupcombo), the_class->groupnameslist);
	DEBUG_MSG("new_ref_dialog, lenght(the_class->groupstructlist)=%d\n", g_list_length(the_class->groupstructlist));
	tmp = g_list_nth_data(the_class->groupstructlist, 0);
	DEBUG_MSG("new_ref_dialog, tmp=%p, tmp->functions=%p, tmp->name=%s\n", tmp, tmp->functions, tmp->name);
	gtk_combo_set_popdown_strings(GTK_COMBO(refdialog->functioncombo), tmp->functions);
	DEBUG_MSG("new_ref_dialog, length(tmp->functions)=%d\n", g_list_length(tmp->functions));
	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 = bf_stock_cancel_button(GTK_SIGNAL_FUNC(close_refdialog), refdialog);
	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_widget_show(insertb);
	gtk_widget_show(closeb);
	gtk_widget_show(cancelb);

	gtk_widget_show(refdialog->dialog);
}

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

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

/* find in which pointer of groupstructlist the selected string is found */
	DEBUG_MSG("group_changed, length groupnameslist=%d, groupstructlist=%d\n",
			  g_list_length(data->which_class->groupnameslist), g_list_length(data->which_class->groupstructlist));
	for (count = g_list_length((GList *) 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((GList *) data->which_class->groupnameslist, count);
		DEBUG_MSG("group_changed, count=%d, tmp1=%s, tmp2=%s\n", count, tmp1, tmp2);
		if (strcmp(tmp1, tmp2) == 0) {
			count1 = count;
			count = 0;
			DEBUG_MSG("group_changed, it is=%s (=%s) !! count1=%d\n", tmp1, tmp2, count1);
		}
	}
	/* set the GList of the functioncombo to that of the pointer where the string of the groupstructlist was found */
	tmplist = (RefGroup *) g_list_nth_data((GList *) data->which_class->groupstructlist, count1);
	gtk_combo_set_popdown_strings(GTK_COMBO(data->functioncombo), tmplist->functions);
}

static void close_refdialog(GtkWidget * widget, RefDialog * data)
{
	DEBUG_MSG("close_refdialog, data=%p\n", data);
	gtk_signal_handlers_destroy(GTK_OBJECT(data->dialog));
	gtk_widget_destroy(data->dialog);
	g_free(data);
}

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

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

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


/* 
 * get the php3 class
 */
static RefClass *php3_get_class()
{
	/* make sure it is properly initialised */
	if (php3_ref == NULL) {
		php3_ref = ref_init("/.bluefish/php3_functions");
	}
	return php3_ref;
}

/* 
 * get the php4 class
 */
static RefClass *php4_get_class()
{
	/* make sure it is properly initialised */
	if (php4_ref == NULL) {
		php4_ref = ref_init("/.bluefish/php4_functions");
	}
	return php4_ref;
}

/*
  Look for the description of a php(3|4) function
*/
static gchar *php_get_function_desc(RefClass *rfclass, gchar *function_name)
{
  GList *grplist, *funlist;
  gchar fname[200];
 
  fname[0] = ' ';
  strcpy(fname + 1, function_name);
  strcat(fname, "(");
  if( rfclass ) {
    for(grplist = rfclass->groupstructlist;
	grplist;
	grplist = g_list_next(grplist) ) {
      for(funlist = ((RefGroup *)grplist->data)->functions;
	  funlist;
	  funlist = g_list_next(funlist) ) {
	if( strstr(funlist->data, fname) != NULL )
	  return funlist->data;
      }
    }
  }
  return NULL;
}

/*
  Look for the description of a php3 function
*/
gchar *php3_get_function_desc(gchar *function_name)
{
  return php_get_function_desc(php3_get_class(), function_name);
}

/*
  Look for the description of a php4 function
*/
gchar *php4_get_function_desc(gchar *function_name)
{
  return php_get_function_desc(php4_get_class(), function_name);
}






