package jp.hasc.hasctool.core.runtime.filter;

import java.util.concurrent.TimeUnit;

import jp.hasc.hasctool.core.data.SignalMessage;
import jp.hasc.hasctool.core.messaging.MessageConnector;
import jp.hasc.hasctool.core.messaging.MessageProcessor;
import jp.hasc.hasctool.core.messaging.MessageQueue;
import jp.hasc.hasctool.core.runtime.AbstractTask;
import jp.hasc.hasctool.core.runtime.RuntimeContext;
import jp.hasc.hasctool.core.runtime.annotation.PortInfo;
import jp.hasc.hasctool.core.runtime.annotation.RuntimeBeanInfo;

/**
 * SignalMessageのtimeに合わせて、適宜Thread.sleep()して出力するフィルタです。
 * 一括出力されるSignalMessageを、実時間で出力したい場合に使います。
 * @author iwasaki
 */
@RuntimeBeanInfo(
		inputPorts = { @PortInfo(name = "inputPort", classes = {SignalMessage.class}) },
		outputPorts = { @PortInfo(name = "outputPort", classes = {SignalMessage.class}) }
)
public class SleepFilter extends AbstractTask {
	
	@Override
	public void setup(RuntimeContext context) {
		super.setup(context);
		//
		inputPort_=getRuntimeContext().createDefaultMessageQueue();
	}

	private MessageQueue inputPort_;
	private MessageConnector outputPort_ = new MessageConnector();
	
	public MessageProcessor getInputPort() { return inputPort_; }
	public MessageConnector getOutputPort() { return outputPort_; }
	
	protected void outputMessage(Object message) throws InterruptedException {
		getOutputPort().processMessage(message);
	}
	
	/**
	 * n倍の時間をかけて再生
	 */
	private double timeScale_=1.0;

	public double getTimeScale() {
		return timeScale_;
	}

	public void setTimeScale(double timeScale) {
		timeScale_ = timeScale;
	}
	@Override
	protected void run() throws InterruptedException {
		boolean first=true, ended=false;
		long sigStart=0;
		long hwStart=0;
		while(!isShutdown() && !ended) {
			Object obj=inputPort_.readMessage();
			if (obj instanceof SignalMessage) {
				SignalMessage sig=(SignalMessage)obj;
				long now = System.currentTimeMillis();
				if (first) {
					first=false;
					sigStart=sig.getTime();
					hwStart=now;
				}else{
					long sigT=(long)((sig.getTime()-sigStart)*timeScale_);
					long hwT=SignalMessage.TIME_UNIT.convert(now-hwStart,TimeUnit.MILLISECONDS);
					long dt=sigT-hwT;
					// sleep!
					if (dt>0) Thread.sleep(TimeUnit.MILLISECONDS.convert(dt,SignalMessage.TIME_UNIT));
				}
			}else if (obj==SignalMessage.END) {
				ended=true;
			}
			//
			outputMessage(obj);
		}
	}
}
