package org.bench4q.recorder.httpcapture;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ProxyServer implements Runnable {
	private Vector<Observer> listeners;
	private ServerSocket srvSock;
	private int count;
	private static final Log log = LogFactory.getLog(ProxyServer.class);

	public ProxyServer() throws IOException {
		this(0);
	}

	public ProxyServer(int port) throws IOException {
		this.srvSock = new ServerSocket(port);
		this.listeners = new Vector<Observer>();
	}

	public void addObserver(Observer proxy) {
		this.listeners.addElement(proxy);
	}

	public void removeObserver(Observer proxy) {
		this.listeners.removeElement(proxy);
	}
 
	public void processRequest(HttpRequestHeader header, byte[] requestBody)
			throws Exception {
		for (Enumeration<Observer> e = this.listeners.elements(); e
				.hasMoreElements();) {
			Observer pl = (Observer) e.nextElement();
			pl.processRequest(header, requestBody);                             
		}
	}

	public void processResponse(HttpRequestHeader header, byte[] requestBody,
			ResponseModel response) throws Exception {
		for (Enumeration<Observer> e = this.listeners.elements(); e
				.hasMoreElements();) {
			Observer pl = (Observer) e.nextElement();
			pl.processResponse(header, requestBody, response);
		}
	}

	public void run() {
		if (this.getServerSocket().isClosed()) {
			return;
		}
		try {
			while (true) {
				RequestHandler handler = new RequestHandler(this, this
						.getServerSocket().accept());
				log.trace("New connection.  Creating new RequestHandler thread.");
				Thread t = new Thread(handler, "Bench4QRequestHandler #"
						+ this.getLocalPort() + "#" + this.count);
				t.start();
				this.count += 1;
			}
		} catch (Exception e) {
			return;
		}
	}

	int getLocalPort() {
		return this.srvSock.getLocalPort();
	}

	public ServerSocket getServerSocket() {
		return this.srvSock;
	}

	public static abstract interface Observer {
		public abstract void processRequest(
				HttpRequestHeader paramHttpRequestHeader,
				byte[] paramArrayOfByte) throws Exception;

		public abstract void processResponse(
				HttpRequestHeader paramHttpRequestHeader, byte[] requestBody,
				ResponseModel response) throws Exception;
	}
}
