package org.afplib.io;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.afplib.Data;
import org.afplib.base.SF;

public class AfpInputStream extends FilterInputStream {

	StructuredFieldFactory factory = new StructuredFieldFactory();
	byte[] data = new byte[32768];
	int length;
	
	int number = 0;
	long offset = 0;
	
	public AfpInputStream(InputStream in) {
		super(in);
	}

	/**
	 * Reads a new structured field from the input stream.
	 * This method is not thread-safe!
	 * 
	 * @return structured field or null if end of input.
	 * @throws IOException
	 */
	public SF readStructuredField() throws IOException {
		
		int buf;
		int leadingLength = 0;
		
		long thisOffset = offset;

		do {
			buf = read(); offset++;
			leadingLength++;
		} while((buf & 0xff) != 0x5a && buf != -1 && leadingLength < 5);
		
		if(buf == -1 && leadingLength > 1)
			throw new IOException("found trailing garbage at the end of file.");
		
		if(buf == -1)
			return null;
		
		if((buf & 0xff) != 0x5a)
			throw new IOException("cannot find 5a magic byte");
		data[0] = (byte) (buf & 0xff);
		
		buf = read(); offset++;
		if(buf == -1)
			throw new IOException("premature end of file.");
		data[1] = (byte) (buf & 0xff);

		length = (byte) buf << 8;

		buf = read(); offset++;
		if(buf == -1)
			throw new IOException("premature end of file.");
		data[2] = (byte) (buf & 0xff);

		length |= (byte) buf & 0xff;
		
		length -= 2;
		
		if(length > data.length)
			throw new IOException("length of structured field is too large: "+length);
				
		int read = read(data, 3, length);
		offset += read;
		
		if(read < length)
			throw new IOException("premature end of file.");
		
		SF sf = factory.sf(data, 0, getLength() + 2);
		sf.setLength(length + 3);
		sf.setOffset(thisOffset);
		sf.setNumber(number++);
		
		return sf;
	}
	
	/**
	 * current position in the input stream
	 * 
	 * @return position
	 */
	public long getCurrentOffset() {
		return offset;
	}
	
	/**
	 * returns a copy of the last read buffer that
	 * contained the previous structured field.
	 * 
	 * @return copy of internal buffer
	 */
	public byte[] getLastReadBuffer() {
		byte[] result = new byte[length + 3];
		System.arraycopy(data, 0, result, 0, length + 3);
		return result;
	}
	
	private int getLength() {
		int result = length;
		
		if((data[6] & 0x08) == 0x08) { // padding
			int padding = 0;
			if(data[data.length - 1] == 0) {
				padding = Data.toUnsigned(data, data.length-3, data.length-2);
			} else {
				padding = Data.toUnsigned(data, data.length-1, data.length-1);
			}
			result -= padding;
		}
		return result;
	}

	
}

@@ -363,18 +363,48 @@
 et = 0;%0A
+%09int leadingLengthBytes = -1;%0A
 %09%0A
-
 %09public 
@@ -710,33 +710,8 @@
 uf;%0A
-%09%09int leadingLength = 0;%0A
 %09%09%0A%09
@@ -742,15 +742,190 @@
 t;%0A%0A
+%09%09if(leadingLengthBytes == -1) %7B%0A%09%09%09// we haven't tested for mvs download leading length bytes%0A%09%09%09// we don't need them and don't want to see them%0A%09%09%09int leadingLength = 0;%0A%09
 %09%09do %7B%0A
+%09
 %09%09%09b
@@ -947,16 +947,17 @@
 fset++;%0A
+%09
 %09%09%09leadi
@@ -970,16 +970,17 @@
 th++;%0A%09%09
+%09
 %7D while(
@@ -1034,25 +1034,74 @@
 gth %3C 5);%0A%09%09
+%09
 %0A
+%09%09%09leadingLengthBytes = leadingLength-1;%0A%09%09%09%0A//%09
 %09%09if(buf == 
@@ -1125,16 +1125,19 @@
 th %3E 1)%0A
+//%09
 %09%09%09throw
@@ -1196,24 +1196,146 @@
 of file.%22);%0A
+%09%09%7D else %7B%0A%09%09%09if(leadingLengthBytes %3E 0) read(data, 0, leadingLengthBytes); // just throw away those%0A%09%09%09buf = read();%0A%09%09%7D%0A
 %09%09%0A%09%09if(buf 

fix for files with preceding host length bytes