/** File ge_project.c
 *
 *   Copyright (c) 2010 P. Vincent.    See GNU GPL ../LICENCE
 */


#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>

#include "globals.h"

#include "globals.h"
#include "device.h"
#include "utils.h"
#include "plotone.h"
#include "graphutils.h"

#include "gw_list.h"

#include "gg_gutil.h"
#include "gg_gtkinc.h"
#include "gg_protos.h"
#include "gg_events.h"

#include "ge_tree.h"
#include "ge_protos.h"
#include "gg_page_dimensions.h" 

extern GdkColor  bleuciel ,wheat;

static GtkWidget *w_titre = NULL;
static GtkWidget *project_notb = NULL;
static GtkWidget *w_graphs_list ,*w_graphs_box;

static PageDimensions pdim;

static GtkWidget *w_bg_color   	,*w_bg_fill;
static GtkWidget *w_add     	,*w_kill;
static GtkWidget *w_ncols   	,*w_nrows;
static GtkWidget *w_order   	,*w_snake;
static GtkWidget *w_toff    	,*w_loff;
static GtkWidget *w_roff    	,*w_boff;
static GtkWidget *w_hgap    	,*w_hpack;
static GtkWidget *w_vgap    	,*w_vpack;
static GtkWidget *add_fun_bt;

#define NB_COLS 8
static GtkWidget *gcol[NB_COLS] ,**gbut;
static int cur_col = 0;
static int cur_ngraphs = 0;

static gulong handler_id;

static void ge_project_graph_list    (void);

void ge_hpack_CB (GtkToggleButton *tbut ,gpointer p);
void ge_vpack_CB (GtkToggleButton *tbut ,gpointer p);

static void ge_project_hide_CB       (GtkWidget *w ,gpointer p);
static void ge_project_select_CB     (GtkWidget *w ,gpointer p);
static void ge_project_toggle_sel_CB (GtkWidget *w ,gpointer p);
static void ge_project_duplicate_CB  (GtkWidget *w ,gpointer p);
static void ge_project_kill_CB       (GtkWidget *w ,gpointer p);
static void ge_project_attach_fun_CB (GtkWidget *w ,gpointer p);


/**
 *  gtk_widget_hide_all in ge_tree_CB emits the "switch-page" signal
 *  successively for each page => need block/unblock
 *  Idem when the notebook is created => current_page is initialized at -1
 *  while the notebook is not created.
 */
static gint current_page = -1;
static gulong handler_id;

void ge_project_page_block (void)
{
  g_signal_handler_block (project_notb ,handler_id);
}
void ge_project_page_unblock (void)
{
  g_signal_handler_unblock (project_notb ,handler_id);
}
static void ge_project_switch_page_CB (GtkNotebook     *notebook,
					    GtkNotebookPage *page,
					    guint            page_num,
					    gpointer         user_data)
{
  if (current_page >= 0) current_page = page_num;
  gtk_widget_set_sensitive (w_graphs_list ,current_page > 0);
  ge_function_type_update ();
}

void ge_project_set_page (void)
{
  gtk_notebook_set_current_page (GTK_NOTEBOOK (project_notb) ,current_page);
  gtk_widget_set_sensitive (w_graphs_list ,current_page > 0);
  ge_function_type_update ();
}


/**
**************** Menu creation *******************
*/
GtkWidget *ge_project_create_menu (GtkWidget *parent)
{
  GtkWidget *rc ,*fr ,*ta;
  int i;

  gg_set_wait_cursor();
  if (w_titre == NULL) {
    w_titre = gg_CreateVContainer (parent);

    gg_frame_connect (NULL);

    /* Notebook */
    project_notb = gtk_notebook_new ();

    /* ------------ Page tab create -------------- */
    rc = gg_CreateTabPage (project_notb ,"Page");

    /* Page dimensions */
    gg_page_dimensions_new (rc ,&pdim);

    /* Page background */
    fr = gg_frame (rc ,"Page background" ,&wheat ,1 ,0);
    w_bg_color = gg_color_new (fr, "Color:");
    w_bg_fill  = gg_check_new (fr ,"Fill");


    /* ------------ Layout of graphs tab create -------------- */
    rc = gg_CreateTabPage (project_notb ,"Layout");
    w_add  = gg_check_new (rc ,"Add graphs as needed to fill the matrix");
    w_kill = gg_check_new (rc ,"Kill extra graphs");

    ta = gg_frame (rc ,"Matrix" ,&wheat ,2 ,2);
    w_ncols = gg_spin_new  (ta ,"Cols:" ,1.0 ,99.0 ,1.0);
    w_order = gg_order_new (ta ,"Order");
    w_nrows = gg_spin_new  (ta ,"Rows:" ,1.0 ,99.0 ,1.0);
    w_snake = gg_check_new (ta , "Snake fill");

    ta = gg_frame (rc ,"Page offsets" ,&bleuciel ,3 ,3);
    gg_void_cell (ta);
    w_toff = gg_spin_new (ta ,"" ,0.0 ,1.0 ,0.05);
    gg_void_cell (ta);
    w_loff = gg_spin_new (ta ,"" ,0.0 ,1.0 ,0.05);
    gg_void_cell (ta);
    w_roff = gg_spin_new (ta ,"" ,0.0 ,1.0 ,0.05);
    gg_void_cell (ta);
    w_boff = gg_spin_new (ta ,"" ,0.0 ,1.0 ,0.05);

    ta = gg_frame (rc ,"Spacing" ,&wheat ,2 ,2);
    w_hgap  = gg_spin_new (ta , "Hgap/width"  ,0.0 ,9.0 ,0.1);
    w_hpack = gg_check_new (ta , "Pack");
    w_vgap  = gg_spin_new (ta , "Vgap/height" ,0.0 ,9.0 ,0.1);
    w_vpack = gg_check_new (ta , "Pack");

    /* ------------ Graphs operations tab create -------------- */
    rc = gg_CreateTabPage (project_notb ,"Graphs");
    ta = gg_frame (rc ,"Actions on selected graphs" ,&bleuciel ,2 ,3);
    gg_buttonA (ta ,"Show"      ,ge_project_hide_CB ,FALSE);
    gg_buttonA (ta ,"Hide"      ,ge_project_hide_CB ,TRUE);
    gg_buttonA (ta ,"Duplicate" ,ge_project_duplicate_CB ,0);
    gg_buttonA (ta ,"Kill"      ,ge_project_kill_CB ,0);

    ta = gg_frame (rc ,"Select graphs" ,&wheat ,3 ,3);
    gg_buttonA (ta ,"Select all"       ,ge_project_select_CB     ,TRUE);
    gg_buttonA (ta ,"Toggle selection" ,ge_project_toggle_sel_CB ,TRUE);
    gg_buttonA (ta ,"Unselect all"     ,ge_project_select_CB     ,FALSE);

    w_graphs_list = gtk_frame_new ("Graphs list");
    w_graphs_box  = gtk_hbox_new (TRUE ,1);
    for (i = 0; i < NB_COLS; i++) gcol[i] = gg_CreateVContainer (w_graphs_box);
    gtk_container_add  (GTK_CONTAINER (w_graphs_list) ,w_graphs_box);
    gtk_box_pack_end   (GTK_BOX (w_titre) ,w_graphs_list  ,TRUE  ,FALSE ,1);

    /* ------------ Functions tab create -------------- */
    rc = gg_CreateTabPage (project_notb ,"Functions");
    ge_function_create_menu  (rc ,0);

    add_fun_bt = gg_button_new (rc ,"Add function to selected graphs");
    gtk_widget_modify_bg ( add_fun_bt ,GTK_STATE_NORMAL ,&bleuciel);


    ta = gg_frame (rc ,"Select graphs to attach the function" ,&wheat ,3 ,3);
    gg_buttonA (ta ,"Select all"       ,ge_project_select_CB     ,TRUE);
    gg_buttonA (ta ,"Toggle selection" ,ge_project_toggle_sel_CB ,TRUE);
    gg_buttonA (ta ,"Unselect all"     ,ge_project_select_CB     ,FALSE);

    /* ------------ Notebook defaults and callbacks  -------------- */
    gtk_box_pack_start (GTK_BOX (w_titre) ,project_notb ,FALSE ,TRUE  ,0);

    /* Must be called before the g_signal_connect */
    gg_set_int  (w_order ,0);
    ge_project_update (tdevice);
    gg_set_int  (w_nrows ,1);
    gg_set_int  (w_ncols ,1);
    gg_set_dble (w_toff  ,GA_OFFSET_DEFAULT);
    gg_set_dble (w_loff  ,GA_OFFSET_DEFAULT);
    gg_set_dble (w_roff  ,GA_OFFSET_DEFAULT);
    gg_set_dble (w_boff  ,GA_OFFSET_DEFAULT);
    gg_set_dble (w_hgap  ,GA_GAP_DEFAULT);
    gg_set_dble (w_vgap  ,GA_GAP_DEFAULT);
    gg_set_int  (w_add   ,TRUE);

    /* Callbacks */
    g_signal_connect (w_hpack     ,"toggled" ,G_CALLBACK (ge_hpack_CB) ,NULL);
    g_signal_connect (w_vpack     ,"toggled" ,G_CALLBACK (ge_vpack_CB) ,NULL);
    g_signal_connect (add_fun_bt  ,"clicked" ,G_CALLBACK (ge_project_attach_fun_CB) ,NULL);
    handler_id = g_signal_connect (project_notb ,"switch-page" ,G_CALLBACK (ge_project_switch_page_CB) ,NULL);

    gg_unset_wait_cursor();
    gtk_widget_show_all (w_titre);
    current_page = 0;
  }
  return w_titre;
}

/**
 *   Menu update
 */
void ge_project_update  (int device_id)
{
  if (w_titre == NULL) return;
  if (project_notb != NULL) {
    /* ------------ Page tab  update -------------- */
    /* Page dimensions */
    pdim.device_id = device_id;
    gg_page_dimensions_update (&pdim);
    /* Page background */
    gg_set_int (w_bg_color ,getbgcolor ());
    gg_set_int (w_bg_fill  ,getbgfill());
    /* ------------ Graphs operations tab update -------------- */
    ge_project_graph_list ();
    /* ------------ Function tab update -------------- */
    ge_function_type_update ();
  }
}

/**
 *   Menu apply
 */
void ge_project_apply  (void)
{
  char message[40];
  Device_entry dev;
  int ngraphs ,*graphs ,i;
  int nrows, ncols, order, snake;
  int hpack, vpack, add, kill;
  double toff, loff, roff, boff, vgap, hgap;

  if (w_titre == NULL) return;
  dev = get_device_props (tdevice);

  /* ------------ Main tab apply -------------- */
  gg_page_dimensions_apply (&pdim);
  setbgcolor (gg_get_int (w_bg_color));
  setbgfill  (gg_get_int (w_bg_fill));


  /* ------------ Arrange graphs tab apply -------------- */
  if (current_page == 1) { /* only if the tab is the current one i.e. tab 1 */
    nrows = gg_get_int (w_nrows);
    ncols = gg_get_int (w_ncols);
    if (nrows < 1 || ncols < 1) {
      errmsg("# of rows and columns must be > 0");
      return;
    }

    ngraphs = 0;
    for (i = 0; i < number_of_graphs (); i++) {
      if (gg_get_int (gbut[i]) == TRUE) ngraphs++;
    }
    if (ngraphs == 0) ngraphs = number_of_graphs();

    graphs = malloc (ngraphs * sizeof(int));
    for (i = 0; i <ngraphs ; i++)  graphs[i] = i;


    order = gg_get_int (w_order);
    snake = gg_get_int (w_snake);

    toff  = gg_get_dble (w_toff);
    loff  = gg_get_dble (w_loff);
    roff  = gg_get_dble (w_roff);
    boff  = gg_get_dble (w_boff);
    hgap  = gg_get_dble (w_hgap);
    vgap  = gg_get_dble (w_vgap);

    add   = gg_get_int (w_add);
    kill  = gg_get_int (w_kill);
    hpack = gg_get_int (w_hpack);
    vpack = gg_get_int (w_vpack);

    ge_tree_need_update  (FALSE);

    if (add && ngraphs < nrows*ncols) {
      int gno;
      graphs = xrealloc (graphs, nrows*ncols*SIZEOF_INT);
      for (gno = number_of_graphs(); ngraphs < nrows*ncols; ngraphs++, gno++) {
	graphs[ngraphs] = gno;
      }
      ge_tree_need_update  (TRUE);
    }

    if (kill && ngraphs > nrows*ncols) {
      sprintf (message, "Kill Graphs %d to  %d?" ,nrows*ncols+1 ,ngraphs);
      if (yesno (message) == FALSE) return;
      for (; ngraphs > nrows*ncols; ngraphs--) {
	kill_graph (graphs[ngraphs - 1]);
      }
      ge_tree_need_update  (TRUE);
    }
    arrange_graphs (graphs, ngraphs,
		    nrows, ncols, order, snake,
		    loff, roff, toff, boff, vgap, hgap,
		    hpack, vpack);
  }
  gg_update_all();
  set_dirtystate ();
  gg_drawgraph ();
}


/**************** C A L L B A C K S ****************/


void ge_project_apply_CB (GtkWidget *w ,gpointer p)
{
  ge_project_apply ();
}

void ge_hpack_CB (GtkToggleButton *tbut ,gpointer p)
{
  gtk_widget_set_sensitive (w_hgap ,!gtk_toggle_button_get_active (tbut));
}
void ge_vpack_CB (GtkToggleButton *tbut ,gpointer p)
{
  gtk_widget_set_sensitive (w_vgap ,!gtk_toggle_button_get_active (tbut));
}


/**
 * Create check buttons for the graph list
 */
static void ge_project_graph_list (void)
{
  int ngraphs ,i ,j;
  char buf[8];
  ngraphs = number_of_graphs ();
  if (ngraphs > cur_ngraphs) {
    gbut = xrealloc (gbut ,ngraphs * sizeof (GtkWidget *));
    j = cur_ngraphs % NB_COLS;
    for (i = cur_ngraphs; i < ngraphs; i++) {
      sprintf (buf ,"%d" ,i);
      gbut[i] = gg_check_new (gcol[j] ,buf);
      j++;
      j = j % NB_COLS;
    }
    cur_col = j;
  } else if (ngraphs < cur_ngraphs) {
    for (i = ngraphs; i < cur_ngraphs ; i++) {
      gtk_widget_destroy (gbut[i]);
    }
  }
  for (i = 0; i < ngraphs; i++) {
    gg_set_int (gbut[i] ,FALSE);
  }
  cur_ngraphs = ngraphs;
}

static void ge_project_select_CB (GtkWidget *w ,gpointer p)
{
  int i;
  int sel = GPOINTER_TO_INT (p);
  for (i = 0; i < cur_ngraphs; i++) {
    gg_set_int (gbut[i] ,sel);
  }
}

static void ge_project_toggle_sel_CB (GtkWidget *w ,gpointer p)
{
  int i ,osel;
  for (i = 0; i < cur_ngraphs; i++) {
    osel = gg_get_int (gbut[i]);
    gg_set_int (gbut[i] ,!osel);
  }
}


static void ge_project_hide_CB (GtkWidget *w ,gpointer p)
{
  int i;
  int ghide = GPOINTER_TO_INT (p);
  for (i = 0; i < cur_ngraphs; i++) {
    if (gg_get_int (gbut[i])) {
      set_graph_hidden (i ,ghide);
    }
  }
  gg_drawgraph();
  gg_graph_update_all_lists ();
}

static void ge_project_duplicate_CB (GtkWidget *w ,gpointer p)
{
  int i;

  for (i = 0; i < cur_ngraphs; i++) {
    if (gg_get_int (gbut[i])) {
      duplicate_graph (i);
    }
  }
  gg_drawgraph();
  ge_update_explorer ();
  ge_project_graph_list ();
}


static void ge_project_kill_CB (GtkWidget *w ,gpointer p)
{
  int i;
  if (yesno ("Kill selected graphs?") == FALSE) return;

  for (i = 0; i < cur_ngraphs; i++) {
    if (gg_get_int (gbut[i])) {
      kill_graph (i);
    }
  }
  gg_drawgraph          ();
  ge_update_explorer    ();
  ge_project_graph_list ();
}

static void ge_project_attach_fun_CB (GtkWidget *w ,gpointer p)
{
  int i;

  for (i = 0; i < cur_ngraphs; i++) {
    if (gg_get_int (gbut[i])) {
      ge_function_create (i);
    }
  }
  gg_drawgraph();
  ge_update_explorer ();
  ge_expand_current ();
  ge_select_current ();
}

/**
 * Open explorer project/page tab from outside this file
 */
void ge_project_open_page_tab_CB (GtkWidget *w ,gpointer p)
{
  ge_explorer_popup ();
  ge_unselect_all   ();
  ge_select_root    ();
  current_page = 0;
  ge_project_set_page ();
}


/******************** GRACE-5 COMPATIBILITY ********************/

void ge_project_layout_g5compat_CB (GtkWidget *w ,gpointer p)
{
  ge_explorer_popup   ();
  ge_unselect_all     ();
  ge_select_root      ();
  current_page        = 1;  /* the layout tab */
  ge_project_set_page ();


}
