/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* result_msock.c --- output recognition result via module socket */

#include <julius.h>
#include <time.h>

/**********************************************************************/
/* decode outcode "WLPSwlps" to each boolean value */
/* default: "WLPS" */
static boolean out1_word = FALSE, out1_lm = FALSE, out1_phone = FALSE, out1_score = FALSE;
static boolean out2_word = TRUE, out2_lm = TRUE, out2_phone = TRUE, out2_score = TRUE;
static boolean out1_never = TRUE, out2_never = FALSE;

void
decode_output_selection(char *str)
{
  int i;
  out1_word = out1_lm = out1_phone = out1_score = FALSE;
  out2_word = out2_lm = out2_phone = out2_score = FALSE;
  for(i = strlen(str) - 1; i >= 0; i--) {
    switch(str[i]) {
    case 'W': out2_word  = TRUE; break;
    case 'L': out2_lm    = TRUE; break;
    case 'P': out2_phone = TRUE; break;
    case 'S': out2_score = TRUE; break;
    case 'w': out1_word  = TRUE; break;
    case 'l': out1_lm    = TRUE; break;
    case 'p': out1_phone = TRUE; break;
    case 's': out1_score = TRUE; break;
    default:
      j_printerr("Error: unknown outcode `%c', ignored\n", str[i]);
      break;
    }
  }
  out1_never = ! (out1_word | out1_lm | out1_phone | out1_score);
  out2_never = ! (out2_word | out2_lm | out2_phone | out2_score);

}

/**********************************************************************/

/* 1st pass: begin output */
static void
msock_pass1_begin()
{
}

/* 1st pass: output current result while search */
static void
msock_pass1_current(int t, WORD_ID *seq, int num, LOGPROB score, LOGPROB LMscore, WORD_INFO *winfo)
{
  int i,j;
  char buf[50];

  if (out1_never) return;	/* no output specified */

  if (out1_score) {
    module_send("<RECOGOUT>\n  <PHYPO PASS=\"1\" SCORE=\"%f\" FRAME=\"%d\" TIME=\"%ld\">\n", score, t, time(NULL));
  } else {
    module_send("<RECOGOUT>\n  <PHYPO PASS=\"1\" FRAME=\"%d\" TIME=\"%ld\">\n", t, time(NULL));
  }
  for (i=0;i<num;i++) {
    module_send("    <WHYPO");
    if (out1_word) {
      module_send(" WORD=\"%s\"", winfo->woutput[seq[i]]);
    }
    if (out1_lm) {
      module_send(" CLASSID=\"%s\"", winfo->wname[seq[i]]);
    }
    if (out1_phone) {
      module_send(" PHONE=\"");
      for(j=0;j<winfo->wlen[seq[i]];j++) {
	center_name(winfo->wseq[seq[i]][j]->name, buf);
	if (j == 0) module_send("%s", buf);
	else module_send(" %s", buf);
      }
      module_send("\"");
    }
    module_send("/>\n");
  }
  module_send("  </PHYPO>\n</RECOGOUT>\n.\n");
}

/* 1st pass: output final result */
static void
msock_pass1_final(WORD_ID *seq, int num, LOGPROB score, LOGPROB LMscore, WORD_INFO *winfo)
{
  int i,j;
  char buf[50];

  if (out1_never) return;	/* no output specified */

  if (out1_score) {
    module_send("<RECOGOUT>\n  <SHYPO PASS=\"1\" SCORE=\"%f\">\n", score);
  } else {
    module_send("<RECOGOUT>\n  <SHYPO PASS=\"1\">\n", score);
  }
  for (i=0;i<num;i++) {
    module_send("    <WHYPO");
    if (out1_word) {
      module_send(" WORD=\"%s\"", winfo->woutput[seq[i]]);
    }
    if (out1_lm) {
      module_send(" CLASSID=\"%s\"", winfo->wname[seq[i]]);
    }
    if (out1_phone) {
      module_send(" PHONE=\"");
      for(j=0;j<winfo->wlen[seq[i]];j++) {
	center_name(winfo->wseq[seq[i]][j]->name, buf);
	if (j == 0) module_send("%s", buf);
	else module_send(" %s", buf);
      }
      module_send("\"");
    }
    module_send("/>\n");
  }
  module_send("  </SHYPO>\n</RECOGOUT>\n.\n");
}

/* 1st pass: end output */
static void
msock_pass1_end()
{
  /* no op */
}

/**********************************************************************/

/* 2nd pass output */
static void
msock_pass2(NODE *hypo, int rank, WORD_INFO *winfo)
{
  int i,j;
  WORD_ID w;
  char buf[50];

  if (out2_never) return;	/* no output specified */

  if (hypo == NULL) {
    module_send("<RECOGFAIL>\n.\n");
    return;
  }
  /* assume ranks are ordered */
  if (rank <= 1) {		/* first time */
    module_send("<RECOGOUT>\n");
  }
  module_send("  <SHYPO RANK=\"%d\"", rank);
  if (out2_score) {
    module_send(" SCORE=\"%f\"", hypo->score);
  }
#ifdef USE_DFA
  /* output which grammar the best hypothesis belongs to */
  {
    MULTIGRAM *m;
    int tb,te;
    WORD_ID c;

    /* determine only by the last word */
    c = winfo->wton[hypo->seq[0]];
    for(m = gramlist; m; m = m->next) {
      if (m->active) {
	tb = m->cate_begin;
	te = tb + m->dfa->term_num;
	if (tb <= c && c < te) { /* found */
	  module_send(" GRAM=\"%d\"", m->id);
	  break;
	}
      }
    }
  }
#endif
  
  module_send(">\n");
  for (i=hypo->seqnum-1;i>=0;i--) {
    w = hypo->seq[i];
    module_send("    <WHYPO");
    if (out2_word) {
      module_send(" WORD=\"%s\"", winfo->woutput[w]);
    }
    if (out2_lm) {
      module_send(" CLASSID=\"%s\"", winfo->wname[w]);
    }
    if (out2_phone) {
      module_send(" PHONE=\"");
      for(j=0;j<winfo->wlen[w];j++) {
	center_name(winfo->wseq[w][j]->name, buf);
	if (j == 0) module_send("%s", buf);
	else module_send(" %s", buf);
      }
      module_send("\"");
    }
    module_send("/>\n");
  }
  
  module_send("  </SHYPO>\n");
  if (rank >= nbest) {		/* last candidate */
    module_send("</RECOGOUT>\n.\n");
  }
}

/**********************************************************************/
/* recording status */
void
msock_status_recready()
{
  module_send("<INPUT STATUS=\"LISTEN\" TIME=\"%ld\"/>\n.\n", time(NULL));
}
void
msock_status_recstart()
{
  module_send("<INPUT STATUS=\"STARTREC\" TIME=\"%ld\"/>\n.\n", time(NULL));
}
void
msock_status_recend()
{
  module_send("<INPUT STATUS=\"ENDREC\" TIME=\"%ld\"/>\n.\n", time(NULL));
}
/**********************************************************************/
/* regist functions */
void
setup_result_msock()
{
  if (!module_mode) {
    j_error("Error: result_msock: not in module mode!\n");
  }
  result_pass1_begin   = msock_pass1_begin;
  result_pass1_current = msock_pass1_current;
  result_pass1_final   = msock_pass1_final;
  result_pass1_end     = msock_pass1_end;
  result_pass2         = msock_pass2;
}
