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

import java.util.concurrent.TimeUnit;

import jp.hasc.hasctool.core.data.SignalMessage;
import jp.hasc.hasctool.core.data.VectorSignalMessage;
import jp.hasc.hasctool.core.data.VectorSignalMessages;
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.filter.interpolator.PeriodicSignalSampler;
import jp.hasc.hasctool.core.runtime.filter.interpolator.VectorPeriodicSignalSampler;

/**
 * ベクトルの積分器です。
 * timeStep毎にy'(time)を入力し、y(time+timeStep)を出力します。
 * <pre>
 * y(time + timeStep) = y(time) + y'(time) * dt
 * dt = timeStep / unitTime（デフォルト1秒）
 * </pre>
 * @author iwasaki
 */
public class VectorIntegrator extends AbstractTask {
	
	private VectorSignalMessage initialValue_;
	private long timeStep_;
	private long unitTime_=SignalMessage.TIME_UNIT.convert(1, TimeUnit.SECONDS);
	
	private PeriodicSignalSampler inputSampler_;
	private MessageQueue inputQueue_;
	private MessageConnector outputPort_ = new MessageConnector();
	
	public MessageProcessor getInputPort() { return inputSampler_; }
	public MessageConnector getOutputPort() { return outputPort_; }
	
	protected void outputMessage(Object message) throws InterruptedException {
		getOutputPort().processMessage(message);
	}
	
	@Override
	public void setup(RuntimeContext context) {
		super.setup(context);
		//
		inputQueue_=getRuntimeContext().createDefaultMessageQueue();
		//
		inputSampler_=new VectorPeriodicSignalSampler();
		inputSampler_.setTimeStep(timeStep_);
		inputSampler_.setInitialTime(initialValue_.getTime());
		inputSampler_.setup(context);
		//
		inputSampler_.getOutputPort().connect(inputQueue_);
	}
	
	@Override
	protected void run() throws InterruptedException {
		outputMessage(SignalMessage.BEGIN);
		outputMessage(initialValue_);
		//
		long time=initialValue_.getTime();
		double[] sumValue=new double[initialValue_.getVectorSize()];
		for(int i=0;i<sumValue.length;++i) sumValue[i]=initialValue_.getVectorElement(i);
		double dt=(double)timeStep_ / unitTime_;
		//
		while(!isShutdown()) {
			Object message = inputQueue_.readMessage();
			if (message instanceof VectorSignalMessage) {
				// 入力
				VectorSignalMessage vec = (VectorSignalMessage) message;
				if (time!=vec.getTime()) throw new RuntimeException();
				// 加算
				time+=timeStep_;
				for(int i=0;i<sumValue.length;++i) {
					sumValue[i] += vec.getVectorElement(i) * dt;
				}
				//　出力
				outputMessage(VectorSignalMessages.create(time, sumValue, true));
				
			}else if (message==SignalMessage.END) {
				break;
			}else{
				// ignore
			}
		}
		// end
		outputMessage(SignalMessage.END);
	}
	
	public long getUnitTime() {
		return unitTime_;
	}
	
	public void setUnitTime(long unitTime) {
		unitTime_ = unitTime;
	}
	public VectorSignalMessage getInitialValue() {
		return initialValue_;
	}
	public void setInitialValue(VectorSignalMessage initialValue) {
		initialValue_ = initialValue;
	}
	public long getTimeStep() {
		return timeStep_;
	}
	public void setTimeStep(long timeStep) {
		timeStep_ = timeStep;
	}
}
