/**
 * $Id: SRMSubModule.java,v 1.6 2008/02/14 02:59:34 nishi Exp $
 */
package galatea.io.wrapper;

import galatea.dialog.InterpretedEvent;
import galatea.dialog.window.DialogManagerWindow;
import galatea.io.ISenderToDevice;
import galatea.logger.Logger;
import galatea.recogman.RecogInterpreter;
import galatea.recogman.RecogInterpreterListener;
import galatea.submodule.AbstractSubModule;
import galatea.util.Property;
import galatea.util.Util;

import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SRMSubModule 
extends AbstractSubModule
implements RecogInterpreterListener
{
	private Logger dbg = new Logger("SRM", 0);
	private RecogInterpreter parser_ = new RecogInterpreter();
	
	private String  xmlContent_ = "";
	private boolean debugMode_ = true;
	
	private Pattern patSrmTell_ = Pattern.compile("^From @SRM tell (.*)$");
	private boolean insideMultiLine_ = false;

	private boolean useSIM_ = false; // 外部 SIM プロセスを使うか？
	private boolean useDIM_ = false;
	
	public SRMSubModule() {
		useDIM_ = Property.getAsBoolean("DM.UseDIM", true);
		useSIM_ = Property.getAsBoolean("DM.UseSIM", false);
		debugMode_ = Property.getAsBoolean("Debug.RecogMan", false);
		parser_.setListener(this);
	}
	
	private void _debugPrint(String str) {
		if (debugMode_) {
			dbg.print(str);
		}
	}
	
	public void setDialogName(String s) {
		parser_.setDialogName(s);
	}
	
	public void setSlotAlias(String s) {
		if (s.equals("RESET")) {
			parser_.resetSlotAlias();
		} else {
			parser_.setSlotAlias(s);
		}
	}
	
	private void _sendRecogState(int s) {
		if (useDIM_ ) {
			sender_.send("to @DIM set RecogState = " + s);
		}
	}
	
	private void _sendUserSpeakState(int s) {
		if (useDIM_) {
			sender_.send("to @DIM set UserSpeakState = " + s);
		}
	}
	
	private void _fromSRMtell(String s) {
		_debugPrint("[" + xmlContent_ + "] [" + s + "]");
		
		if (s.startsWith("grammar ")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("ModuleStart")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("ModuleExit")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("<STARTPROC/>")) {
			logger_.inputEventReceived(s);
			receiver_.receiveRunLevel(2, this);
			return;
		}
		if (s.startsWith("<GMM ")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("<INPUT ")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("<INPUTPARAM ")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("<REJECTED ")) {
			logger_.inputEventReceived(s);
			return;
		}
		if (s.startsWith("<GRAMMAR ")) {
			logger_.inputEventReceived(s);
			return;
		}
		
		/* 
		 * <INPUT STATUS="LISTEN" TIME="1164166313"/>
		 * <INPUT STATUS="STARTREC" TIME="1164166322"/>
		 * <INPUT STATUS="ENDREC" TIME="1164166323"/>
		 * <INPUTPARAM FRAMES="146" MSEC="1460"/>
		 * <RECOGOUT>  
		 * <SHYPO RANK="1" SCORE="-3783.279297" GRAM="2">    
		 * <WHYPO WORD="silB:" CLASSID="0" PHONE="silB" CM="1.000"/>    
		 * <WHYPO WORD="新大阪@source=新大阪" CLASSID="7" PHONE="sh i N o: s a k a" CM="0.999"/>    
		 * <WHYPO WORD="silE:" CLASSID="1" PHONE="silE" CM="1.000"/>  
		 * </SHYPO>
		 * </RECOGOUT>
		 */
		
		if (xmlContent_.length() > 0 || s.startsWith("<")) {
			xmlContent_ += s;
			// validation ?? 
			if (/* xmlContent_.endsWith("/>") || */ 
					xmlContent_.endsWith("</RECOGOUT>") 
					|| xmlContent_.endsWith("</GRAMINFO>") 
			) {
				try {
					parser_.receiveRecogMessage(xmlContent_);
				} catch (Exception e) {
					_debugPrint(e.toString());
				}
				xmlContent_ = "";
			}
		}
	}
	
	public void recogListenStarted() {
		_sendUserSpeakState(0);
	}
	
	public void recogRecordStarted() {
		_sendUserSpeakState(1);
	}
	
	public void recogRecordFinished() {
		_sendUserSpeakState(0);
	}
	
	public void recogPass1Finished() {
	}
	
	public void recogPass2Finished() {
		String script = parser_.getScript();
		String text = parser_.getText();
		String xmlevent = "<ev src=\"SRM\" type=\"INPUT\"><interpreted>"
		+"<text>" + text + "</text>"
		+"<script>" + script + "</script></interpreted></ev>";
		InterpretedEvent ev = InterpretedEvent.newInstance(xmlevent);
		receiver_.receiveInterpreted(ev);
		logger_.inputEventReceived(xmlevent);
	}
	
	public void recogFailed() {
	}
	
	public void recogException(Exception e, String str) {
		_debugPrint("recogException(" + str +") " + e.toString());
	}
	
	public boolean receiveFromDevice(String str) {
		if (useSIM_) {
			Pattern pSIMResult = Pattern.compile("From @SIM tell 300 (.*)$");
			Matcher mSIMResult = pSIMResult.matcher(str);
			if (mSIMResult.matches()) {
				String xmlevent = mSIMResult.group(1);
				dbg.print("tell 300 " + xmlevent);
				InterpretedEvent ev = InterpretedEvent.newInstance(xmlevent);
				receiver_.receiveInterpreted(ev);
				logger_.inputEventReceived(xmlevent);
				return true;
			}
		}
		if (str.startsWith("From @SRM ")) {
			if (insideMultiLine_) {
				if (str.startsWith("From @SRM EOM")) {
					insideMultiLine_ = false;
					_debugPrint("multiLine End");
				} else {
					String s = str.replaceAll("From @SRM ", "");
					_fromSRMtell(s);
				}
			} else if (str.startsWith("From @SRM tell << EOM")) {
				insideMultiLine_ = true;
				_debugPrint("multiLine Start ");
			} else {
				_fromSRMtell(str.replaceAll("From @SRM tell ",""));
			}
			return true;
		}
		return false;
	}
	
	public boolean filterOutputNative(String str) {
		if (!useSIM_) {
			String s;
			if ((s = Util.getFirstGroup("to @SIM set DialogName = (.*)$", str)) != null) {
				setDialogName(s);
				return true;
			} else if ((s = Util.getFirstGroup("to @SIM set SlotAlias = (.*)$", str)) != null) {
				setSlotAlias(s);
				return true;
			}
		}
		if (str.startsWith("to @SRM set Grammar =")) {
			String doc = getGrammarForDisplay(str);
			logger_.grammarFileUpdated(doc);
		}
		return false;
	}
	
	public String getGrammarForDisplay(String str) {
		String s;
		if ((s = Util.getFirstGroup("to @SRM set Grammar = (.*)$", str)) != null) {
			String file = s.replaceAll(".dfa", "");
			Charset charset_ = Util.getSystemDefaultCharset();
			String XML_ENCODING = "EUC-JP";
			Charset xmlCharset_ = Charset.forName(XML_ENCODING);
			try {
				String s1 = Util.loadFromFile(file + ".voca", charset_);
				String s2 = Util.loadFromFile(file + ".grammar", charset_);
				String s3 = Util.loadFromFile(file + ".xml", xmlCharset_);
				return str 
						+ "\n\n[voca]\n" + s1 
						+ "\n\n[grammar]\n" + s2 
						+ (s3 != null ? "\n\n[xml]\n" + s3 : "");
			} catch (Exception e) {
				return str + "\n" + file + "\n" + e.toString();
			}
		}
		return "";
	}
	
	public void setTargetRunLevel(int level) {
		if (level == 2) {
			sender_.send("to @SRM set Run = INIT");
			sender_.send("to @SRM set Run = START");
		}
		this.receiver_.receiveRunLevel(level, this);
	}
	
} 

