package dangerzone;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

//There has got to be a better way.
//read a byte at a time? Really???
//Let's do stream input in the most inefficient way possible...
//FIXME TODO - write a callout to C to do real I/O
//FIXME TODO - switch to SocketChannels? Faster???


public class NetworkInputBuffer {
	int currentlen = 0;
	ByteBuffer b = null;
	int maxlen = 0;
	InputStream datain = null;
	boolean error_happened = false;
	
	//howbig just needs to be a a few k. its all byte-oriented so bigger is not better...
	public NetworkInputBuffer(InputStream inout, int howbig){
		datain = inout;
		b = ByteBuffer.allocate(howbig+200);	//plus a little extra			
		maxlen = howbig;
	}
	
	public void close(){
		
	}
	
	public boolean errorOccurred(){
		return error_happened;
	}
	
	//read as much as possible...
	private void getAtLeast(int min){
		if(currentlen >= min)return;
		if(error_happened){
			b.rewind();
			b.position(0);
			return;
		}
		int newval, i;
		int maxread = 0;
				
		//copy current buffer down, then reset position and read more
		if(currentlen > 0){
			byte b1[] = b.array();			
			for(i=0;i<currentlen;i++){
				b1[i] = b.get();
			}
		}
		b.position(currentlen);

		//read as many as we can, maybe... .available is an "estimate"...
		//it also doesn't even return an error on a closed connection...
		try {
			maxread = datain.available();
			//System.out.printf("available = %d\n", maxread);
		} catch (IOException e1) {
			error_happened = true;
			if(DangerZone.start_client)DangerZone.gameover = 1;
			b.rewind();
			b.position(0);
			return;
		}
		if(maxread < min-currentlen)maxread = min-currentlen;
		if(maxread > maxlen-currentlen)maxread = maxlen-currentlen;

		for(i=0;i<maxread;i++){
			try {
				newval = datain.read(); //read one byte at a time, because, its &%$#*&^)*&^#@! java... 
				b.put((byte)newval);
				currentlen++;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				//e.printStackTrace();
				error_happened = true;
				if(DangerZone.start_client)DangerZone.gameover = 1;
				break;
			}
		}
		b.rewind();
		b.position(0);

	}
			
	
	
	public int readInt(){
		int retval = 0;
		getAtLeast(4);
		if(error_happened)return retval;
		retval = b.getInt();
		currentlen -= 4;
		return retval;
	}
	
	public short readShort(){
		short retval = 0;
		getAtLeast(2);
		if(error_happened)return retval;
		retval = b.getShort();
		currentlen -= 2;
		return retval;
	}
	
	public byte readByte(){
		byte retval = 0;
		getAtLeast(1);
		if(error_happened)return retval;
		retval = b.get();
		currentlen -= 1;
		return retval;
	}
	
	public float readFloat(){
		float retval = 0;
		getAtLeast(4);
		if(error_happened)return retval;
		retval = b.getFloat();
		currentlen -= 4;
		return retval;
	}	
	
	public double readDouble(){
		double retval = 0;
		getAtLeast(8);
		if(error_happened)return retval;
		retval = b.getDouble();
		currentlen -= 8;
		return retval;
	}	
	
	public long readLong(){
		long retval = 0;
		getAtLeast(8);
		if(error_happened)return retval;
		retval = b.getLong();
		currentlen -= 8;
		return retval;
	}	

	
	public String readString(){
		if(error_happened)return null;
		byte [] stringbytes = readByteArray();
		if(stringbytes == null)return null;
		String s = "";
		for(int i=0;i<stringbytes.length;i++){
			s += (char)stringbytes[i];
		}

		return s;
	}
	
	public short [] readShortArray(){
		int len = readInt();
		if(len <= 0)return null;
		
		short [] sh = new short[len];
		
		for(int i=0;i<len;i++){
			sh[i] = readShort();
		}
		return sh;
	}
	
	public byte [] readByteArray(){
		int len = readInt();
		if(len <= 0)return null;
		
		byte [] sh = new byte[len];
		
		//System.out.printf("readByteArray len = %d\n", len);
		getAtLeast(len);
		if(error_happened)return null;
		for(int i=0;i<len;i++){
			sh[i] = b.get();
			currentlen--;
		}
		return sh;
	}

}
