/* -*- Java -*-
 *
 * Copyright (c) 2003
 * Spoken Language Systems Group
 * MIT Laboratory for Computer Science
 * Massachusetts Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 **/

/**
 * Modified by Aaron Adler, Design Rationale Group, 3-14-03
 * (c) MIT 2003.  All rights reserved.
 **/

package rec.multi;

import java.io.*;
import java.net.ConnectException;
import edu.mit.lcs.sls.galaxy.frame.*;
import edu.mit.lcs.sls.galaxy.server.*;
import java.util.StringTokenizer;
import rec.util.Console;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;
import edu.mit.tools.watch.Logging;

/**
 * A simple Frame-relay server that controls the C++ Playbox server
 **/
public class Playbox extends Server implements SpeechInput {

  private static Logger LOG = Logging.PLAYBOX;
  
  private BufferedReader m_reader;
  private String m_playboxDest = "playbox_audio";
  private MultiModal m_multi;
  private int m_connectErrorCount = 0;

  private String m_host ;
  private int m_port;
  private String m_name;
  
  private boolean m_done = false;

  public Playbox(String host, int port, String name, MultiModal multi) {
    super(host, port, name, new BasicFrameFactory());

    LOG.debug("creating new playbox");
    
    m_multi = multi;
    m_host = host;
    m_port = port;
    m_name = name;
    
    m_reader = new BufferedReader(new InputStreamReader(System.in));
  }
  
  /**
   * Abort the connection attempt.
   */
  public void abort() {
    super.abort();

    LOG.info("aborting the connection attempt");
    
    m_done = true;
  }
  

  /**
   * ada:
   * Override method in Server!
   * moved some stuff from constuctor to run, also changed to set ready to true
   * 
   * Start the server running.  This will connect to the frame-relay
   * server if a connection has not already been established.
   * */
  public void run() {
    // begin move from constructor
    Frame frame = frameFactory.createClause("set_list_destination");
    frame.putProperty("dest", m_name);
    while(!m_done){
      try {
	sendMessage(m_playboxDest, frame);
	break;
      }
      catch (IOException e){
	System.err.println(e.toString());
      }
    }
    frame = frameFactory.createClause("start_recording");
    try {
      sendMessage(m_playboxDest, frame);
    } catch (IOException e){
      LOG.debug("IO Exception: "+e.toString());
    }
    LOG.debug("Waiting for result");
    // end move

    try {
      while(!m_done){
	try {
	  whileConnected(new Operation(){
	      
	      public void invoke() throws IOException{
		m_multi.setReady(true); // ready to go!
		while(!m_done){
		  handleMessage();
		}
	      }});	
	} catch (UnknownHostException e){
	  throw e;
	} catch (IOException e){
	  onException(e);
	  disconnect();
	}
      }
    } catch (UnknownHostException e){
      onException(e);
      return;
    }
  }
  
  public void onException(Exception e){
    LOG.error("Connection error in Playbox");
  }	    

    /**
     * Received frames will be sent to this function, which dispatches
     * to a handler based on the frame name.
     **/
    public void onFrame(ServerContext context, Frame f){
	try {
	    String op = f.getName();
	    if (op.equals("wordconf_nbest")){
		// extract the relevant text
	        String eStr = getBestString(extractString(f.toString()));
		LOG.debug("Top choice is: "+eStr);

		// ada: we need to get the time for the speech events
		// somehow, now we're just guessing! 
		long curTime = System.currentTimeMillis();
		long startTimeGuess = curTime - (eStr.length()*100);
		m_multi.addSpeech(eStr, startTimeGuess, curTime);

	    } else if (op.equals("print")){
		onPrint(context, (String)f.getProperty("output_string"));
	    } else if (op.equals("enable_input")){
		onEnableInput(context,(String)f.getProperty("prompt"));
	    } else {
		LOG.error("UNKNOWN frame: "+f.toString());
	    }
	}
	catch(ClassCastException e){
	    LOG.error("class cast exception: "+e.toString());
	}
    }

    public void onPrint(ServerContext context, String string){
	LOG.debug(string);
	context.reply(frameFactory.createClause("lintest.reply"));
    }

    public void onEnableInput(ServerContext context, String prompt){
	System.out.println(prompt);
	System.out.print("> ");
	System.out.flush();	// Flush to print partial line
	try {
	    String val = m_reader.readLine();
	    Frame reply = frameFactory.createClause("lintest.reply");
	    reply.putProperty("input_string", val);
	    context.reply(reply);
	} catch (IOException e){
	    System.err.println("ERROR: "+e.toString());
	}
    }

  private String getBestString(String in) {
    // we need the first string which is deliniated by brackets []
    int startIndex = in.indexOf("[") +1;
    int endIndex = in.indexOf("]");

    String basicString = in.substring(startIndex, endIndex);

    return basicString;
  }
    
  
  private String extractString(String in) {
    // we need the part of the string that is inside the parens
    String insidePart = in.substring(in.indexOf("(")+1, in.indexOf(")")-1);
    StringTokenizer st = new StringTokenizer(insidePart);
    StringBuffer out = new StringBuffer();
    
    // for now skip the first 3 numbers that are in quotes
    st.nextToken();
    st.nextToken();
    st.nextToken();
    st.nextToken();
    st.nextToken();

    // now what we want is surrounded by " marks
    while (st.hasMoreElements() && (st.nextToken().equals("\""))) {
      // we have another choice
      if (!st.hasMoreElements()) break;
      String next = st.nextToken();
      out.append("[");
      while (st.hasMoreElements() && (!next.equals("\""))) {
	// we have another word
	out.append(next+" ");
	if (!st.hasMoreElements()) break;
	st.nextToken(); // read the number that we don't do anything with for now
	if (!st.hasMoreElements()) break;
	next = st.nextToken();
      }
      out.append("]\n");
    }

    return out.toString();
  }

}

