/* Copyright (C) 2002 Bjoern Beutel. */

/* Description. =============================================================*/

/* Read in and display Malaga debugger expressions. */

/* Includes. ================================================================*/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <gtk/gtk.h>
#include "basic.h"
#include "scanner.h"
#include "input.h"
#include "canvas.h"
#include "expressions.h"

/* Types. ===================================================================*/

typedef struct 
{ 
  list_node_t *next;
  pos_string_t *name;
  pos_value_t *value;
  bool_t is_shown;
} expression_t;

/* Global variables. ========================================================*/

rectangle_t expressions_geometry;
string_t expressions_font_family;
int_t expressions_font_size;

/* Variables. ===============================================================*/

static list_t expressions;
static canvas_t *expressions_canvas;
static pos_string_t *equal, *dots;

/* Functions. ===============================================================*/

static void
configure_expressions( canvas_t *canvas, int_t *width_p, int_t *height_p )
{
  int_t width, height;
  expression_t *expression;
  int_t font_height = get_font_height( canvas );
  int_t space_width = get_space_width( canvas );
  int_t border_width = get_border_width( canvas );

  config_pos_string( equal, canvas );
  config_pos_string( dots, canvas );

  width = height = border_width;
  FOREACH( expression, expressions ) 
  { 
    if (expression != (expression_t *) expressions.first) 
      height += font_height;

    config_pos_string( expression->name, canvas );
    expression->name->x = border_width;
    expression->name->y = height;
    equal->x = expression->name->x + expression->name->width + space_width;
    if (expression->is_shown)
    {
      config_pos_value( expression->value, canvas );
      expression->value->x = equal->x + equal->width + space_width;
      expression->value->y = height;
      expression->name->y += (expression->value->height - font_height) / 2;
      width = MAX( width, expression->value->x + expression->value->width );
      height += expression->value->height;
    }
    else
    {
      dots->x = equal->x + equal->width + space_width;
      width = MAX( width, dots->x + dots->width );
      height += font_height;
    }
  }

  *width_p = width + border_width;
  *height_p = height + border_width;
}

/*---------------------------------------------------------------------------*/

static void
expose_expressions( canvas_t *canvas, rectangle_t *area )
{
  int_t space_width = get_space_width( canvas );
  expression_t *expression;
  
  set_color( BLACK );
  FOREACH( expression, expressions ) 
  { 
    draw_pos_string( expression->name, canvas );
    equal->x = expression->name->x + expression->name->width + space_width;
    equal->y = expression->name->y;
    draw_pos_string( equal, canvas );
    if (expression->is_shown) 
      draw_pos_value( expression->value, canvas );
    else 
    {
      dots->x = equal->x + equal->width + space_width;
      dots->y = equal->y;
      draw_pos_string( dots, canvas );
    }
  }
}

/*---------------------------------------------------------------------------*/

static bool_t
mouse_event( canvas_t *canvas, int_t x, int_t y, int_t button )
/* Called if mouse has moved in CANVAS at position X/Y. */
{
  expression_t *expression;
  int_t font_height = get_font_height( canvas );

  FOREACH( expression, expressions )
  {
    if (x >= expression->name->x 
	&& x < expression->name->x + expression->name->width
	&& y >= expression->name->y 
	&& y < expression->name->y + font_height)
    {
      if (button == 0) 
	set_cursor( canvas, TRUE );
      else if (button == 1) 
      { 
	expression->is_shown = ! expression->is_shown;
	configure_canvas( canvas );
      }
      else if (button == 3)
      {
	free_pos_string( &expression->name );
	free_pos_value( &expression->value );
	free_node( (list_t *) &expressions, (list_node_t *) expression );
	configure_canvas( canvas );
      }
      return TRUE;
    }
  }
  set_cursor( canvas, FALSE );
  return FALSE;
}

/*---------------------------------------------------------------------------*/

static void
show_all_expressions( canvas_t *canvas, guint do_show )
{
  expression_t *expression;

  FOREACH( expression, expressions ) 
    expression->is_shown = do_show;
  configure_canvas( canvas );
}

/*---------------------------------------------------------------------------*/

static void clear_expressions( canvas_t *canvas )
{
  expression_t *expression;

  FOREACH_FREE( expression, expressions ) 
  { 
    free_pos_string( &expression->name );
    free_pos_value( &expression->value );
  }
  configure_canvas( canvas );
}

/*---------------------------------------------------------------------------*/

static GtkItemFactoryEntry menu_items[] = 
{
  { "/Expressions", NULL, NULL, 0, "<Branch>" },
  { "/Expressions/Clear All", NULL, clear_expressions, NULL, NULL },
  { "/Expressions/Show All", NULL, show_all_expressions, TRUE, NULL },
  { "/Expressions/Hide All", NULL, show_all_expressions, FALSE, NULL },
};

/*---------------------------------------------------------------------------*/

void 
read_expressions( void )
/* Read new expressions from STDIN. */
{
  string_t line;
  expression_t *expression;

  while (TRUE) 
  { 
    line = read_line( stdin );
    if (line == NULL) 
      complain( "Premature EOF." );
    if (strcmp_no_case( line, "end" ) == 0) 
      break;

    /* Read a new expression. */
    expression = new_node( &expressions, sizeof( expression_t ), LIST_END );
    set_scanner_input( line );

    /* Read expression name. */
    test_token( TOK_STRING );
    expression->name = new_pos_string( token_string );
    read_next_token();

    /* Read expression value. */
    parse_token( '{' );
    expression->value = parse_pos_value();
    parse_token( '}' );
    parse_token( EOF );
    set_scanner_input( NULL );
    free_mem( &line );

    expression->is_shown = TRUE;
  }
  free_mem( &line );
  
  if (equal == NULL) 
    equal = new_pos_string( "=" );
  if (dots == NULL) 
    dots = new_pos_string( "..." );

  if (expressions_canvas == NULL) 
  { 
    expressions_canvas = create_canvas(
      "Malaga Expressions", "expressions.eps", &expressions_geometry, 
      configure_expressions, expose_expressions, NULL, mouse_event,
      TRUE, menu_items, ARRAY_LENGTH( menu_items ) );
  } 
  else
  {
    configure_canvas( expressions_canvas );
    go_canvas_bottom( expressions_canvas );
    show_canvas( expressions_canvas );
  }
}

/* End of file. =============================================================*/
