/* formulas.c
 * geg, a GTK+ Equation Grapher
 * David Bryant 1998
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include "formulas.h"
#include "log.h"
#include "prefs.h"
#include "colors.h"

/* global data */
extern struct_prefs prefs;
extern misc_colors m_colors;

/* locally global data */
static gchar **formulas = NULL;
static int nformulas = 0;
static GtkWidget *wi = NULL;
static GtkStyle *style;

static void close_event(GtkWidget *widget, gpointer data);
static void remove_event(GtkWidget *widget, gpointer data);
static void really_remove_event(gpointer data, gpointer user_data);

void
remove_all_event(GtkWidget *widget, gpointer data)
{
  int i;

  for(i = 0; i < nformulas; i++)
    g_free(formulas[i]);

  if(formulas)
    g_free(formulas);
  formulas = NULL;

  nformulas = 0;
}

/* formula_foreach, calls the supplied function for each formula in the
 * array of formulas, called by go_event in app.c
 */
void
formula_foreach(FormulaFunc func)
{
  int i;

  for(i = 0; i < nformulas; i++)
    func(formulas[i], i);
}

/* formula_forall,
 */
void formula_forall(FormulaAllFunc func,
		    gdouble x1, gdouble x2,
		    gdouble y1, gdouble y2)
{
  func(formulas, nformulas, x1, x2, y1, y2);
}

/* formula_add,
 */
gint
formula_add(FormulaFunc func, gchar *formula)
{
  if(*formula == '\0')	/* check for a real formula */
    return(FALSE);

  if(nformulas >= prefs.maxform) {
    write_log(NULL, "Maximum Formulas");
    return(FALSE);
  }

  write_log(NULL, formula);

  if(!func(formula, nformulas)) {
    write_log(NULL, "Parse Error!");
    return(FALSE);
  }

  /* add the formula to the list */
  formulas = (gchar **)g_realloc(formulas, ++nformulas * sizeof(gchar **));
  formulas[nformulas - 1] = g_strdup(formula);

  return(TRUE);
}

/* delete_event, deletes the window, not sure if it would be GTK+ approved 
 */
static gint
delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  gtk_widget_destroy(wi);
  wi = NULL;
  gtk_style_unref(style);
  return(TRUE);
}

/* close_event, closes the 'erase' dialog, it is called by the 'Cancel'
 * and the 'Ok' button
 */
static void
close_event(GtkWidget *widget, gpointer data)
{
  gtk_widget_destroy(wi);
  wi = NULL;
  gtk_style_unref(style);
}

/* erase_event, brings up the 'erase' dialog, it is called by the 'erase'
 * toolbar button in the main dialog
 */
void
erase_event(GtkWidget *widget, gpointer data)
{
  int i;
  GtkWidget *temp_bu, *fr, *li;
  GtkSignalFunc refresh_graph;

  if(wi && wi->window) {
    gtk_widget_map(wi);
    gdk_window_raise(wi->window);
    return;
  }

  refresh_graph = (GtkSignalFunc)data;

  wi = gtk_dialog_new();

  gtk_signal_connect(GTK_OBJECT(wi), "delete_event",
                     GTK_SIGNAL_FUNC(delete_event), NULL);

  gtk_window_set_wmclass(GTK_WINDOW(wi), "erase", "geg");
  gtk_window_set_title(GTK_WINDOW(wi), "Erase");
  gtk_window_set_policy(GTK_WINDOW(wi), FALSE, TRUE, FALSE);
  gtk_window_position(GTK_WINDOW(wi), GTK_WIN_POS_MOUSE);

  gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(wi)->vbox), 5);

  /* the list to delete functions from */
  fr = gtk_frame_new("Select functions to erase:");
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->vbox), fr, TRUE, TRUE, 0);
  li = gtk_clist_new(1);	/* only want 1 column */

  /* gtk_clist_set_reorderable(GTK_CLIST(li), TRUE); */

  /* style stuff */
  style = gtk_style_copy(gtk_widget_get_style(widget));
  style->bg[GTK_STATE_PRELIGHT] = *m_colors.back;

  gtk_widget_set_style(li, style);
  gtk_clist_set_selection_mode(GTK_CLIST(li), GTK_SELECTION_MULTIPLE);

  /* add the formulas to the list */
  for(i = 0; i < nformulas; i++) {
    gtk_clist_append(GTK_CLIST(li), &formulas[i]);
    gtk_clist_set_foreground(GTK_CLIST(li), i, function_color(i));
    gtk_clist_set_background(GTK_CLIST(li), i, m_colors.back);
  }
  /* make the list a bit bigger than the default size */
  gtk_widget_set_usize(li, 200, 200);
  gtk_container_add(GTK_CONTAINER(fr), li);
  gtk_widget_show(li);
  gtk_widget_show(fr);

  /* Ok button */
  temp_bu = gtk_button_new_with_label("Ok");
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(remove_event), li);
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(refresh_graph), NULL);
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(close_event), NULL);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->action_area), temp_bu,
                     TRUE, TRUE, 0);
  gtk_widget_show(temp_bu);

  /* Cancel button */
  temp_bu = gtk_button_new_with_label("Cancel");
  gtk_signal_connect(GTK_OBJECT(temp_bu), "clicked",
                     GTK_SIGNAL_FUNC(close_event), NULL);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wi)->action_area), temp_bu,
                     TRUE, TRUE, 0);
  gtk_widget_show(temp_bu);

  gtk_grab_add(wi);
  gtk_widget_show(wi);
  /* how do I do this ? */
  /* gdk_window_set_decorations(wi->window, GDK_DECOR_BORDER); */
}

/* really_remove_event, called for each item in the glist in remove_event    */
static void
really_remove_event(gpointer data, gpointer user_data)
{
  gint i = 0;
  gchar *text;

  gtk_clist_get_text((GtkCList *)user_data, (gint)data, 0, &text);
  while(strcmp(text, formulas[i++]));
  g_free(formulas[--i]);
  nformulas--;
  /* the next part shuffles the order if we didn't delete the last one       */
  /* this disturbs the order, ideally this should not happen... maybe later  */
  if(i != nformulas)
    formulas[i] = formulas[nformulas];
  formulas = (gchar **)g_realloc(formulas, nformulas * sizeof(gchar **));
}

/* remove_event, called from the 'ok' button in the 'erase' dialog. it
 * passes a pointer to the CList, which has selected entries which we
 * wish to delete
 */
static void
remove_event(GtkWidget *widget, gpointer data)
{
  GtkCList *clist;
  GList *glist;		/* glib doubly linked list */

  clist = GTK_CLIST((GtkWidget *)data);
  glist = clist->selection;
  if(glist)
    write_log(NULL, "Erase Formulas");
  g_list_foreach(glist, (GFunc)really_remove_event, clist);
}


syntax highlighted by Code2HTML, v. 0.9.1