/* Copyright (c) 2008 Charles Rich and Worcester Polytechnic Institute.
 * All Rights Reserved.  Use is subject to license terms.  See the file
 * "license.terms" for information on usage and redistribution of this
 * file and for a DISCLAIMER OF ALL WARRANTIES.
 * 
 * Refactored from SpeechGuide by willie
 */
package edu.wpi.cetask.guide;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
import edu.wpi.cetask.*;

import javax.swing.*;

public class SpeechUI implements ITaskUI {
   
   private boolean mute;
   
   /**
    * Simple wrapper for speech recognition system
    */
   public interface Recognizer {
      
      /**
       * Turn on microphone for one utterance (automatic endpointing)
       * @return recognized string
       */
      String recognize ();

      /**
       * @param utterance - natural language string
       * @return semantics of utterance 
       */
      Object interpret (String utterance);
      
      /**
       * Load and start using specified grammar (replaces current grammar)
       */
      void loadGrammar (String uri) throws IOException;
      
      /**
       * Free up threads, etc., so can exit cleanly 
       */
      void deallocate ();
      
      /**
       * Clean up and buffers
       */
      void clear();
   }
   
   /**
    * Simple wrapper for text-to-speech system
    */
   public interface Generator {
      
      /**
       * Generate speech for given text
       */
      void generate (String text);
   }
   
   //final protected Recognizer recognizer;
   //final protected Generator generator;
   protected Recognizer recognizer;
   protected Generator generator;
   final protected SpeechUI speech;
   
   static private JFrame win;
   
   protected SpeechUI (Recognizer recognizer, Generator generator) {
	   
	   win = new JFrame("Speech Guide") ;
	   win.setVisible(true);
	      
	  System.setProperty( "freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory" );
	   
      this.recognizer = recognizer;
      this.generator = generator;
      
      speech = this;
      Guide.guide.engine.setOnParsing(new TaskEngine.OnParsing () {
    	  public void onParse (String uri, TaskModel model) {
    		  // TODO internationalize with resource bundles
    		  uri = Utils.replaceEndsWith(uri, ".xml", ".gram");
    		  try { 
    			  speech.recognizer.loadGrammar(uri); 
    			  if ( TaskEngine.VERBOSE ) 
    				  Guide.guide.println("# Loaded speech grammar "+uri);
    		  } catch (IOException e) {} // ignore if no grammar
    	  }
      });

      // make control key push-to-talk
      // note this only works if there is a window with focus
      /*
      KeyboardFocusManager.getCurrentKeyboardFocusManager()
        .addKeyEventDispatcher(new KeyEventDispatcher () {
           public boolean dispatchKeyEvent (KeyEvent event) {
              if ( event.getID() ==  KeyEvent.KEY_PRESSED
                    && event.getKeyCode() == KeyEvent.VK_CONTROL)
                 try {
                	 Guide.guide.addInput("ptt");
                 }
                 catch (Throwable e) { throw new RuntimeException(e); }
              return false;
           }
        });
        */
   }
   
   public void deallocate () {
	  
      recognizer.deallocate();
      // this is giving an error on my Mac, saying the window was unexepectedly closed
      win.dispose();
      win = null;
   }
   

   public void println (Object object) {
      if ( !mute ) {
         String string = object.toString();
         if ( string.length() > 0 ) {
        	 if ( string.charAt(0) != '#' )
        		 generator.generate(object.toString());
         }
      }
   }

   public void prompt () {
	   // clear the microphone buffer
	   recognizer.clear();

	   String command;
	      String utterance = speech.recognizer.recognize();
	      if ( utterance == null || utterance.length() == 0 ) generator.generate("Please repeat");
	      else {
	         //super.println("say "+utterance);
	         //say(utterance);
		      // for this guide, semantics is simply a command string
	    	  generator.generate("I heard, " + utterance);
		      command = (String) speech.recognizer.interpret(utterance);
		      generator.generate("I interpret this to mean, " + command);
		      if ( command == null ) generator.generate("I did not get that, please rephrase."); // respond("@rephrase");
		      else {
		    	  if (Guide.guide != null) {
		  			Guide.guide.addInput(command);
		  		}
		         //if ( TaskEngine.DEBUG ) println("# "+command);
		         //processCommand(command);
		      }

	      }

   }
   
   static public JFrame getSpeechWindow() {
	   return win;
   }
   
}
