package com.ociweb.gl.impl;

import com.ociweb.pronghorn.pipe.DataInputBlobReader;
import com.ociweb.pronghorn.pipe.DataOutputBlobWriter;
import com.ociweb.pronghorn.pipe.MessageSchema;
import com.ociweb.pronghorn.pipe.Pipe;
import com.ociweb.pronghorn.util.TrieParserReader;

public class PayloadReader<S extends MessageSchema<S>> extends DataInputBlobReader<S> {

	private TrieParserReader reader = new TrieParserReader(true);
	private int limit = -1;
	
	public PayloadReader(Pipe<S> pipe) {
        super(pipe);
    }
	

    protected static <S extends MessageSchema<S>> void checkLimit(PayloadReader<S> that, int min) {
    	if ( (that.position+min) > that.limit ) {
    		throw new RuntimeException("Read attempted beyond the end of the field data");
    	}
    }
   
	
	@Override
	public int openHighLevelAPIField(int loc) {		
		int len = super.openHighLevelAPIField(loc);
		limit = len + position;
		return len;
	}
	
	@Override
	public int openLowLevelAPIField() {		
		int len = super.openLowLevelAPIField();
		limit = len + position;
		return len;
	}

	private int fieldIdx(long fieldId) {
		return (int)fieldId & 0xFFFF;
	}

	protected int fieldType(long fieldId) {
		return (((int)fieldId)>>16) & 0xFF;
	}

	protected int computePosition(long fieldId) {
		assert(fieldId>=0) : "check field name, it does not match any found field";
		//jump to end and index backwards to find data position
		int result = readFromEndLastInt(fieldIdx(fieldId));	
		assert(result<available()) : "index of "+result+" is out of limit "+available()+" for field id "+fieldId+" at index "+fieldIdx(fieldId);
		return result;
	}
	
	protected int computePositionSecond(long fieldId) {
		assert(fieldId>=0) : "check field name, it does not match any found field";
		//jump to end and index backwards to find data position
		return readFromEndLastInt(1+fieldIdx(fieldId));		
	}


	/////////////////////

	@Override
	public int read(byte[] b) {
		checkLimit(this,2);
		return super.read(b);
	}


	@Override
	public int read(byte[] b, int off, int len) {
		checkLimit(this,2);//not len because read will read less
		return super.read(b, off, len);
	}


	@Override
	public void readFully(byte[] b) {
		checkLimit(this,2);
		super.readFully(b);
	}


	@Override
	public void readFully(byte[] b, int off, int len) {
		checkLimit(this,2);//not len because read will read less
		super.readFully(b, off, len);
	}


	@Override
	public int skipBytes(int n) {
		checkLimit(this,n);
		return super.skipBytes(n);
	}


	@Override
	public boolean readBoolean() {
		checkLimit(this,1);
		return super.readBoolean();
	}


	@Override
	public byte readByte() {
		checkLimit(this,1);
		return super.readByte();
	}


	@Override
	public int readUnsignedByte() {
		checkLimit(this,1);
		return super.readUnsignedByte();
	}


	@Override
	public short readShort() {
		checkLimit(this,2);
		return super.readShort();
	}


	@Override
	public int readUnsignedShort() {
		checkLimit(this,2);
		return super.readUnsignedShort();
	}


	@Override
	public char readChar() {
		checkLimit(this,1);
		return super.readChar();
	}


	@Override
	public int readInt() {
		checkLimit(this,4);
		return super.readInt();
	}


	@Override
	public long readLong() {
		checkLimit(this,8);
		return super.readLong();
	}


	@Override
	public float readFloat() {
		checkLimit(this,4);
		return super.readFloat();
	}


	@Override
	public double readDouble() {
		checkLimit(this,8);
		return super.readDouble();
	}


	@Override
	public int read() {
		checkLimit(this,1);
		return super.read();
	}


	@Override
	public String readLine() {
		checkLimit(this,1);
		return super.readLine();
	}


	@Override
	public String readUTF() {
		checkLimit(this,2);
		return super.readUTF();
	}


	@Override
	public <A extends Appendable> A readUTF(A target) {
		checkLimit(this,2);
		return super.readUTF(target);
	}


	@Override
	public Object readObject() {
		checkLimit(this,1);
		return super.readObject();
	}


	@Override
	public <T extends MessageSchema<T>> void readInto(DataOutputBlobWriter<T> writer, int length) {
		checkLimit(this,length);
		super.readInto(writer, length);
	}


	@Override
	public <A extends Appendable> A readPackedChars(A target) {
		checkLimit(this,1);
		return super.readPackedChars(target);
	}


	@Override
	public long readPackedLong() {
		checkLimit(this,1);
		return super.readPackedLong();
	}


	@Override
	public int readPackedInt() {
		checkLimit(this,1);
		return super.readPackedInt();
	}


	@Override
	public double readDecimalAsDouble() {
		checkLimit(this,2);
		return super.readDecimalAsDouble();
	}


	@Override
	public long readDecimalAsLong() {
		checkLimit(this,2);
		return super.readDecimalAsLong();
	}


	@Override
	public short readPackedShort() {
		checkLimit(this,1);
		return super.readPackedShort();
	}

	

}

@@ -622,16 +622,125 @@
  %7B%0A    %09
+%0A    %09//TODO: this bounds checker is broken, open does not set limit right since static is used%0A    %09%0A    %09//
 if ( (th
@@ -778,16 +778,18 @@
  %7B%0A    %09
+//
 %09throw n
@@ -865,16 +865,18 @@
 );%0A    %09
+//
 %7D%0A    %7D%0A
@@ -1512,20 +1512,14 @@
 n%0A%09%09
-int result =
+return
  rea
@@ -1559,163 +1559,8 @@
 );%09%0A
-%09%09assert(result%3Cavailable()) : %22index of %22+result+%22 is out of limit %22+available()+%22 for field id %22+fieldId+%22 at index %22+fieldIdx(fieldId);%0A%09%09return result;
 %0A%09%7D%0A

disable checks on limit since math is wrong at the moment