/*
 * $Id: AMMCL.java,v 1.1 2008/02/13 03:47:26 nishi Exp $
 * Galatea AM-MCL for Java
 * by Takuya NISHIMOTO (nishi@hil.t.u-tokyo.ac.jp)
 */

package galatea.agentmanager;

import galatea.agent.Agent;
import galatea.util.HashArray;

import java.util.regex.*;

public class AMMCL extends GalateaBase
{
    private int state = 0;
    //
    // sequence for Speak
    // state0 : IDLE
    // state1 : wait FSM/SSM "rep Speak.stat = READY"
    // state2 : wait FSM/SSM "rep Speak.stat = IDLE"
    //
    // sequence for MouthMove
    // state0 : IDLE
    // state3 : wait FSM     "rep Speak.stat = READY"
    // state4 : wait FSM     "rep Speak.stat = IDLE"
    //

//    private boolean ready_ssm = false;
//    private boolean ready_fsm = false;
    private boolean auto_emotion_speak = false;
    private boolean useEventViewer = false;

    private HashArray agents_;
    private String currAgent_;
    private double curr_mouth_scale = 0;

    public AMMCL()
    {
	super();
	modulename_ = "AM-MCL";
	debug_ = false;
	printDebug("initializing...");

        agents_ = new HashArray();
        agents_.put("man01",   new Agent("man01",   "male01",   "bg01", 1.2));
        agents_.put("man02",   new Agent("man02",   "m001",     "bg02", 1.6));
        agents_.put("woman01", new Agent("woman01", "female01", "bg03", 1.2));
        agents_.put("koizumi", new Agent("koizumi", "male01",   "bg04", 1.0));

        currAgent_ = "woman01";
    }

    private Agent _getCurrAgent()
    {
        return (Agent)agents_.get(currAgent_);
    }


    private Agent _getAgentByName(String name)
    {
        return (Agent)agents_.get(name);
    }


    private void _setAgentByName(String name)
    {
        currAgent_ = name;
    }


    private void _sendAgentSpeakState()
    {
	if (useEventViewer) {
	    sendSet( "DIM.GEV.FS-MCL", "AgentSpeakState", state );
	} else {
	    sendSet( "DIM.FS-MCL", "AgentSpeakState", state );
	}
    }


    private String _getOutputText(String arg)
    {
	if (auto_emotion_speak) {
	    return _getCurrAgent().getOutputText(arg);
	} else {
	    return arg;
	}
    }


    private void _printDebugState()
    {
	printDebug("state: " + state);
    }


    private void _doSetSpeak(String arg)
    {
	if (arg.equals("STOP")) {
	    state = 0;
	    printOut("to @FSM set Speak = STOP");
	    printOut("to @SSM set Speak = STOP");
//	    ready_ssm = false;
//	    ready_fsm = false;
	    _sendAgentSpeakState();
	    _printDebugState();
	} else {
	    if (state != 0) {
		// if speaking, stop automatically
		printOut("to @FSM set Speak = STOP");
		printOut("to @SSM set Speak = STOP");
	    }
	    state = 1;
	    _sendAgentSpeakState();
	    printOut("to @FSM set MouthScale = " + curr_mouth_scale);
	    printOut("to @FSM prop Speak.stat = AutoOutput");
	    printOut("to @SSM prop Speak.stat = AutoOutput");
	    printOut("to @SSM prop Speak.pho = AutoOutput");
	    printOut("to @SSM set Text = " + _getOutputText(arg));
//	    ready_ssm = false;
//	    ready_fsm = false;
	    _printDebugState();
	}
    }


    private void _doSetMoveMouth(String arg)
    {
	Pattern p = Pattern.compile("^scale\\s+(\\S+)\\s+(.*)$");
	Matcher m;
	if (arg.equals("STOP")) {
	    state = 0;
	    printOut( "to @SSM set Speak = STOP");
//	    ready_ssm = false;
//	    ready_fsm = false;
	    _sendAgentSpeakState();
	    _printDebugState();
	} else {
	    state = 3;
	    if ((m = p.matcher(arg)).matches()) {
		printOut( "to @FSM set MouthScale = " + m.group(1));
		printOut( "to @FSM set LipSync.pho = " + m.group(2));
	    } else {
		printOut( "to @FSM set MouthScale = " + curr_mouth_scale);
		printOut( "to @FSM set LipSync.pho = " + arg);
	    }
//	    ready_fsm = false;
	    _sendAgentSpeakState();
	    _printDebugState();
	}
    }
}


/*
  def do_set_mask(arg)
    case arg
    when /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/
      printOut( "to @FS-MCL set Mask = #{$1}"
      printOut( "to @FS-MCL set EmotionNow = #{$2} #{$3}"
      printOut( "to @FS-MCL set RotNow = #{$4} #{$5} #{$6}"
      if self.curr_agent != $1
	self.curr_agent = $1
	printOut( "to @SSM set Speaker = #{curr_speaker}"
      end
      set_emotion $2, $3.to_f
    when /(\S+)\s+(\S+)\s+([0-9\.\+\-]+)/
      if self.curr_agent != $1
	self.curr_agent = $1
	printOut( "to @SSM set Speaker = #{curr_speaker}"
      end
      set_emotion $2, $3.to_f
      printOut( "to @FS-MCL set Mask = #{$1}"
      printOut( "to @FS-MCL set EmotionNow = #{$2} #{$3}"
    when /(\S+)\s+(\S+)/
      if self.curr_agent != $1
	self.curr_agent = $1
	printOut( "to @SSM set Speaker = #{curr_speaker}"
      end
      set_emotion $2
      printOut( "to @FS-MCL set Mask = #{$1}"
      printOut( "to @FS-MCL set EmotionNow = #{$2}"
    when /(\S+)/
      if self.curr_agent != $1
	self.curr_agent = $1
	printOut( "to @SSM set Speaker = #{curr_speaker}"
      end
      printOut( "to @FS-MCL set Mask = #{$1}"
    end
  end


  def set_emotion(type, level=90, duration=0)
    # duration is not used
=begin
    @mutex.synchronize do
      @agents[@curr_agent].set_emotion(type, level)
    end
=end
    self.agents[self.curr_agent].set_emotion(type, level)
  end


  def do_set_emotion(arg)
    printOut( "to @FS-MCL set Emotion = #{arg}"
    case arg
    when /(.+)\s+([0-9\.\+\-]+)\s+([0-9\.\+\-]+)/
      set_emotion($1, $2.to_f, $3.to_f)
    when /(.+)\s+([0-9\.\+\-]+)/
      set_emotion($1, $2.to_f)
    when /(.+)/
      set_emotion($1)
    end
  end


  def set_speak_speed(arg)
    self.agents[self.curr_agent].ssmspeed = arg.to_f
  end
  

  def do_set(slot, arg)
    super
    case slot
    when "Speak" 
      do_set_speak(arg)
    when "MoveMouth" 
      do_set_move_mouth(arg)
    when "SpeakSpeed" 
      set_speak_speed(arg)
    when "AutoMove" 
      printOut( "to @FS-MCL set AutoMove = #{arg}"
    when "AutoGaze" 
      printOut( "to @DIM set AutoGaze = #{arg}"
    when "Mask" 
      do_set_mask(arg)
    when "Emotion" 
      do_set_emotion(arg)
    when "AutoEmotionSpeak" 
      self.auto_emotion_speak = arg.to_i
    end
  end


  def accept_from_state0(mod, str)
  end


  def accept_from_state1(mod, str)
    # waiting responce of "@SSM set Text = value"
    case mod
    when "SSM"
      case str
      when /rep\s+Speak\.pho\s*=\s*(.*)$/
	phones = $1
	phones.gsub!( /\[/, " " )
	phones.gsub!( /\]/, "" )
	# sil 10 k 100 o 85 N 90 n 25 i 60 ch 105 i 50 w 50 a 95 sil 10
	printDebug phones
#	printOut( "to @FSM prop Speak.stat = AutoOutput"
	printOut( "to @FSM set LipSync.pho = #{phones}"
	printOut( "to @FSM inq Speak.stat"
	printDebug "state: #{self.state} speak.pho ready"
      when /rep\s+Speak\.stat\s*=\s*READY\s*$/
	self.ready_ssm = true
	printDebug "state: #{self.state} ready_ssm"
      when /rep\s+Speak\.stat\s*=\s*ERROR\s*$/ 
	self.state = 0
	sendAgentSpeakState
	self.ready_ssm = false
	self.ready_fsm = false
	printDebug "state: #{self.state}"
      end
    when "FSM"
      case str
      when /rep\s+Speak\.stat\s*=\s*READY\s*$/
	self.ready_fsm = true
	printDebug "state: #{self.state} ready_fsm"
      when /rep\s+Speak\.stat\s*=\s*ERROR\s*$/
	self.state = 0
	sendAgentSpeakState
	self.ready_ssm = false
	self.ready_fsm = false
	printDebug "state: #{self.state}"
      end
    end

    if self.ready_fsm && self.ready_ssm
      self.state = 2
      sendAgentSpeakState
      # printOut( "to @SSM set Save = _speech.raw"
      # printOut( "to @SSM set SpeechFile = _speech.raw"
      # $ play -t .sw -x -r 16000 ../../SSM/_speech.raw

#      printOut( "to @SSM set Speak = +100" # for SSMclient.rb
      printOut( "to @SSM set Speak = +0" # 

      printOut( "to @FSM set Speak = + 0"
      printDebug "state: #{self.state} Speak start"
    end
  end


  def accept_from_state2(mod, str)
    #
    if mod == "SSM" && /rep\s+Speak\.stat\s*=\s*IDLE\s*$/ =~ str
      self.ready_ssm = false
      # printDebug "state: #{self.state} ready_ssm = false"

    elsif mod == "FSM" && /rep\s+Speak\.stat\s*=\s*IDLE\s*$/ =~ str
      self.ready_fsm = false
      # printDebug "state: #{self.state} ready_fsm = false"

    end

    if self.ready_fsm == false && self.ready_ssm == false
      self.state = 0 
      printDebug "state: #{self.state} Speak end"
      sendAgentSpeakState
    end
  end


  def accept_from_state3(mod, str)
    if mod == "FSM" && /rep\s+Speak\.stat\s*=\s*READY\s*$/ =~ str
      self.state = 4
      sendAgentSpeakState
      self.ready_ssm = false
      self.ready_fsm = true
      printDebug "state: #{self.state} ready_fsm"
      printOut( "to @FSM set Speak = + 0"
      printDebug "state: #{self.state} Speak start"

    elsif mod == "FSM" && /rep\s+Speak\.stat\s*=\s*ERROR\s*$/ =~ str
      self.state = 0
      sendAgentSpeakState
      self.ready_ssm = false
      self.ready_fsm = false
      printDebug "state: #{self.state}"
    end
  end


  def accept_from_state4(mod, str)
    if mod == "FSM" && /rep\s+Speak\.stat\s*=\s*IDLE\s*$/ =~ str
      self.state = 0 
      printDebug "state: #{self.state} Speak end"
      self.ready_fsm = false
      sendAgentSpeakState
    end
  end


  def accept_from(mod, str)

    #
    # From @XXX set YYY = ZZZ を to @AM-MCL と見なして do_set で処理
    #
    if /^\s*set\s+([^\s=]*)\s*=\s*(.*)$/ =~ str
      do_set $1, $2
      return
    end

    #
    # lipsync
    #
      
    case self.state 
    when 1
      accept_from_state1(mod, str)
    when 2
      accept_from_state2(mod, str)
    when 3
      accept_from_state3(mod, str)
    when 4
      accept_from_state4(mod, str)
    end

  end

  def accept_to(mod, str)
    printOut( "to @MON set SysLogText = #{str}"
  end

end

# ------------------------------

AM_MCL.new.run

# end of file
*/
