/*
 * Created on May 13, 2004
 *
 */

/**
 * @author ande
 * Andrew Ebaugh, Saurav Chatterjee
 * CSE477, Spring 2004
 */

import java.io.*;
import java.net.*;


public class PortListener implements Runnable {
	
	public static final int ID_LEN = 16;
	
	// Protocol version, written at connection-open time
	// 2 bytes: first byte is always 'T', second byte is
	// protocol version
	// The actual protocol used will be min(my-version, other-version)
	final static byte VERSION[] = {'T', ' '};
	
	public static final String BAD_READ_STR = "CRC Error";
	
	private Socket client;
	private Service service;
	private String scan_data;
	private String addr;
	private InputStream is;
	private OutputStream os;
	private int port;
	
	
	PortListener(Service service, String addr, int port) {
		this.service = service;
		this.addr = addr;
		this.port = port;
	}


	public void run() {
		Socket sock = null;
		InetAddress iaddr = null;
		try {
 			iaddr = InetAddress.getByName(addr);
		}
		catch(UnknownHostException uhe){
			System.out.println(uhe);
			return;
		}
				
		try{
			sock = new Socket(iaddr, port); 
		} catch (IOException e) {
		  System.out.println("Failed to connect on: "+port+"\n");
		  return;
		}
		
		try{
			

		  handleConnection(sock);
		  
		} catch (IOException e) {
		  System.out.println("Socket connection screwed up\n");
		}
		finally {
			try{
				sock.close();
			} catch(IOException ioe){
				System.out.println("IOE closing socket: "+ioe);
			}
		}
		
	}
	
	protected void openSource() throws IOException {
		// Assumes streams are open
		os.write(VERSION);
		byte[] received = readN(2);
		if (received[0] != VERSION[0]
			|| (received[1] & 0xff) < (VERSION[1] & 0xff))
			throw new IOException("Protocol Error");
		// We know we're using the initial protocol version...
	}
	
	public void handleConnection(Socket sock) throws IOException {

		String data = null;
		String reader_id = null;
		byte[] bbuff;
		
	 	is = sock.getInputStream();
	 	os = sock.getOutputStream();
	 	
	 	openSource();		


		bbuff = readSourcePacket();
		data = new String(bbuff, 12, ID_LEN);
		reader_id = new String(bbuff, 6, 2);
		
		if(!(data == null || data.startsWith(BAD_READ_STR))){
			service.serveScan(data, reader_id);
		}
		
		
	}

	protected byte[] readSourcePacket() throws IOException {
		// Protocol is straightforward: 1 size byte, <n> data bytes
		byte[] size = readN(1);
		return readN(size[0] & 0xff);
	}

	protected byte[] readN(int n) throws IOException {
		byte[] data = new byte[n];
		int offset = 0;

		// A timeout would be nice, but there's no obvious way to
		// write it before java 1.4 (probably some trickery with
		// a thread and closing the stream would do the trick, but...)
		while (offset < n) {
			int count = is.read(data, offset, n - offset);
			if (count == -1)
				throw new IOException("End-Of-Stream");
			offset += count;
		}
		return data;
	}

}
