import java.io.*;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import javax.speech.*;
import javax.speech.recognition.*;
import javax.speech.synthesis.*;

public class Hello {

  static RuleGrammar ruleGrammar;
  static DictationGrammar dictationGrammar;
  static Recognizer recognizer;
  static Synthesizer synthesizer;
  static ResourceBundle resources;

  //
  // Le listener pour la rule grammar. Sa méthode
  // resultAccepted() est appelée lorsqu'une
  // règle publique a été reconnue.
  // On teste alors les balises associées à cette grammaire
  // et on lance l'action correspondante à la balise
  // (filtre sur les balises).
  // Utiliser les balises plutôt que de tester
  // directement les phrases dites permet d'être
  // indépendant de la langue. On peut alors changer la
  // langue sans changer ce programme.
  // Remarque : on utilise une classe interne

  static ResultListener ruleListener = new ResultAdapter() {
    public void resultAccepted(ResultEvent e) {
      try {
        FinalRuleResult result = (FinalRuleResult) e.getSource();
        String tags[] = result.getTags();

        // L'utilisateur a dit "Je m'appelle ..."
        if (tags[0].equals("name")) {
          String s = resources.getString("hello");
          for (int i=1; i<tags.length; i++)
            s += " " + tags[i];
          speak(s);

        // L'utilisateur a dit "Répétez après moi"
        } else if (tags[0].equals("begin")) {
          speak(resources.getString("listening"));
          ruleGrammar.setEnabled(false);
          ruleGrammar.setEnabled("<stop>", true);
          dictationGrammar.setEnabled(true);
          recognizer.commitChanges();
        
        // L'utilisateur a dit "C'est fini"
        } else if (tags[0].equals("stop")) {
          dictationGrammar.setEnabled(false);
          ruleGrammar.setEnabled(true);
          recognizer.commitChanges();

        // L'utilisateur a dit "Au revoir"
        } else if (tags[0].equals("bye")) {
          speak(resources.getString("bye"));
          if (synthesizer!=null)
            synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY);
          Thread.sleep(1000);
          System.exit(0);
        }

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    // Mots mal compris par le programme. 
    // Le programme doit répondre "Pardon?" ou bien "Eh?" ou bien 
    // "Quoi?"
    int i = 0;
    String eh[] = null;
    public void resultRejected(ResultEvent e) {
      if (eh==null) {
        String s = resources.getString("eh");
        StringTokenizer t = new StringTokenizer(s);
        int n = t.countTokens();
        eh = new String[n];
        for (int i=0; i<n; i++)
          eh[i] = t.nextToken();
      }
      if (((Result)(e.getSource())).numTokens() > 2)
        speak(eh[(i++)%eh.length]);
    }
  };


  //
  // L'auditeur pour la dictation grammar. 
  // La méthode resultUpdated() est appelée à chaque mot reconnu.
  // La méthode resultAccepted() est appelée lorsque l'utilisation 
  // de la dictation grammar est terminée. Dans cette application, 
  // cela se produit lorsque l'utilisateur a dit "C'est fini"
  //

  static ResultListener dictationListener = new ResultAdapter() {

    int n = 0; // nombre de mots déjà reconnus

    public void resultUpdated(ResultEvent e) {
      Result result = (Result) e.getSource();
      for (int i=n; i<result.numTokens(); i++)
        System.out.println(result.getBestToken(i).getSpokenText());
      n = result.numTokens();
    }

    public void resultAccepted(ResultEvent e) {
      Result result = (Result) e.getSource();
      String s = "";
      for (int i=0; i<n; i++)
        s += result.getBestToken(i).getSpokenText() + " ";
      speak(s);
      n = 0;
    }
  };


  //
  // L'audio listener. Il imprime le niveau sonore 
  // des paroles de l'utilisateur (bien utile pour déboguer)
  //
  static RecognizerAudioListener audioListener =new RecognizerAudioAdapter(){
    public void audioLevel(RecognizerAudioEvent e) {
      System.out.println("volume " + e.getAudioLevel());
    }
  };


  //
  // La méthode qui fait prononcer des phrases. Si un synthétiseur 
  // vocal n'est pas disponible (mais qu'un reconnaisseur l'est), 
  // affiche les phrases reconnues a l'écran.
  //
  static void speak(String s) {
    if (synthesizer!=null) {
      try {
        synthesizer.speak(s, null);
      } catch (Exception e) {
        e.printStackTrace();
      }
    } else
      System.out.println(s);
  }


  //
  // La méthode main
  //
  public static void main(String args[]) {
    try {
      // Positionne puis affiche la contrée
      if (args.length>0) Locale.setDefault(new Locale(args[0], ""));
      if (args.length>1) Locale.setDefault(new Locale(args[0],
        args[1]));
      System.out.println("locale is " + Locale.getDefault());
      resources = ResourceBundle.getBundle("res");

      // Crée un reconnaisseur correspondant à la contrée
      // ajoute un audio listener
      recognizer = Central.createRecognizer(null);
      recognizer.allocate();
      recognizer.getAudioManager().addAudioListener(audioListener);

      // crée une dictation grammar
      dictationGrammar = recognizer.getDictationGrammar(null);
      dictationGrammar.addResultListener(dictationListener);
      
      // crée une grammaire de règles et la rend active
      String grammarName = resources.getString("grammar");
      Reader reader = new FileReader(grammarName);
      ruleGrammar = recognizer.loadJSGF(reader);
      ruleGrammar.addResultListener(ruleListener);
      ruleGrammar.setEnabled(true);
    
      // Informe le reconnaisseur du statut des diverses grammaires 
      // et lance la reconnaissance de la parole
      recognizer.commitChanges();
      recognizer.resume();

      // crée un synthétiseur et lance un message d'invite
      synthesizer = Central.createSynthesizer(null);
      if (synthesizer!=null) {
        synthesizer.allocate();
      }
      speak(resources.getString("greeting"));

    } catch (Exception e) {
      e.printStackTrace();
      System.exit(-1);
    }
  }
}