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

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

/* Read in and display Malaga Allomorphs. */

/* 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 "allomorphs.h"

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

typedef struct 
{ 
  list_node_t *next;
  pos_string_t *index;
  pos_string_t *surf;
  pos_value_t *value;
} allomorph_t;

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

rectangle_t allomorphs_geometry;
string_t allomorphs_font_family;
int_t allomorphs_font_size;

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

static list_t allomorphs;
static canvas_t *allomorphs_canvas;
static pos_string_t *colon;
static bool_t in_line;

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

static void
configure_allomorphs( canvas_t *canvas, int_t *width_p, int_t *height_p )
{
  int_t width, height;
  allomorph_t *allomorph;
  int_t space_width = get_space_width( canvas );
  int_t font_height = get_font_height( canvas );
  int_t font_ascent = get_font_ascent( canvas );
  int_t border_width = get_border_width( canvas );

  height = border_width;
  width = border_width;

  config_pos_string( colon, canvas );

  FOREACH( allomorph, allomorphs ) 
  { 
    if (allomorph != (allomorph_t *) allomorphs.first) 
      height += font_height;

    config_pos_string( allomorph->index, canvas );
    allomorph->index->x = border_width;
    colon->x = allomorph->index->x + allomorph->index->width;
    config_pos_string( allomorph->surf, canvas );
    allomorph->surf->x = colon->x + colon->width + space_width;
    width = MAX( width, allomorph->surf->x + allomorph->surf->width );

    config_pos_value( allomorph->value, canvas );
    allomorph->value->x = allomorph->surf->x;
    if (in_line)
    {
      allomorph->index->y = allomorph->surf->y = 
	height + allomorph->value->ascent - font_ascent;
      allomorph->value->x += allomorph->surf->width + 2 * space_width;
    }
    else
    {
      allomorph->index->y = allomorph->surf->y = height;
      height += font_height;
    }
    allomorph->value->y = height;
    width = MAX( width, allomorph->value->x + allomorph->value->width );
    height += allomorph->value->height;
  }

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

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

static void
expose_allomorphs( canvas_t *canvas, rectangle_t *area )
{
  allomorph_t *allomorph;
  
  set_color( BLACK );
  FOREACH( allomorph, allomorphs ) 
  { 
    draw_pos_string( allomorph->index, canvas );
    colon->x = allomorph->index->x + allomorph->index->width;
    colon->y = allomorph->index->y;
    draw_pos_string( colon, canvas );
    draw_pos_string( allomorph->surf, canvas );
    draw_pos_value( allomorph->value, canvas );
  }
}

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

static void
free_allomorphs( canvas_t *canvas )
{
  allomorph_t *allomorph;

  free_pos_string( &colon );
  FOREACH_FREE( allomorph, allomorphs ) 
  { 
    free_pos_string( &allomorph->index );
    free_pos_string( &allomorph->surf );
    free_pos_value( &allomorph->value );
  }
}

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

static void 
set_in_line( canvas_t *canvas, guint action, GtkWidget *item )
{
  in_line = GTK_CHECK_MENU_ITEM( item )->active;
  configure_canvas( canvas );
}

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

static GtkItemFactoryEntry in_line_items[] = 
{
  { "/Style/Inline", NULL, set_in_line, 0, "<ToggleItem>" }
};

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

void 
read_allomorphs( void )
/* Read new allomorphs from STDIN. */
{
  string_t line, string;
  allomorph_t *allomorph;
  
  free_allomorphs( NULL );

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

    /* Read a new allomorph. */
    allomorph = new_node( &allomorphs, sizeof( allomorph_t ), LIST_END );
    set_scanner_input( line );

    /* Read allomorph index. */
    string = int_to_string( token_number );
    allomorph->index = new_pos_string( string );
    free_mem( &string );
    read_next_token();

    /* Read allomorph surface. */
    test_token( TOK_STRING );
    string = new_string_readable( token_string, NULL );
    allomorph->surf = new_pos_string( string );
    free_mem( &string );
    read_next_token();

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

  colon = new_pos_string( ":" );

  if (allomorphs_canvas == NULL) 
  { 
    allomorphs_canvas = create_canvas( 
      "Malaga Allomorphs", "allomorphs.eps", &allomorphs_geometry, 
      configure_allomorphs, expose_allomorphs, free_allomorphs, NULL, TRUE, 
      in_line_items, ARRAY_LENGTH( in_line_items ) );
  } 
  else
  { 
    configure_canvas( allomorphs_canvas );
    show_canvas( allomorphs_canvas );
  }
}

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