package org.wikiwebserver.handler.http;

import java.io.IOException;
import java.io.InputStream;


public class HTTPPostReader extends InputStream {
	
	private HTTPInputStream in;
	private String textData;
	private FormData formData;
	
	private final int postLength;
	private final String postType;
	
	private volatile int numBytesRead = 0;

	public HTTPPostReader(HTTPInputStream in, int length, String type) throws HTTPException {
		this.in = in;
        this.postLength = length;
        this.postType = type;
	}

	public int read() throws IOException {

		if (numBytesRead == postLength) return -1; // End of posted data
		int i = in.read();
		if (i != -1) incrementNumBytesRead(1);
		return i;
	}
	
	public void close() throws IOException {
		// Skip over remaining posted data
		in.skipBytes(remaining());
        numBytesRead = postLength;		
		// The raw stream may be reused for subsequent HTTP requests
	}	
	
	public int read(byte[] buffer) throws IOException {
		return read(buffer, 0, buffer.length);
	}
	
	public int read(byte[] buffer, int off, int len) throws IOException {
		
		if (remaining() == 0) return 0;
		
		int bytesToRead = min(len, remaining());
		int r = in.read(buffer, off, bytesToRead);
		incrementNumBytesRead(r);
		return r;
	}
	
	public byte[] readFully() throws IOException {
		byte[] buffer = new byte[postLength];
		int r = read(buffer, 0, postLength);
		if (r <= 0) throw new HTTPException(400, "Failed to read POST fully");
		int total = r;
		while (total < postLength) {
			r = read(buffer, total, postLength-total);
			if (r <= 0) throw new HTTPException(400, "Failed to read POST fully");
			total += r;
		}
		incrementNumBytesRead(total);
		return buffer;
	}
	
	public boolean markSupported() {
		return false;
	}
	
	public int available() throws IOException {
		return min(in.available(), remaining());
	}
	
	public int remaining() {
		return postLength-numBytesRead;
	}	
	
	

	public String getTextData() {
		return this.textData;
	}

	public FormData getFormData() {
		return this.formData;
	}

	void readPOST(String formDataFromUrl) throws IOException {

        boolean raw = true;
        String[] textTypes = { "application/x-www-form-urlencoded", "text/" };
        
        if (postType != null) {
        	// Is this character data?
            for (String textType : textTypes) {
                if (postType.contains(textType)) {
                    raw = false;
                    break;
                }
            }   
            if (raw) {
            	// Populate form data with url query
                if (formDataFromUrl != null && formDataFromUrl.length() > 0) {
                    this.formData = FormData.parseURLEncodedFormData(formDataFromUrl);
                }
            }
            else {
                this.textData = in.readString("US-ASCII", postLength);
                StringBuilder urlEncodedFormData = new StringBuilder();
                
                if (formDataFromUrl != null && formDataFromUrl.length() > 0) {
                	urlEncodedFormData.append(formDataFromUrl);
                }

                if (postType.startsWith("application/x-www-form-urlencoded")) {
                    if (formDataFromUrl != null && formDataFromUrl.length() > 0) {
                    	urlEncodedFormData.append("&");
                    }
                    urlEncodedFormData.append(getTextData());
                }
                
                this.formData = FormData.parseURLEncodedFormData(urlEncodedFormData.toString());         
            }
        }
    }   
	
	private void incrementNumBytesRead(int bytes) {
		numBytesRead += bytes;
		// Notify threads waiting for reading to complete
		if (numBytesRead == postLength) {
			synchronized (this) {
				this.notifyAll();
			}
		}
	}
	
	private int min(int n1, int n2) {
		return n1 < n2 ? n1 : n2;
	}	
}

