package com.app.downloadstream1;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import android.util.Log;

public class TailStream extends InputStream {
	public static final String TAG = "TailStream";
	
	protected String mPath;
	protected long mLength = -1;
	private FileChannel mChannel;
	
	private final DownloadManager.Download mDownload;

	private long mRemaining = 0;
	
	public TailStream(DownloadManager.Download d) {
		this.mDownload = d;
		mPath = d.getDestination().getAbsolutePath();
	}
	
	public TailStream newInstance() {
		return new TailStream(mDownload);
	}
	
	public void open() throws IOException
	{
		mChannel = (new RandomAccessFile(mPath, "r")).getChannel();
		Log.i(TAG, "Waiting for connection...");			
		mDownload.waitForResponse();
		Log.i(TAG, "Got it, length=" + mDownload.getContentLength());
		setLength(mDownload.getContentLength());
	}
	
	public void setLength(long length) {
		this.mLength = length;
		this.mRemaining = length;
	}
	
	public void close() {
		try {
			mChannel.close();
		}catch(IOException e) {
			Log.e(TAG, "error during channel closing: " + e.toString());
		}
		mChannel = null;
	}
	
	public long size() {
		if (mLength < 0)
			throw new IllegalStateException("Length not set after open()");
		
		return mLength;
	}
	
	@Override
	public int read() throws IOException {
		// TODO Auto-generated method stub
		throw new RuntimeException("Don't invoke this method.");
	}
	
	public void seek(long pos) throws IOException
	{
		mChannel.position(pos);
		mRemaining = mLength - pos;
	}
	
	public void waitForData() throws IOException {
		long pos = mLength - mRemaining;
		Thread self = Thread.currentThread();
		while(pos > mChannel.size() && self.isInterrupted() == false) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				throw new EOFException("Aborted stream");
			}
		}
		if (self.isInterrupted() == true)
			throw new EOFException("Aborted stream");
	}
	
	public int read(byte[] b, int offs, int len) throws IOException{
		if (mRemaining == 0)
			return -1; // means the end of the file

		if (len > mRemaining)
			len = (int)mRemaining;

		ByteBuffer buf = ByteBuffer.wrap(b, offs, len);

		int n = mChannel.read(buf);
		assert mRemaining >= n;

		if (n >= 0)
		{
			mRemaining -= n;
			return n;
		}
		else
		{
			waitForData();

			/* Next read will find data... */
			return 0;
		}
	}
	
	
}
