/* file = showmatch.c */ 
/* graphically shows the word spotting results.
   reads in a .wh file, and the corresponding .la and .au files, if any */ 
/* Nigel Ward, University of Tokyo, April 1994 */

/*-----------------------------------------------------------------------------*/
#include "cheap.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

/*----------------------------------------------------------------------------- */
#define CANVAS_WIDTH      1000
#define CANVAS_HEIGHT      700
#define LEFT_MARGIN    20

#define FILENAME_YPOS     30
#define LABEL_YPOS       FILENAME_YPOS + 40
#define ZEROTH_WHYP_YPOS LABEL_YPOS + 30
#define YSPACING     15

#define NOT_FOUND -1

/*----------------------------------------------------------------------------- */
extern Display	*display;
extern Window	win;
extern XEvent  report;

extern struct signature templates[MAX_NTEMPLATES];

/*-----------------------------------------------------------------------------*/
static Audio_filehdr hdr;	

static int nframes; 
static struct whyp labels[MAX_LABELS];
static int nlabels;
static struct whyp hyps[MAX_NTEMPLATES];
static int nwh;

static int nfiles;
static int active_file;
static char file_list[100][MAX_PATH_LEN];
/* directory in which to seek .la and .au files */
static char label_dir[MAX_PATH_LEN];   

/*=============================================================================*/
showmatch_usage() 
{
  fprintf(stderr, "usage: \n");
  fprintf(stderr, "   showmatch [-l label_directory] [input_files.wh]+\n");
  fprintf(stderr, "Options \n");
  fprintf(stderr, "  -l <dir>   specify directory to use for .la and .au files\n");
}

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

main(argc,argv)      int argc;      char *argv[];
{
  int i, first_wh_file;

  /* should parse arguments in a more standard way */
  /* handle -l option */
  if (argc > 1 && argv[1][0] == '-' &&  argv[1][1] == 'l') {
    strcpy(label_dir, argv[2]);
    first_wh_file = 3; }
  else {
    strcpy(label_dir,"");
    first_wh_file = 1; }
  
  nfiles = argc - first_wh_file;
  if (nfiles == 0) {
    fprintf(stderr, "please specify one or more .wh files\n");
    showmatch_usage();
    exit(STRANGE);}
  for (i = 0; i < nfiles; i++) {
    strcpy(file_list[i], argv[first_wh_file + i]); }
  active_file = 0;
  sg_create(CANVAS_WIDTH, CANVAS_HEIGHT, 1, "showmatch");
  nlabels = read_label_file_from_dir(label_dir, file_list[active_file], labels);
  read_wh_file(file_list[active_file], &nframes, &nwh, hyps);
  print_help();
  usleep(300000);     /* sometimes the window comes up blank */
  event_loop(); 
  /* not reached */
  exit(NORMAL);
}

/*-----------------------------------------------------------------------------*/
event_loop()
{
  KeySym keysym;
  static char buffer[MAX_WORD_LEN];
  XComposeStatus compose;
  char *string;

  /* event loop code taken from Nye, volume 2 pg 72 */
  XSelectInput(display, win,  ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask);

  while (TRUE) {
    XNextEvent(display, &report);
    switch (report.type) {
    case Expose:
	if (report.xexpose.count != 0)
	  break;
	redraw_display();
	break;
    case KeyPress:
	/* it's a command */
	(void) XLookupString( (XKeyEvent *) &report, buffer, MAX_WORD_LEN, &keysym, &compose); 
	string = XKeysymToString(keysym);
	if (string != NULL)
	  handle_command(string);
	break; 
    }
  }
}

/*-----------------------------------------------------------------------------*/
handle_command(string)          char* string;
{
  char cmd;
  char msg_string[100];
  if (strcmp (string, "space") == 0) cmd = ' ';
  else cmd = string[0];
  switch (cmd) {
  case 'q': clean_up(); exit(NORMAL); break;
  case 'o': open_next_file(); break;
  case 'u': open_previous_file(); break;
  case ' ': play_audio();    break;
  default: 
    sprintf(msg_string, "unknown command: %c; see term window for commands", cmd);
    draw_notice(msg_string);
    redraw_display();
    print_help();
    break;  
} }

/*-----------------------------------------------------------------------------*/
/* should write to window, not the kterm */
print_help()
{
  fprintf(stderr, "Commands:                               \n");
  fprintf(stderr, "    r - redraw displays file            \n");
  fprintf(stderr, "    o - open next file                  \n");
  fprintf(stderr, "    u - reopen previous file            \n");
  fprintf(stderr, "space - play audio (to speaker or jack) \n");
  fprintf(stderr, "    q - quit                            \n"); }
  

/*=============================================================================*/

clean_up()
{ sg_close();}

/*-----------------------------------------------------------------------------*/
ms_to_pixels(milliseconds)   int milliseconds;
{  return( (int) (LEFT_MARGIN + (milliseconds / (float) MS_PER_PIXEL))); }

/*-----------------------------------------------------------------------------*/
redraw_display()
{
  sg_clear();
  display_filename();
  display_labels();
  display_hyps(); }

/*-----------------------------------------------------------------------------*/
display_labels()
{
  int i, y1, y2;
  y1 = LABEL_YPOS - 10;
  y2 = y1 + 50 + YSPACING * nwh;

  vertical_dots(ms_to_pixels(0), y1, y2);
  for (i = 0; i < nlabels; i++) {
    draw_label(8 + ms_to_pixels(labels[i].start), labels[i].label);
    vertical_dots(ms_to_pixels(labels[i].start), y1, y2); 
    vertical_dots(ms_to_pixels(labels[i].end), y1, y2); 
  }
  vertical_dots(ms_to_pixels(FRAME_SPACING * nframes), y1, y2);
 }

/*-----------------------------------------------------------------------------*/
display_hyps()
{
  int i, index, overlap_exists, start_of_overlap, end_of_overlap;

  for(i = 0; i < nwh; i++) {
    index = lookup_correct(hyps[i].label, labels, nlabels);
    if (index == NOT_FOUND) {
      overlap_exists = FALSE; }
    else {
      start_of_overlap = labels[index].start > hyps[i].start ?
	labels[index].start : hyps[i].start;
      end_of_overlap =
	labels[index].end < hyps[i].end ? labels[index].end : hyps[i].end;
      if (end_of_overlap < start_of_overlap)
	overlap_exists = FALSE;
      else overlap_exists = TRUE;
    }
    display_span(hyps[i].label,
		 ms_to_pixels(hyps[i].start),
		 ms_to_pixels(hyps[i].start + hyps[i].len),
		 ZEROTH_WHYP_YPOS + YSPACING * i,
		 hyps[i].score,
		 overlap_exists, 
		 ms_to_pixels(start_of_overlap), ms_to_pixels(end_of_overlap));
  } }
  
/*-----------------------------------------------------------------------------*/
display_filename()
{  sg_string(LEFT_MARGIN, FILENAME_YPOS, file_list[active_file]);}


/*-----------------------------------------------------------------------------*/
/* show warning messages etc. */
draw_notice(string)         char *string;
{  
  sg_erase_rect(300, 0, 1000, 25);    /* blank out previous messages */
  sg_string(300, 20, string);}

/*-----------------------------------------------------------------------------*/
draw_label(where, string)   int where; char *string;
{  sg_string(where, LABEL_YPOS, string);}

/*-----------------------------------------------------------------------------*/
play_audio()
{
  char raw_data[MAX_SAMPLES];
  char filename[50], au_filename[50];
  int nsamples;
  char info_string[MAX_INFO_STRING_LEN];

  if (strcmp(label_dir,"") == 0) {
    strcpy(filename, file_list[active_file]); }
  else {
    strcpy(filename, label_dir);
    strcat(filename, "/");
    strcat(filename, file_list[active_file]); }
  make_new_path(au_filename, filename, ".au");

  nsamples = read_au_into_array(au_filename, &hdr, info_string, raw_data);
  play_audio_data(raw_data, 0, nsamples); 
}

/*-----------------------------------------------------------------------------*/
open_next_file()
{
  if (active_file + 1 >= nfiles) {
    draw_notice("no more files; q to exit, then restart showmatch"); }
  else {
    active_file +=1;
    do_new_file(); } }

/*-----------------------------------------------------------------------------*/
open_previous_file()
{
  if (active_file == 0) {
    draw_notice("this is the first file, no previous ones"); }
  else {
    active_file -=1;
    do_new_file(); } }

/*-----------------------------------------------------------------------------*/
do_new_file() {
  nlabels = read_label_file_from_dir(label_dir, file_list[active_file], labels);
  read_wh_file(file_list[active_file], &nframes, &nwh, hyps);
  redraw_display(); }

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