/**
 * $Id: GalateaTalkSubModule.java,v 1.7 2008/02/14 02:00:07 nishi Exp $
 */
package galatea.io.plugins;

import galatea.dialog.window.DialogManagerWindow;
import galatea.io.ISenderToDevice;
import galatea.logger.Logger;
import galatea.outitem.AudioOutItem;
import galatea.outitem.OutItem;
import galatea.outitem.VoiceOutItem;
import galatea.submodule.AbstractSubModule;
import galatea.util.Property;
import galatea.util.SubProcess;
import galatea.util.Util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GalateaTalkSubModule 
extends AbstractSubModule
{
	private Logger dbg = new Logger("SSM");
	
	private String speakLen_ = "";
	private String speakUtt_ = "";

	private String errors_ = "";
	private String outputs_ = "";
	private String exception_ = "";
	private String engineExe_ = "gtalk.exe";
	private String engineDir_ = ".";
	private String engineArg_ = "-C ssm-win.conf";
	
	private SubProcess subProcess_;
	private Pattern pSSMSpeakLen = Pattern.compile("rep Speak.len = (.*)$");
	private Pattern pSSMSpeakUtt = Pattern.compile("rep Speak.utt = (.*)$");
	private Pattern pSSMSpeakStat = Pattern.compile("rep Speak.stat = (.*)$");
	private Pattern pToSSM = Pattern.compile("^to @SSM (.*)$");
	
	public GalateaTalkSubModule() {
		super();
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				dbg.print("Shutting down");
				if (subProcess_ != null) {
					subProcess_.sendToStdin("set Run = EXIT");
					subProcess_.destroy();
				}
			}
		});;
	}
	
	public void setTargetRunLevel(int level) {
		if (level == 2) {
			_setup();
			receiver_.receiveRunLevel(2, this);
		}
	}
	
	private void _setup() {
		errors_ = "";
		outputs_ = "";
		exception_ = "";
		engineDir_ = Property.getForPlatformAsStr("GalateaTalk.Dir", "/data/istc-cdrom-2006-10/linux/bin/SSM/gtalk");
		engineExe_ = Property.getForPlatformAsStr("GalateaTalk.Exe", "gtalk");
		engineArg_ = Property.getForPlatformAsStr("GalateaTalk.Arg", "-C ssm.conf");

		subProcess_ = new SubProcess(engineDir_ + "/" + engineExe_ + " " + engineArg_);
		if (subProcess_ == null) {
			logger_.fatalError(subProcess_.getError());
			return;
		}
		if (subProcess_.run(engineDir_) == false) {
			errors_ = subProcess_.getError();
			logger_.fatalError(subProcess_.getError());
			return;
		}
		exception_ = "";
		errors_ = "";
		outputs_ = "";
		dbg.print("GalateaTalkSubModule setup done");
	}
	
	public void doTimerTask() {
		// dbg.print("doTimerTask");
		while (true) {
			String er = subProcess_.receiveFromStderrNB();
			if (er.length() == 0) 
				break;
			dbg.print("E: " + er);
		}
		while (true) {
			String str = subProcess_.receiveFromStdoutNB();
			if (str.length() == 0) 
				break;
			dbg.print("O: " + str);
			Matcher mSSMSpeakLen = pSSMSpeakLen.matcher(str);
			if (mSSMSpeakLen.matches()) {
				speakLen_ = mSSMSpeakLen.group(1);
				break;
			}
			Matcher mSSMSpeakUtt = pSSMSpeakUtt.matcher(str);
			if (mSSMSpeakUtt.matches()) {
				speakUtt_ = mSSMSpeakUtt.group(1);
				break;
			}
			Matcher mSSMSpeakStat = pSSMSpeakStat.matcher(str);
			if (mSSMSpeakStat.matches()) {
				String g1 = mSSMSpeakStat.group(1);
				if ( g1.equals("IDLE") ) {
					dbg.print("checkFromSSM IDLE");
					receiver_.receiveOutputReady("voice", speakLen_ + " " +speakUtt_);
					logger_.outputVoiceStarted("");
					break;
				} else if ( g1.equals("ERROR") ) {
					dbg.print("checkFromSSM ERROR");
					receiver_.receiveOutputReady("voice", "ERROR");
					break;
				} else if ( g1.equals("SPEAKING") ) {
					dbg.print("checkFromSSM SPEAKING");
					receiver_.receiveOutputBusy("voice", "");
					break;
				} else if ( g1.equals("PROCESSING") ) { // 
					dbg.print("checkFromSSM PROCESSING");
					break;
				} else if ( g1.equals("READY") ) { // 
					dbg.print("checkFromSSM READY");
					subProcess_.sendToStdin("set Speak = NOW");
					break;
				}
			}
		}
	}
	
	public boolean filterOutputNative(String str) {
		Matcher m = pToSSM.matcher(str);
		if (m.matches()) {
			subProcess_.sendToStdin(m.group(1));
			return true;
		}
		return false;
	}
	
	public boolean startOutput(OutItem item) {
		if (!(item instanceof VoiceOutItem)) return false;
		String str = ((VoiceOutItem)item).getArg();
		if (str.length() == 0) {
			dbg.print("doOutput() speak empty *** ignored ***");
			return false;
		}
		subProcess_.sendToStdin("set Text = " + str);
		logger_.outputVoiceStarted(str);
		dbg.print("start(" + str +")");
		return true;
	}

	public boolean stopOutput(OutItem item) {
		if (item instanceof VoiceOutItem) {
			subProcess_.sendToStdin("set Speak = STOP");
			logger_.outputVoiceStarted("");
			return true;
		}
		return false;
	}

}
