package unileipzig.isys.neuronviz.kernel;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;

/**
 * Class DataStreamer
 * 
 */
abstract public class DataStreamer implements Runnable
{
	protected Vector listeners = new Vector();
	protected boolean receiveEnabled = true;
	protected boolean threadRunning = false;
	protected int threadPause = 50;
	protected int streamingMode;
	protected int endOfDescription = 0;
	protected int actualLine = 0;
	protected int notifyIntervall = 1;
	
	public final static int FILE_MODE = 1;
	public final static int PIPE_MODE = 2;
	
	protected BufferedReader dataReader = null;

	/**
	 * 
	 * @param listener
	 * @return
	 */
	public void addDataListener(DataListener listener)
	{
		listeners.add(listener);
		listener.streamingMode(streamingMode);
	}

	/**
	 * 
	 * @param listener
	 * @return
	 */
	public void removeDataListener(DataListener listener)
	{
		listeners.remove(listener);
	}

	/**
	 * 
	 * @param event
	 * @return
	 */
	protected synchronized void notifyData(DataEvent event)
	{
		for (int i = 0; i < listeners.size(); i++)
		{
			((DataListener) (listeners.get(i))).dataReceived(event);
		}
	}

	public void run()
	{
		// recieve data as long as receiver is enabled
		while (receiveEnabled)
		{
			threadRunning = true;
			try
			{
				if(!readDataLine()) Thread.sleep(20);
				
				Thread.sleep(this.threadPause);
			} catch (Exception e)
			{
				System.out.println("Error while receiving data: " + e.getMessage());
			}
		}
		threadRunning = false;
	}
	
	public void startStreaming(int speed)
	{
		this.threadPause = speed;
		
		if(!threadRunning)
		{
			receiveEnabled = true;
			(new Thread(this)).start();
		}
	}
	
	public void stopStreaming()
	{
		receiveEnabled = false;
	}

	public void setInputStream(InputStream in)
	{
		dataReader = new BufferedReader(new InputStreamReader(in));
		actualLine = 0;
	}

	public boolean isRunning()
	{
		return threadRunning;
	}
	
	/**
	 * reads a line from the stream and throws a DataEvent
	 * @return
	 */
	public boolean readDataLine()
	{
		boolean dataRead = false;

		try
		{
			if (dataReader.ready())
			{
				String s = dataReader.readLine();
				dataRead = true;
				if (++actualLine % notifyIntervall == 0)
					notifyData(new DataEvent(this, s));
			}
		} catch (Exception e)
		{
			System.out.println("Error while reading data line: " + e.getMessage());
		}
		
		return dataRead;
	}

	public int getStreamingMode()
	{
		return streamingMode;
	}

	public void setStreamingMode(int streamingMode)
	{
		this.streamingMode = streamingMode;
	}
	
	public void setEndOfDescription(int eod)
	{
		this.endOfDescription = eod;
	}

	public int getEndOfDescription()
	{
		return endOfDescription;
	}

	public int getActualLine()
	{
		return actualLine;
	}

	public void setThreadPause(int threadPause)
	{
		this.threadPause = threadPause;
	}	
}
