/*
 * Created on May 25, 2004
 *
 * Paros and its related class files.
 * 
 * Paros is an HTTP/HTTPS proxy for assessing web application security.
 * Copyright (C) 2003-2004 Chinotec Technologies Company
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Clarified Artistic License
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Clarified Artistic License for more details.
 * 
 * You should have received a copy of the Clarified Artistic License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.parosproxy.paros.core.proxy;
 
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Vector;

import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.parosproxy.paros.network.ConnectionParam;
import org.parosproxy.paros.network.HttpUtil;
import org.parosproxy.paros.network.SSLConnector;


/**
 *
 * To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Generation - Code and Comments
 */
public class ProxyServer implements Runnable {

	static {
	    ProtocolSocketFactory sslFactory = null;
	    try {
	        Protocol protocol = Protocol.getProtocol("https");
		    sslFactory = protocol.getSocketFactory();
	    } catch (Exception e) {}
	    if (sslFactory == null || !(sslFactory instanceof SSLConnector)) {
	        Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) new SSLConnector(), 443));
	    }
	}
	
	protected Thread	thread = null;

	protected final static int PORT_TIME_OUT = 2000;
	protected ServerSocket proxySocket = null;
	protected boolean isProxyRunning = false;
	protected ProxyParam proxyParam = new ProxyParam();
	protected ConnectionParam connectionParam = new ConnectionParam();
	protected Vector listenerList = new Vector();
	protected boolean serialize = false;
	
    /**
     * @return Returns the serialize.
     */
    public boolean isSerialize() {
        return serialize;
    }
	public ProxyServer() {
	}

	public void setProxyParam(ProxyParam param) {
		proxyParam = param;
	}

	public ProxyParam getProxyParam() {
		return proxyParam;
	}
	
	public void setConnectionParam(ConnectionParam connection) {
	    connectionParam = connection;
	}

	public ConnectionParam getConnectionParam() {
	    return connectionParam;
	}
	
	/**
	 * 
	 * @return	true = the server is started successfully.
	 */
	public synchronized boolean startServer() {

		if (isProxyRunning) {
			stopServer();
		}
	
		isProxyRunning	= false;

		thread = new Thread(this);
		thread.setDaemon(true);
   	    thread.setPriority(Thread.NORM_PRIORITY + 1);

		try {

			proxySocket = createServerSocket();
			proxySocket.setSoTimeout(PORT_TIME_OUT);
			isProxyRunning = true;

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

		thread.start();

		return true;
		
	}

	/**
	 * Stop this server
	 * @return true if server can be stopped.
	 */
	public synchronized boolean stopServer(){

		if (!isProxyRunning) {
			return false;
		}

		isProxyRunning = false;

		try {
			thread.join(PORT_TIME_OUT);
		} catch (Exception e) {
		}

		HttpUtil.closeServerSocket(proxySocket);
		proxySocket = null;

		return true;
	}

	public void run() {

		Socket clientSocket = null;
		ProxyThread process = null;

		while (isProxyRunning) {
			try {
				clientSocket = proxySocket.accept();
				process = createProxyProcess(clientSocket);
				process.start();
			} catch (SocketTimeoutException e) {
			    // nothing, socket time reached only.
			} catch (IOException e) {
			    // unknown IO exception - continue but with delay to avoid eating up CPU time if continue
			    try {
                    Thread.sleep(50);
                    //e.printStackTrace();
                } catch (InterruptedException e1) {
                }
			}
			
		}

	}

	protected ServerSocket createServerSocket() throws UnknownHostException, IOException {
		ServerSocket socket = new ServerSocket(getProxyParam().getProxyPort(), 300, InetAddress.getByName(getProxyParam().getProxyIp()));
		return socket;
	}
	
	protected ProxyThread createProxyProcess(Socket clientSocket) {
		ProxyThread process = new ProxyThread(this, clientSocket);
		return process;
	}
	
	protected void writeOutput(String s) {
	}
	
	public void addProxyListener(ProxyListener listener) {
		listenerList.add(listener);		
	}
	
	public void removeProxyListener(ProxyListener listener) {
		listenerList.remove(listener);
	}
	
	synchronized List getListenerList() {
		return listenerList;
	}


    /**
     * @param serialize The serialize to set.
     */
    public void setSerialize(boolean serialize) {
        this.serialize = serialize;
    }
}
