git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4136 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/971CV/src/org/frc971/HTTPClient.java b/971CV/src/org/frc971/HTTPClient.java
new file mode 100644
index 0000000..294b49f
--- /dev/null
+++ b/971CV/src/org/frc971/HTTPClient.java
@@ -0,0 +1,146 @@
+package org.frc971;
+
+//Author: Daniel Petti
+
+import java.io.*;
+import java.net.*;
+
+import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
+
+import com.googlecode.javacv.cpp.opencv_core.IplImage;
+
+public class HTTPClient {
+	//Connects to HTTP Server on robot and receives images
+	
+	private final static boolean LOCAL_DEBUG = true;
+	
+	private Socket sock;
+	private BufferedReader sock_in;
+	private PrintWriter sock_out;
+	
+	private String LastBoundary = "";
+	
+	private void WriteDebug(String message) {
+		//small helper function to write debug messages
+		if (LOCAL_DEBUG)
+			System.out.println(message);
+	}
+	private String ReadtoBoundary(String boundary) {
+		//reads from socket until it encounters a specific character combination
+		//if boundary is null, it reads until it runs out of data
+		StringBuilder recvd = new StringBuilder();
+		String message = "";
+		try {
+			sock.setSoTimeout(5000);
+		}
+		catch (SocketException e) {
+			System.err.println("Warning: Could not set socket timeout.");
+		}
+		try {
+			int ret;
+			while ((ret = sock_in.read()) != -1) {
+				if (ret == 0) {
+					//finished receiving
+					message += recvd.toString();
+					recvd.setLength(0);
+					if (boundary == null)
+						break;
+				}
+				else {
+					recvd.append((char)ret);
+					if (boundary != null) {
+						if (message.contains(boundary))
+							break;
+						else
+							continue;
+					}
+				}
+			}
+		}
+		catch (InterruptedIOException e) {
+			System.err.println("Warning: Image receive timed out.");
+			return null;
+		}
+		catch (IOException e) {
+			System.err.println("Error: Socket read failed.");
+			return null;
+		}
+		return message;
+	}
+	public HTTPClient() {
+		//Initialize socket connection to robot
+		try {
+			WriteDebug("Connecting to server...");
+			sock = new Socket("192.168.0.178", 9714);
+			sock_in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
+			sock_out = new PrintWriter(sock.getOutputStream(), true);
+			//Write headers
+			//HTTPStreamer does not actually use the headers, so we can just write terminating chars.
+			WriteDebug("Writing headers...");
+			sock_out.println("\r\n\r\n");
+			//Receive headers
+			WriteDebug("Reading headers...");
+			ReadtoBoundary("cross\r\n");
+			WriteDebug("Now receiving data.");
+		}
+		catch (UnknownHostException e) {
+			System.err.println("Error: Invalid host.");
+			System.exit(1);
+		}
+		catch (IOException e) {
+			System.err.println("Error: Socket IO failed.");
+			System.exit(2);
+		}
+		
+	}
+	public ImageWithTimestamp GetFrame() {
+		//read all current data from socket, in case of processing bottleneck
+		WriteDebug("Emptying TCP stack...");
+		String message = ReadtoBoundary(null);
+		//we must end with a boundary
+		int len = message.length();
+		if (message.substring(len - 4, len - 1) != "\r\n\r\n") {
+			WriteDebug("Boundary was not found. Waiting for boundary...");
+			message += ReadtoBoundary("\r\n\r\n");
+		}
+		//Add the last boundary we cut off to the beginning of our message
+		message = LastBoundary + message;
+		//Divide our large message into string separated by boundary beginnings
+		String[] cut = message.split("\r\n--");
+		len = cut.length;
+		//Save the newest boundary, so we can use it later.
+		LastBoundary = cut[len - 1];
+		//Keep only our penultimate boundary and the image after it
+		//NOTE that message is missing its preceding \r\n--
+		message = cut[len - 2];
+		cut = message.split("\r\n\r\n");
+		//NOTE that boundary is now missing its trailing \r\n\r\n
+		String boundary = cut[0];
+		String JPEGImage = cut[1];
+		//extract timestamp in seconds
+		cut = boundary.split("X-Timestamp: ");
+		String time_data = cut[1];
+		boundary = cut[0];
+		float timestamp = Float.parseFloat(time_data);
+		//extract size so we can make sure our image data is not corrupted
+		cut = boundary.split("Content-Length: ");
+		String size_data = cut[1];
+		float size = Float.parseFloat(size_data);
+		assert (size == JPEGImage.length()) : ("Fatal size mismatch between image and expected image size. Check regular expressions.");
+		byte[] ImageArray = JPEGImage.getBytes();
+		InputStream in = new ByteArrayInputStream(ImageArray);
+		try {
+			BufferedImage bImageFromConvert = ImageIO.read(in);
+			ImageWithTimestamp to_return = new ImageWithTimestamp();
+			to_return.image = IplImage.createFrom(bImageFromConvert);
+			to_return.timestamp = timestamp;
+			WriteDebug("Image processing successful.");
+			return to_return;
+		}
+		catch (IOException e) {
+			System.err.println(e.getMessage());
+			return null;
+		}
+	}	
+}